mirror of
https://github.com/pkimpel/retro-b5500.git
synced 2026-02-12 03:07:30 +00:00
Continue initial I/O Unit development.
This commit is contained in:
@@ -87,6 +87,20 @@ B5500CentralControl.mask2 = [ // (2**n)-1 For n From 0 to 52
|
||||
0x0FFFFFFFFFFFF, 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF,
|
||||
0x0FFFFFFFFFFFFF] ;
|
||||
|
||||
// The following two-dimensional array translates unit designates to a unique 1-relative
|
||||
// peripheral unit index. This index is the same as the unit's ready-status bit number,
|
||||
// which is why they are in the range 17..47. The [0] dimension determines the index
|
||||
// when writing; the [1] dimension determines the index when reading. This approach
|
||||
// is necessary since some unit designates map to two different devices depending
|
||||
// on IOD.[24:1], e.g. designate 14=CPA/CRA (status bits 23/24).
|
||||
|
||||
B5500CentralControl.unitIndex = [
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
[null, 47,null, 46, 31, 45, 29, 44, 30, 43, 25, 42, 28, 41,null, 40,
|
||||
17, 39, 21, 38, 18, 37, 27, 36,null, 35, 26, 34,null, 33, 22, 32],
|
||||
[null, 47,null, 46, 31, 45, 29, 44, 30, 43, 24, 42, 28, 41, 23, 40,
|
||||
17, 39, 20, 38, 19, 37,null, 36,null, 35,null, 34,null, 33, 22, 32]];
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.clear = function() {
|
||||
/* Initializes (and if necessary, creates) the system and starts the
|
||||
@@ -478,36 +492,37 @@ B5500CentralControl.prototype.tock = function tock() {
|
||||
} else {
|
||||
that.TM = 0;
|
||||
that.CCI03F = 1; // set timer interrupt
|
||||
// inhibit for now // that.signalInterrupt();
|
||||
// >>>>> inhibit for now >>>>> that.signalInterrupt();
|
||||
}
|
||||
interval = (that.nextTimeStamp += B5500CentralControl.rtcTick) - thisTime;
|
||||
that.timer = setTimeout(function() {that.tock()}, (interval < 0 ? 1 : interval));
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.haltP2 = function() {
|
||||
/* Called by P1 to halt P2. storeForInterrupt() will set P2BF=0 */
|
||||
|
||||
this.HP2F = 1;
|
||||
// We know P2 is not currently running on this thread, so save its registers
|
||||
if (this.P2 && this.P2BF) {
|
||||
this.P2.storeForInterrupt(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.initiateP2 = function() {
|
||||
/* Called by P1 to initiate P2. Assumes that an INCW has been stored at
|
||||
memory location @10. If P2 is busy or not present, sets the P2 busy
|
||||
interrupt. Otherwise, loads the INCW into P2's A register and initiates
|
||||
the processor. */
|
||||
var p2 = this.P2;
|
||||
|
||||
if (!this.P2 || this.P2BF) {
|
||||
this.CCI12F = 1; // set P2 busy interrupt
|
||||
this.signalInterrupt();
|
||||
} else {
|
||||
p2.M = 8; // Now have P2 pick up the INCW
|
||||
p2.access(0x04); // A = [M]
|
||||
p2.AROF = 1;
|
||||
p2.T = 0x849; // inject 4111=IP1 into P2's T register
|
||||
p2.TROF = 1;
|
||||
p2.NCSF = 0; // make sure P2 is in control state
|
||||
this.P2BF = 1;
|
||||
this.HP2F = 0;
|
||||
|
||||
// Now start scheduling P2 on the Javascript thread
|
||||
p2.procTime = new Date().getTime()*1000;
|
||||
p2.scheduler = setTimeout(p2.schedule, 0);
|
||||
this.P2.initiateAsP2();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -578,21 +593,13 @@ B5500CentralControl.prototype.testUnitBusy = function(ioUnit, unit) {
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.testUnitReady = function(unit) {
|
||||
B5500CentralControl.prototype.testUnitReady = function(rw, unit) {
|
||||
/* Determines whether the unit designate "unit" is currently in ready status.
|
||||
Returns 0 if not ready */
|
||||
"rw" indicates whether the designate is for writing (0) or reading (1).
|
||||
Returns 1 if ready, 0 if not ready */
|
||||
var index = B5500CentralControl.unitIndex[rw & 1][unit & 0x1F];
|
||||
|
||||
if (ioUnit != "1" && this.IO1 && this.IO1.REMF && this.AD1F && this.IO1.Dunit == unit) {
|
||||
return 1;
|
||||
} else if (ioUnit != "2" && this.IO2 && this.IO2.REMF && this.AD2F && this.IO2.Dunit == unit) {
|
||||
return 2;
|
||||
} else if (ioUnit != "3" && this.IO3 && this.IO3.REMF && this.AD3F && this.IO3.Dunit == unit) {
|
||||
return 3;
|
||||
} else if (ioUnit != "4" && this.IO4 && this.IO4.REMF && this.AD4F && this.IO4.Dunit == unit) {
|
||||
return 4;
|
||||
} else {
|
||||
return 0; // peripheral unit not in use by any other I/O Unit
|
||||
}
|
||||
return (index ? this.bit(this.unitStatusMask, index) : 0);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -653,15 +660,7 @@ B5500CentralControl.prototype.loadComplete = function loadComplete() {
|
||||
if (completed) {
|
||||
that.loadTimer = null;
|
||||
that.LOFF = 0;
|
||||
that.P1.C = 0x10; // execute from address @20
|
||||
that.P1.access(0x30); // P = [C]
|
||||
that.P1.T = that.fieldIsolate(that.P, 0, 12);
|
||||
that.P1.TROF = 1;
|
||||
that.P1.L = 1; // advance L to the next syllable
|
||||
|
||||
// Now start scheduling P1 on the Javascript thread
|
||||
that.P1.procTime = new Date().getTime()*1000;
|
||||
that.P1.scheduler = setTimeout(that.P1.schedule, 0);
|
||||
that.P1.start();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -752,16 +751,7 @@ B5500CentralControl.prototype.runTest = function(runAddr) {
|
||||
this.clear();
|
||||
this.loadTimer = null;
|
||||
this.LOFF = 0;
|
||||
this.P1.C = runAddr; // starting execution address
|
||||
this.P1.access(0x30); // P = [C]
|
||||
this.P1.T = this.fieldIsolate(this.P1.P, 0, 12);
|
||||
this.P1.TROF = 1;
|
||||
this.P1.L = 1; // advance L to the next syllable
|
||||
|
||||
// Now start scheduling P1 on the Javascript thread
|
||||
this.busy = 1;
|
||||
this.P1.procTime = new Date().getTime()*1000;
|
||||
this.P1.scheduler = setTimeout(this.P1.schedule, 0);
|
||||
this.P1.start();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
|
||||
@@ -44,11 +44,10 @@ function B5500IOUnit(ioUnitID, cc) {
|
||||
|
||||
this.ioUnitID = ioUnitID; // I/O Unit ID ("1", "2", "3", or "4")
|
||||
this.cc = cc; // Reference back to Central Control module
|
||||
this.rdAddress = {"1": 0x0C, "2": 0x0D, "3": 0x0E, "4": 0x0F}[ioUnitID];
|
||||
|
||||
this.scheduler = null; // Reference to current setTimeout id
|
||||
this.accessor = { // Memory access control block
|
||||
requestorID: procID, // Memory requestor ID
|
||||
requestorID: ioUnitID, // Memory requestor ID
|
||||
addr: 0, // Memory address
|
||||
word: 0, // 48-bit data word
|
||||
MAIL: 0, // Truthy if attempt to access @000-@777 in normal state
|
||||
@@ -61,7 +60,7 @@ function B5500IOUnit(ioUnitID, cc) {
|
||||
// Establish a buffer for the peripheral modules to use during their I/O.
|
||||
// The size is sufficient for 63 disk sectors, rounded up to the next 8KB.
|
||||
this.bufferArea = new ArrayBuffer(16384);
|
||||
this.buffer = new UInt8Array(bufferArea);
|
||||
this.buffer = new Uint8Array(this.bufferArea);
|
||||
|
||||
this.clear(); // Create and initialize the processor state
|
||||
}
|
||||
@@ -217,6 +216,180 @@ B5500IOUnit.prototype.store = function(addr) {
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500IOUnit.prototype.fetchBuffer = function(mode, words) {
|
||||
/* Fetches words from memory starting at this.Daddress and coverts the
|
||||
BIC characters to ANSI in this.buffer. "mode": 0=alpha, 1=binary;
|
||||
"words": maximum number of words to transfer. In alpha mode, the transfer
|
||||
can be terminated by a group-mark code in memory. At exit, updates this.Daddress
|
||||
with the final transfer address+1. If this.D23F, updates this.wordCount
|
||||
with any remaining count.
|
||||
Returns the number of characters fetched into the buffer */
|
||||
var addr = this.Daddress; // local copy of memory address
|
||||
var buf = this.buffer; // local pointer to buffer
|
||||
var c; // current character code
|
||||
var count = 0; // number of characters fetched
|
||||
var done = false; // loop control
|
||||
var s; // character shift counter
|
||||
var w; // local copy of this.W
|
||||
|
||||
do { // loop through the words
|
||||
if (words <= 0) {
|
||||
done = true;
|
||||
} else {
|
||||
words--;
|
||||
if (addr > 0x7FFF) {
|
||||
this.D26F = 1; // address overflow: set invalid address error
|
||||
done = true;
|
||||
} else if (this.fetch(addr)) { // fetch the next word from memory
|
||||
if (this.accessor.MAED) {
|
||||
this.D26F = 1; // set invalid address error
|
||||
}
|
||||
if (this.accessor.MPED) {
|
||||
this.D29F = 1; // set memory parity error
|
||||
}
|
||||
} else { // fill the buffer with this word's characters
|
||||
w = this.W;
|
||||
for (s=0; s<8; s++) {
|
||||
c = (w - (w %= 0x40000000000))/0x40000000000;
|
||||
if (mode || c != 0x1F) { // if binary mode or not a group-mark
|
||||
buf[count++] = B5500IOUnit.BICtoANSI[c];
|
||||
w *= 64; // shift word left 6 bits
|
||||
} else {
|
||||
done = true; // group-mark detected in alpha mode
|
||||
break;
|
||||
}
|
||||
} // for s
|
||||
}
|
||||
addr++;
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
this.Daddress = addr % 0x7FFF;
|
||||
if (this.D23F) {
|
||||
this.DwordCount = words % 0x1FF;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500IOUnit.prototype.storeBuffer = function(chars, offset, mode, words) {
|
||||
/* Converts characters in this.buffer from ANSI to BIC, assembles them into
|
||||
words, and stores the words into memory starting at this.Daddress.
|
||||
BIC characters to ANSI in this.buffer. "chars": the number of characters to
|
||||
stort, starting at "offset" in the buffer; "mode": 0=alpha, 1=binary;
|
||||
"words": maximum number of words to transfer. In alpha mode, the final character
|
||||
stored from the buffer is followed by a group-mark, assuming the word count is
|
||||
not exhausted. At exit, updates this.Daddress with the final transfer address+1.
|
||||
If this.D23F, updates this.wordCount with any remaining count.
|
||||
Returns the number of characters stored into memory from the buffer */
|
||||
var addr = this.Daddress; // local copy of memory address
|
||||
var buf = this.buffer; // local pointer to buffer
|
||||
var c; // current character code
|
||||
var count = 0; // number of characters fetched
|
||||
var done = (words > 0); // loop control
|
||||
var power = 0x40000000000; // factor for character shifting into a word
|
||||
var s = 8; // character shift counter
|
||||
var w = 0; // local copy of this.W
|
||||
|
||||
while (!done) { // loop through the words
|
||||
if (count >= chars) {
|
||||
done = true;
|
||||
} else {
|
||||
c = B5500IOUnit.ANSItoBIC[buf[offset+(count++)]];
|
||||
w += c*power;
|
||||
power /= 64;
|
||||
if (--s <= 0) {
|
||||
this.W = w;
|
||||
if (addr > 0x7FFF) {
|
||||
this.D26F = 1; // address overflow: set invalid address error
|
||||
done = true;
|
||||
} else if (this.store(addr)) { // store the word in memory
|
||||
if (this.accessor.MAED) {
|
||||
this.D26F = 1; // set invalid address error
|
||||
}
|
||||
}
|
||||
addr++;
|
||||
s = 8;
|
||||
w = 0;
|
||||
power = 0x40000000000;
|
||||
if (--words <= 0) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // while !done
|
||||
|
||||
if (!mode) { // alpha transfer terminates with a group-mark
|
||||
w += 0x1F*power; // set group mark in register
|
||||
s--;
|
||||
count++;
|
||||
}
|
||||
if (s < 8 && words > 0) { // partial word left to be stored
|
||||
this.W = w;
|
||||
if (addr > 0x7FFF) {
|
||||
this.D26F = 1; // address overflow: set invalid address error
|
||||
done = true;
|
||||
} else if (this.store(addr)) { // store the word in memory
|
||||
if (this.accessor.MAED) {
|
||||
this.D26F = 1; // set invalid address error
|
||||
}
|
||||
}
|
||||
addr++;
|
||||
words--;
|
||||
}
|
||||
|
||||
this.Daddress = addr % 0x7FFF;
|
||||
if (this.D23F) {
|
||||
this.DwordCount = words % 0x1FF;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500IOUnit.prototype.finish = function () {
|
||||
/* Called to finish an I/O operation on this I/O Unit. Constructs and stores
|
||||
the result descriptor, sets the appropriate I/O Finished interrupt in CC */
|
||||
|
||||
this.W = this.D =
|
||||
this.Dunit * 0x10000000000 +
|
||||
this.DwordCount * 0x40000000 +
|
||||
this.D18F * 0x20000000 +
|
||||
this.D21F * 0x4000000 +
|
||||
this.D22F * 0x2000000 +
|
||||
this.D23F * 0x1000000 +
|
||||
this.D24F * 0x800000 +
|
||||
this.D26F * 0x200000 +
|
||||
this.D27F * 0x100000 +
|
||||
this.D28F * 0x80000 +
|
||||
this.D29F * 0x40000 +
|
||||
this.D30F * 0x20000 +
|
||||
this.D31F * 0x10000 +
|
||||
this.D32F * 0x8000 +
|
||||
this.Daddressf;
|
||||
|
||||
switch(ioUnitID) {
|
||||
case "1":
|
||||
this.store(0x0C);
|
||||
this.cc.CCI08F = 1; // set I/O Finished #1
|
||||
break;
|
||||
case "2":
|
||||
this.store(0x0D);
|
||||
this.cc.CCI08F = 1; // set I/O Finished #2
|
||||
break;
|
||||
case "3":
|
||||
this.store(0x0E);
|
||||
this.cc.CCI08F = 1; // set I/O Finished #3
|
||||
break;
|
||||
case "4":
|
||||
this.store(0x0F);
|
||||
this.cc.CCI08F = 1; // set I/O Finished #4
|
||||
break;
|
||||
}
|
||||
|
||||
this.Dunit = 0; // zero so CC won't think unit is busy
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500IOUnit.prototype.initiate = function() {
|
||||
/* Initiates an I/O operation on this I/O Unit */
|
||||
@@ -227,32 +400,89 @@ B5500IOUnit.prototype.initiate = function() {
|
||||
this.EXNF = 0;
|
||||
this.D31F = 1; // preset IOD fetch error condition (cleared if successful)
|
||||
if (this.fetch(0x08)) { // fetch the IOD address from @10
|
||||
... return descriptor ...
|
||||
this.finish();
|
||||
} else {
|
||||
this.EXNF = 1;
|
||||
this.Daddress = addr = this.W % 0x7FFF;
|
||||
if (this.fetch(addr)) { // fetch the IOD from that address
|
||||
... return descriptor ...
|
||||
this.finish();
|
||||
} else {
|
||||
this.D31F = 0; // reset the IOD-fetch error condition
|
||||
this.D = x = this.W; // explode the D-register into its fields
|
||||
this.Dunit = this.cc.fieldIsolate(x, 3, 5);
|
||||
this.DwordCount = this.cc.fieldIsolate(x, 8, 10);
|
||||
x = x % 0x40000000;
|
||||
this.D18F = (x >>> 29) & 1;
|
||||
this.D21F = (x >>> 26) & 1;
|
||||
this.D22F = (x >>> 25) & 1;
|
||||
this.D23F = (x >>> 24) & 1;
|
||||
this.D24F = (x >>> 23) & 1;
|
||||
x = x % 0x40000000; // isolate low-order 30 bits
|
||||
this.D18F = (x >>> 29) & 1; // memory inhibit
|
||||
this.D21F = (x >>> 26) & 1; // mode
|
||||
this.D22F = (x >>> 25) & 1; // direction (for tapes)
|
||||
this.D23F = (x >>> 24) & 1; // use word counter
|
||||
this.D24F = (x >>> 23) & 1; // write/read
|
||||
this.LP = (x >>> 15) & 0x3F;// save control bits for drum and printer
|
||||
this.Daddress = x % 0x7FFF;
|
||||
if (this.cc.testUnitBusy(this.ioUnitID, this.Dunit)) {
|
||||
this.D32F = 1; // set unit busy error
|
||||
... return descriptor ...
|
||||
} else if (!this.cc.testUnitReady(this.Dunit)) {
|
||||
this.finish();
|
||||
} else if (!this.cc.testUnitReady(this.D24F, this.Dunit)) {
|
||||
this.D30F = 1; // set unit not-ready error
|
||||
... return descriptor ...
|
||||
this.finish();
|
||||
} else {
|
||||
|
||||
switch(this.Dunit) {
|
||||
// disk designates
|
||||
case 6:
|
||||
case 12:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// printer designates
|
||||
case 22:
|
||||
case 26:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// datacom designate
|
||||
case 16:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// card #1 reader/punch
|
||||
case 10:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// card #2 reader
|
||||
case 14:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// SPO designate
|
||||
case 30:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// magnetic tape designates
|
||||
case 1: case 3: case 5: case 7: case 9: case 11: case 13: case 15:
|
||||
case 17: case 19: case 21: case 23: case 25: case 27: case 29: case 31:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// drum designates
|
||||
case 4:
|
||||
case 8:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// paper tape designates
|
||||
case 18:
|
||||
case 20:
|
||||
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
|
||||
break;
|
||||
|
||||
// illegal designates
|
||||
default:
|
||||
this.D30F = 1; // report invalid unit as not ready
|
||||
this.finish();
|
||||
break;
|
||||
} // switch this.Dunit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1061,11 +1061,11 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) {
|
||||
this.TROF = 0;
|
||||
this.PROF = 0;
|
||||
this.busy = 0;
|
||||
this.cc.HP2F = 1;
|
||||
this.cc.P2BF = 0;
|
||||
if (this.cc.P2 && this.cc.P2.scheduler) {
|
||||
clearTimeout(this.cc.P2.scheduler);
|
||||
this.cc.P2.scheduler = null;
|
||||
this.cc.HP2F = 1;
|
||||
this.cc.P2BF = 0; // tell P1 we've stopped
|
||||
if (this.scheduler) {
|
||||
clearTimeout(this.scheduler);
|
||||
this.scheduler = null;
|
||||
}
|
||||
}
|
||||
this.CWMF = 0;
|
||||
@@ -1086,15 +1086,31 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) {
|
||||
this.PROF = 0;
|
||||
this.busy = 0;
|
||||
this.cc.HP2F = 1;
|
||||
this.cc.P2BF = 0;
|
||||
if (this.cc.P2 && this.cc.P2.scheduler) {
|
||||
clearTimeout(this.cc.P2.scheduler);
|
||||
this.cc.P2.scheduler = null;
|
||||
this.cc.P2BF = 0; // tell P1 we've stopped
|
||||
if (this.scheduler) {
|
||||
clearTimeout(this.scheduler);
|
||||
this.scheduler = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.start = function() {
|
||||
/* Initiates the processor from a load condition at P=@20 */
|
||||
|
||||
this.C = runAddr; // starting execution address
|
||||
this.access(0x30); // P = [C]
|
||||
this.T = this.fieldIsolate(this.P, 0, 12);
|
||||
this.TROF = 1;
|
||||
this.L = 1; // advance L to the next syllable
|
||||
|
||||
// Now start scheduling the processor on the Javascript thread
|
||||
this.busy = 1;
|
||||
this.procTime = new Date().getTime()*1000;
|
||||
this.scheduler = setTimeout(this.schedule, 0);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.initiate = function(forTest) {
|
||||
/* Initiates the processor from interrupt control words stored in the
|
||||
@@ -1192,6 +1208,23 @@ B5500Processor.prototype.initiate = function(forTest) {
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.initiateAsP2 = function() {
|
||||
/* Called from Central Control to initiate the processor as P2. Fetches the
|
||||
INCW from @10 and calls initiate() */
|
||||
|
||||
this.M = 0x08; // address of the INCW
|
||||
this.access(0x04); // A = [M]
|
||||
this.AROF = 1;
|
||||
this.T = 0x849; // inject 4111=IP1 into P2's T register
|
||||
this.TROF = 1;
|
||||
this.NCSF = 0; // make sure P2 is in control state
|
||||
|
||||
// Now start scheduling P2 on the Javascript thread
|
||||
this.procTime = new Date().getTime()*1000;
|
||||
this.scheduler = setTimeout(this.schedule, 0);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.singlePrecisionCompare = function() {
|
||||
/* Algebraically compares the B register to the A register. Function returns
|
||||
@@ -3322,10 +3355,8 @@ B5500Processor.prototype.run = function() {
|
||||
break;
|
||||
|
||||
case 0x12: // 2211: HP2=Halt Processor 2
|
||||
if (!this.NCSF && this.cc.P2 && this.cc.P2BF) { // control-state only
|
||||
this.cc.HP2F = 1;
|
||||
// We know P2 is not currently running on this thread, so save its registers
|
||||
this.cc.P2.storeForInterrupt(0);
|
||||
if (!this.NCSF) { // control-state only
|
||||
this.cc.haltP2();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user