mirror of
https://github.com/pkimpel/retro-220.git
synced 2026-01-13 15:18:24 +00:00
Commit version 0.03b: continue development of magnetic tape drive.
This commit is contained in:
parent
d518d6e044
commit
4c63d98515
@ -243,8 +243,8 @@ function B220Processor(config, devices) {
|
||||
this.boundCardatronReceiveWord = B220Processor.bindMethod(this, B220Processor.prototype.cardatronReceiveWord);
|
||||
|
||||
this.boundMagTapeComplete = B220Processor.bindMethod(this, B220Processor.prototype.magTapeComplete);
|
||||
this.boundMagTapeReceiveBlock = B220Processor.bindMethod(this, B220Processor.prototype.magTapeReceiveBlock);
|
||||
this.boundMagTapeSendBlock = B220Processor.bindMethod(this, B220Processor.prototype.magTapeSendBlock);
|
||||
this.boundMagTapeReceiveWord = B220Processor.bindMethod(this, B220Processor.prototype.magTapeReceiveWord);
|
||||
this.boundMagTapeSendWord = B220Processor.bindMethod(this, B220Processor.prototype.magTapeSendWord);
|
||||
|
||||
this.clear(); // Create and initialize the processor state
|
||||
|
||||
@ -256,7 +256,7 @@ function B220Processor(config, devices) {
|
||||
* Global Constants *
|
||||
***********************************************************************/
|
||||
|
||||
B220Processor.version = "0.03a";
|
||||
B220Processor.version = "0.03b";
|
||||
|
||||
B220Processor.tick = 1000/200000; // milliseconds per clock cycle (200KHz)
|
||||
B220Processor.cyclesPerMilli = 1/B220Processor.tick;
|
||||
@ -1886,7 +1886,7 @@ B220Processor.prototype.compareField = function compareField() {
|
||||
if (s == 0) {
|
||||
s = 10;
|
||||
}
|
||||
L = (this.CCONTROL >>> 8) & 0x0F;
|
||||
L = (this.CCONTROL >>> 8)%0x10;
|
||||
if (L == 0) {
|
||||
L = 10;
|
||||
}
|
||||
@ -2009,7 +2009,7 @@ B220Processor.prototype.increaseFieldLocation = function increaseFieldLocation()
|
||||
if (s == 0) {
|
||||
s = 10;
|
||||
}
|
||||
L = (this.CCONTROL >>> 8) & 0x0F;
|
||||
L = (this.CCONTROL >>> 8)%0x10;
|
||||
if (L == 0) {
|
||||
L = 10;
|
||||
}
|
||||
@ -2092,7 +2092,7 @@ B220Processor.prototype.decreaseFieldLocation = function decreaseFieldLocation(l
|
||||
if (s == 0) {
|
||||
s = 10;
|
||||
}
|
||||
L = (this.CCONTROL >>> 8) & 0x0F;
|
||||
L = (this.CCONTROL >>> 8)%0x10;
|
||||
if (L == 0) {
|
||||
L = 10;
|
||||
}
|
||||
@ -2173,7 +2173,7 @@ B220Processor.prototype.branchField = function branchField(regValue) {
|
||||
if (s == 0) {
|
||||
s = 10;
|
||||
}
|
||||
L = (this.CCONTROL >>> 8) & 0x0F;
|
||||
L = (this.CCONTROL >>> 8)%0x10;
|
||||
if (L == 0) {
|
||||
L = 10;
|
||||
}
|
||||
@ -2265,7 +2265,7 @@ B220Processor.prototype.storeRegister = function storeRegister() {
|
||||
if (s == 0) {
|
||||
s = 10;
|
||||
}
|
||||
L = (this.CCONTROL >>> 8) & 0x0F;
|
||||
L = (this.CCONTROL >>> 8)%0x10;
|
||||
if (L == 0) {
|
||||
L = 10;
|
||||
}
|
||||
@ -2433,7 +2433,7 @@ B220Processor.prototype.consoleOutputSign = function consoleOutputSign(printSign
|
||||
this.ioComplete(true);
|
||||
} else {
|
||||
this.D.set(this.IB.value);
|
||||
this.opTime += 0.070; // estimate for memory access and rotation
|
||||
this.execClock += 0.070; // estimate for memory access and rotation
|
||||
w = this.D.value%0x10000000000;
|
||||
d = (this.D.value - w)/0x10000000000; // get the sign digit
|
||||
this.D.set(w*0x10 + d); // rotate D+sign left one
|
||||
@ -2470,7 +2470,7 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar
|
||||
w = this.D.value % 0x1000000000;
|
||||
d = (this.D.value - w)/0x1000000000; // get next 2 digits
|
||||
this.D.set(w*0x100 + d); // rotate D+sign left by two
|
||||
this.opTime += 0.060; // estimate for rotation
|
||||
this.execClock += 0.060; // estimate for rotation
|
||||
this.DC.inc(); // increment DC for two digits
|
||||
this.DC.inc();
|
||||
this.PA.set(d);
|
||||
@ -2495,7 +2495,7 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar
|
||||
w = this.D.value % 0x10000000000;
|
||||
d = (this.D.value - w)/0x10000000000; // get a digit
|
||||
this.D.value = w*0x10 + d; // rotate D+sign left by one
|
||||
this.opTime += 0.065; // estimate for rotation
|
||||
this.execClock += 0.065; // estimate for rotation
|
||||
this.DC.inc();
|
||||
} while (d == 0 && this.LT1.value && this.DC.value < 0x20);
|
||||
|
||||
@ -2727,13 +2727,14 @@ B220Processor.prototype.cardatronOutputWord = function cardatronOutputWord() {
|
||||
} else if (this.MET.value) { // previous memory access error
|
||||
word = 0;
|
||||
} else {
|
||||
this.opTime += 0.117; // time for full-word transfer
|
||||
word = this.readMemory(); // address in E was previously set
|
||||
if (this.MET.value) {
|
||||
word = 0;
|
||||
} else {
|
||||
this.E.dec(); // step down to next memory address
|
||||
}
|
||||
|
||||
this.execClock += 0.117; // time for full-word transfer
|
||||
}
|
||||
|
||||
return word;
|
||||
@ -2771,7 +2772,6 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
// Memory error has occurred: just ignore further data from Cardatron
|
||||
} else {
|
||||
// Full word accumulated -- process it and initialize for the next word
|
||||
this.opTime += 0.117; // time for full-word transfer
|
||||
this.D.set(word);
|
||||
word %= 0x10000000000; // strip the sign digit
|
||||
sign = (this.D.value - word)/0x10000000000; // get D-sign
|
||||
@ -2811,8 +2811,8 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
default: // sign is 8, 9: store word with optional B mod
|
||||
if (!(this.rDigit & 0x08)) { // no B-register modification
|
||||
this.IB.set(this.D.value);
|
||||
} else { // add B to low-order five digits of word
|
||||
word = word - word%0x100000 + this.bcdAdd(word, this.B.value, 5);
|
||||
} else { // add B to low-order four digits of word
|
||||
word = word - word%0x100000 + this.bcdAdd(word, this.B.value, 4);
|
||||
this.C10.set(0); // reset carry toggle
|
||||
this.IB.set((sign%2)*0x10000000000 + word);
|
||||
}
|
||||
@ -2822,6 +2822,8 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
}
|
||||
break;
|
||||
} // switch sign
|
||||
|
||||
this.execClock += 0.117; // time for full-word transfer
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
@ -2864,139 +2866,81 @@ B220Processor.prototype.magTapeComplete = function magTapeComplete(alarm, contro
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.magTapeSendBlock = function magTapeSendBlock(buffer, words) {
|
||||
/* Sends a block of data from memory to the tape control unit. "buffer" is an
|
||||
array of words to receive the data to be written to tape. "words" is the number
|
||||
of words to place in the buffer, starting at the current operand address in the
|
||||
C register. Returns true if the processor has been cleared or a memory address
|
||||
error occurs, and the I/O must be aborted */
|
||||
var result = false; // return value
|
||||
var that = this; // local context
|
||||
var x = 0; // buffer index
|
||||
|
||||
//console.log("TSU " + this.selectedUnit + " W, Len " + words +
|
||||
// ", ADDR=" + this.CADDR.toString(16));
|
||||
B220Processor.prototype.magTapeSendWord = function magTapeSendWord(initial) {
|
||||
/* Sends the next of data from memory to the tape control unit, starting at
|
||||
the current operand address in the C register. "initial" is true if this
|
||||
call is the first to fetch words for a block. This causes the routine to
|
||||
save the current operand address in the control digits of C. Returns
|
||||
binary -1 if the processor has been cleared or a memory address error
|
||||
occurs, and the I/O must be aborted. Returns the BCD memory word otherwise */
|
||||
var result; // return value
|
||||
|
||||
if (!this.AST.value) {
|
||||
result = true;
|
||||
result = -1; // we've probably been cleared
|
||||
} else {
|
||||
while (x < words) {
|
||||
this.E.set(this.CADDR);
|
||||
this.CADDR = this.bcdAdd(this.CADDR, 1, 4);
|
||||
this.readMemory();
|
||||
if (this.MET.value) { // invalid address
|
||||
result = true;
|
||||
break; // out of do-loop
|
||||
} else {
|
||||
buffer[x] = this.IB.value;
|
||||
++x;
|
||||
}
|
||||
if (initial) {
|
||||
this.clockIn();
|
||||
this.CCONTROL = this.CADDR; // copy C address into control digits
|
||||
}
|
||||
|
||||
this.E.set(this.CADDR);
|
||||
this.CADDR = this.bcdAdd(this.CADDR, 1, 4);
|
||||
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
|
||||
this.readMemory();
|
||||
if (this.MET.value) { // invalid address
|
||||
result = -1;
|
||||
} else {
|
||||
result = this.IB.value;
|
||||
this.D.set(result);
|
||||
this.execClock += 0.480; // time to transfer one word to tape
|
||||
}
|
||||
}
|
||||
|
||||
this.C.set(this.C.value - this.C.value%0x10000 + this.CADDR);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.magTapeReceiveBlock = function magTapeReceiveBlock(block, lastBlock) {
|
||||
/* Called by the tape control unit to store a block of 20 words. If "lastBlock" is
|
||||
true, it indicates this is the last block and the I/O is finished. If "block"
|
||||
is null, that indicates the I/O was aborted and the block must not be stored
|
||||
in memory. The block is stored in one of the loops, as determined by the
|
||||
togMT1BV4 and togMT1BV5 control toggles. Sign digit adjustment and B-register
|
||||
modification take place at this time. If the C-register operand address is
|
||||
less than 8000, the loop is then stored at the current operand address, which
|
||||
is incremented by blockFromLoop(). If this is the last block, schedule()
|
||||
is called after the loop is stored to terminate the read instruction. Since
|
||||
tape block reads take 46 ms, they are much longer than any loop-to-memory
|
||||
transfer, so this routine simply exits after the blockFromLoop is initiated,
|
||||
and the then processor waits for the next block to arrive from the tape, by
|
||||
which time the blockFromLoop will (should?) have completed. Returns true if
|
||||
the processor has been cleared and the tape control unit should abort the I/O */
|
||||
var aborted = false; // return value
|
||||
var loop;
|
||||
B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initial, word) {
|
||||
/* Stores the next of data from the tape control unit to memory, starting at
|
||||
the current operand address in the C register. "initial" is true if this
|
||||
call is the first to store words for a block. This causes the routine to
|
||||
save the current operand address in the control digits of C. Returns
|
||||
binary -1 if the processor has been cleared or a memory address error
|
||||
occurs, and the I/O must be aborted. Returns 0 otherwise */
|
||||
var result = 0; // return value
|
||||
var sign; // sign digit
|
||||
var that = this;
|
||||
var w; // scratch word
|
||||
var x; // scratch index
|
||||
|
||||
function blockStoreComplete() {
|
||||
if (lastBlock) {
|
||||
if (that.togMT3P) { // if false, we've probably been cleared
|
||||
that.A = that.D = 0; // for display only
|
||||
that.togMT3P = 0;
|
||||
that.togMT1BV4 = that.togMT1BV5 = 0;
|
||||
that.schedule();
|
||||
}
|
||||
} else {
|
||||
// Flip the loop buffer toggles
|
||||
that.togMT1BV5 = that.togMT1BV4;
|
||||
that.togMT1BV4 = 1-that.togMT1BV4;
|
||||
// Suspend time again during I/O
|
||||
that.execTime -= performance.now()*B220Processor.wordsPerMilli;
|
||||
}
|
||||
}
|
||||
|
||||
//console.log("TSU " + this.selectedUnit + " R, L" + (this.togMT1BV4 ? 4 : 5) +
|
||||
// ", ADDR=" + this.CADDR.toString(16) +
|
||||
// " : " + block[0].toString(16) + ", " + block[19].toString(16));
|
||||
|
||||
if (!this.togMT3P) { // if false, we've probably been cleared
|
||||
aborted = true;
|
||||
if (!this.AST.value) {
|
||||
result = -1; // we've probably been cleared
|
||||
} else {
|
||||
this.execTime += performance.now()*B220Processor.wordsPerMilli; // restore time after I/O
|
||||
// Select the appropriate loop to receive data from the drive
|
||||
if (this.togMT1BV4) {
|
||||
loop = this.L4;
|
||||
this.toggleGlow.glowL4 = 1; // turn on the lamp and let normal decay work
|
||||
} else {
|
||||
loop = this.L5;
|
||||
this.toggleGlow.glowL5 = 1;
|
||||
if (initial) {
|
||||
this.clockIn();
|
||||
this.CCONTROL = this.CADDR; // copy C address into control digits
|
||||
}
|
||||
|
||||
if (!block) { // control unit aborted the I/O
|
||||
blockStoreComplete();
|
||||
} else {
|
||||
// Copy the tape block data to the appropriate high-speed loop
|
||||
for (x=0; x<loop.length; ++x) {
|
||||
this.D.set(w = block[x]); // D for display only
|
||||
if (w < 0x20000000000) {
|
||||
this.togCLEAR = 1; // no B modification
|
||||
} else {
|
||||
// Adjust sign digit and do B modification as necessary
|
||||
sign = ((w - w%0x10000000000)/0x10000000000) % 0x08; // low-order 3 bits only
|
||||
if (this.tswSuppressB) {
|
||||
this.togCLEAR = 1; // no B modification
|
||||
} else {
|
||||
this.togCLEAR = ((sign & 0x02) ? 0 : 1);
|
||||
sign &= 0x01;
|
||||
}
|
||||
|
||||
w = sign*0x10000000000 + w%0x10000000000;
|
||||
}
|
||||
|
||||
if (this.togCLEAR) {
|
||||
w = this.bcdAdd(w, 0, 11);
|
||||
} else {
|
||||
w = this.bcdAdd(w, this.B.value, 11);
|
||||
}
|
||||
|
||||
loop[x] = w;
|
||||
} // for x
|
||||
|
||||
this.A.set(w); // for display only
|
||||
|
||||
// Block the loop buffer to main memory if appropriate
|
||||
if (this.CADDR < 0x8000) {
|
||||
this.blockFromLoop((this.togMT1BV4 ? 4 : 5), blockStoreComplete);
|
||||
} else {
|
||||
blockStoreComplete();
|
||||
this.E.set(this.CADDR);
|
||||
this.CADDR = this.bcdAdd(this.CADDR, 1, 4);
|
||||
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
|
||||
this.D.set(word);
|
||||
if (this.vDigit & 0x08) { // B-adjustment of words is enabled
|
||||
sign = (word - word%0x10000000000);
|
||||
if (sign & 0x08) { // this word is to be B-adjusted
|
||||
word = (sign&0x07)*0x10000000000 + word%0x10000000000 -
|
||||
word%0x100000 + this.bcdAdd(word, this.B.value, 4);
|
||||
this.C10.set(0); // reset carry toggle
|
||||
}
|
||||
}
|
||||
|
||||
this.IB.set(word);
|
||||
this.writeMemory();
|
||||
if (this.MET.value) { // invalid address
|
||||
result = -1;
|
||||
} else {
|
||||
this.execClock += 0.480; // time to transfer one word to tape
|
||||
}
|
||||
}
|
||||
|
||||
return aborted;
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
@ -3109,7 +3053,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
}
|
||||
|
||||
this.selectedUnit = d;
|
||||
this.rDigit = this.CCONTROL & 0x0F;
|
||||
this.rDigit = this.CCONTROL%0x10;
|
||||
this.sDigit = 1; // use word count in C (32)
|
||||
this.D.set(0);
|
||||
this.ioInitiate();
|
||||
@ -3653,25 +3597,20 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
switch (this.CCONTROL%0x10) {
|
||||
case 0: case 1: case 2: case 3: // MTS/MFS: search or field search
|
||||
this.setProgramCheck(true); // TEMP //
|
||||
this.operationComplete();
|
||||
break;
|
||||
case 4: case 5: case 6: case 7: // MLS: lane select
|
||||
this.ioInitiate();
|
||||
this.magTape.laneSelect(this.D.value, this.boundMagTapeComplete);
|
||||
break;
|
||||
case 8: case 9: // MRW/MDA: rewind, with or without lockout
|
||||
this.ioInitiate();
|
||||
this.magTape.rewind(this.D.value, this.boundMagTapeComplete);
|
||||
break;
|
||||
default: // should never happen
|
||||
this.setProgramCheck(true);
|
||||
this.operationComplete();
|
||||
break;
|
||||
} // switch on operation variant
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.vDigit = this.CCONTROL%0x10;
|
||||
this.ioInitiate();
|
||||
if (this.vDigit & 0x08) { // MRW/MDA: rewind, with or without lockout
|
||||
this.magTape.rewind(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendWord);
|
||||
} else if (this.vDigit & 0x04) { // MLS: lane select
|
||||
this.magTape.laneSelect(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendWord);
|
||||
} else { // MTS/MFS: search or field search
|
||||
if (this.D.value%0x80000000000 < 0x40000000000) { // full-word search
|
||||
this.magTape.search(this.D.value, this.boundMagTapeComplete, 0, this.boundMagTapeSendWord);
|
||||
} else { // partial-word search based on sL in B
|
||||
this.magTape.search(this.D.value, this.boundMagTapeComplete, this.B.value, this.boundMagTapeSendWord);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -3681,13 +3620,29 @@ B220Processor.prototype.execute = function execute() {
|
||||
break;
|
||||
|
||||
case 0x52: //--------------------- MRD Magnetic tape read
|
||||
this.setProgramCheck(1);
|
||||
this.operationComplete();
|
||||
this.opTime = 0.160;
|
||||
if (!this.magTape) {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.vDigit = this.CCONTROL%0x10;
|
||||
this.ioInitiate();
|
||||
this.magTape.read(this.D.value, this.boundMagTapeComplete, false, this.boundMagTapeReceiveWord);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x53: //--------------------- MRR Magnetic tape read, record
|
||||
this.setProgramCheck(1);
|
||||
this.operationComplete();
|
||||
this.opTime = 0.160;
|
||||
if (!this.magTape) {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.vDigit = this.CCONTROL%0x10;
|
||||
this.ioInitiate();
|
||||
this.magTape.read(this.D.value, this.boundMagTapeComplete, true, this.boundMagTapeReceiveWord);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x54: //--------------------- MIW Magnetic tape initial write
|
||||
@ -3696,11 +3651,9 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.CCONTROL = this.CADDR; // copy C address into control digits
|
||||
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.ioInitiate();
|
||||
this.magTape.initialWrite(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendBlock);
|
||||
this.magTape.initialWrite(this.D.value, this.boundMagTapeComplete, false, this.boundMagTapeSendWord);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -3710,22 +3663,34 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.CCONTROL = this.CADDR; // copy C address into control digits
|
||||
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.ioInitiate();
|
||||
this.magTape.initialWriteRecord(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendBlock);
|
||||
this.magTape.initialWrite(this.D.value, this.boundMagTapeComplete, true, this.boundMagTapeSendWord);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x56: //--------------------- MOW Magnetic tape overwrite
|
||||
this.setProgramCheck(1);
|
||||
this.operationComplete();
|
||||
this.opTime = 0.160;
|
||||
if (!this.magTape) {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.ioInitiate();
|
||||
this.magTape.overwrite(this.D.value, this.boundMagTapeComplete, false, this.boundMagTapeSendWord);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x57: //--------------------- MOR Magnetic tape overwrite, record
|
||||
this.setProgramCheck(1);
|
||||
this.operationComplete();
|
||||
this.opTime = 0.160;
|
||||
if (!this.magTape) {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.ioInitiate();
|
||||
this.magTape.overwrite(this.D.value, this.boundMagTapeComplete, true, this.boundMagTapeSendWord);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x58: //--------------------- MPF/MPB/MIE Magnetic tape position forward/backward/at end
|
||||
@ -3734,7 +3699,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setMagneticTapeCheck(true); // no tape control
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.ioInitiate();
|
||||
switch (this.CCONTROL%0x10) {
|
||||
case 1: // MPB: position tape backward
|
||||
@ -3780,9 +3745,9 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setCardatronCheck(1);
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.rDigit = this.CCONTROL & 0x0F;
|
||||
this.vDigit = (this.CCONTROL >>> 4) & 0x0F;
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.rDigit = this.CCONTROL%0x10;
|
||||
this.vDigit = (this.CCONTROL >>> 4)%0x10;
|
||||
this.ioInitiate();
|
||||
d = this.cardatron.inputInitiate(this.selectedUnit, this.rDigit, this.boundCardatronReceiveWord);
|
||||
if (d < 0) { // invalid unit
|
||||
@ -3800,9 +3765,9 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setCardatronCheck(1);
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.rDigit = this.CCONTROL & 0x0F;
|
||||
this.vDigit = (this.CCONTROL >>> 4) & 0x0F;
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.rDigit = this.CCONTROL%0x10;
|
||||
this.vDigit = (this.CCONTROL >>> 4)%0x10;
|
||||
this.ioInitiate();
|
||||
d = this.cardatron.outputInitiate(this.selectedUnit, this.rDigit, this.vDigit,
|
||||
this.boundCardatronOutputWord, this.boundCardatronOutputFinished);
|
||||
@ -3821,8 +3786,8 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setCardatronCheck(1);
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.rDigit = this.CCONTROL & 0x0F;
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.rDigit = this.CCONTROL%0x10;
|
||||
this.ioInitiate();
|
||||
d = this.cardatron.inputFormatInitiate(this.selectedUnit, this.rDigit,
|
||||
this.boundCardatronOutputWord, this.boundCardatronOutputFinished);
|
||||
@ -3841,8 +3806,8 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.setCardatronCheck(1);
|
||||
this.operationComplete();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.rDigit = this.CCONTROL & 0x0F;
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
this.rDigit = this.CCONTROL%0x10;
|
||||
this.ioInitiate();
|
||||
d = this.cardatron.outputFormatInitiate(this.selectedUnit, this.rDigit,
|
||||
this.boundCardatronOutputWord, this.boundCardatronOutputFinished);
|
||||
@ -3860,7 +3825,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
if (!this.cardatron) {
|
||||
this.setCardatronCheck(1);
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
d = this.cardatron.inputReadyInterrogate(this.selectedUnit);
|
||||
if (d < 0) { // invalid unit
|
||||
this.setCardatronCheck(1);
|
||||
@ -3879,7 +3844,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
if (!this.cardatron) {
|
||||
this.setCardatronCheck(1);
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
|
||||
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
|
||||
d = this.cardatron.outputReadyInterrogate(this.selectedUnit);
|
||||
if (d < 0) { // invalid unit
|
||||
this.setCardatronCheck(1);
|
||||
@ -3906,63 +3871,6 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.operationComplete();
|
||||
break;
|
||||
} // switch this.COP
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
|
||||
switch (-1) {
|
||||
|
||||
case 0x40: //---------------- MTR Magnetic Tape Read
|
||||
if (!this.magTape) {
|
||||
//this.schedule();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 4) & 0x0F;
|
||||
d = (this.CCONTROL >>> 8) & 0xFF; // number of blocks
|
||||
this.togMT3P = 1;
|
||||
this.togMT1BV4 = d%2; // select initial loop buffer
|
||||
this.togMT1BV5 = 1-this.togMT1BV4;
|
||||
this.execTime -= performance.now()*B220Processor.wordsPerMilli; // mark time during I/O
|
||||
if (this.magTape.read(this.selectedUnit, d, this.boundMagTapeReceiveBlock)) {
|
||||
this.OFT.set(1); // control or tape unit busy/not-ready
|
||||
this.togMT3P = this.togMT1BV4 = this.togMT1BV5 = 0;
|
||||
//this.schedule();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x42: //---------------- MTS Magnetic Tape Search
|
||||
if (this.magTape) {
|
||||
this.selectedUnit = (this.CCONTROL >>> 4) & 0x0F;
|
||||
d = (this.CCONTROL >>> 8) & 0xFF; // lane number
|
||||
if (this.magTape.search(this.selectedUnit, d, this.CADDR)) {
|
||||
this.OFT.set(1); // control or tape unit busy/not-ready
|
||||
}
|
||||
}
|
||||
//this.schedule();
|
||||
break;
|
||||
|
||||
case 0x50: //---------------- MTW Magnetic Tape Write
|
||||
if (!this.magTape) {
|
||||
//this.schedule();
|
||||
} else {
|
||||
this.selectedUnit = (this.CCONTROL >>> 4) & 0x0F;
|
||||
d = (this.CCONTROL >>> 8) & 0xFF; // number of blocks
|
||||
this.togMT3P = 1;
|
||||
this.togMT1BV4 = d%2; // select initial loop buffer
|
||||
this.togMT1BV5 = 1-this.togMT1BV4;
|
||||
this.execTime -= performance.now()*B220Processor.wordsPerMilli; // mark time during I/O
|
||||
if (this.magTape.write(this.selectedUnit, d, this.boundMagTapeInitiateSend)) {
|
||||
this.OFT.set(1); // control or tape unit busy/not-ready
|
||||
this.togMT3P = this.togMT1BV4 = this.togMT1BV5 = 0;
|
||||
//this.schedule();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: //---------------- (unimplemented instruction -- alarm)
|
||||
break;
|
||||
} // switch this.COP
|
||||
***************************************************************************/
|
||||
};
|
||||
|
||||
|
||||
@ -4025,6 +3933,7 @@ B220Processor.prototype.ioInitiate = function ioInitiate() {
|
||||
/* Initiates asynchronous mode of the processor for I/O */
|
||||
|
||||
this.AST.set(1);
|
||||
this.updateGlow(1); // update the console lamps
|
||||
this.execLimit = 0; // kill the run() loop
|
||||
};
|
||||
|
||||
@ -4348,9 +4257,22 @@ B220Processor.prototype.loadDefaultProgram = function loadDefaultProgram() {
|
||||
this.MM[ 2] = 0x1000540000; // MIW 0,1,10,100
|
||||
this.MM[ 3] = 0x1750540100; // MIW 100,1,7,50
|
||||
this.MM[ 4] = 0x1500550079; // MIR 79,1,5,00
|
||||
this.MM[ 5] = 0x1101540200; // MIW 200,1,1,1
|
||||
this.MM[ 6] = 0x1009500000; // MDA 1
|
||||
this.MM[ 7] = 0x7777009999; // HLT 9999,7777
|
||||
this.MM[ 5] = 0x1101542000; // MIW 2000,1,1,1 // write control block
|
||||
|
||||
this.MM[ 6] = 0x1008500000; // MRW 1
|
||||
this.MM[ 7] = 0x1000560000; // MOW 0,1,10,100
|
||||
this.MM[ 8] = 0x1750560100; // MOW 100,1,7,50
|
||||
this.MM[ 9] = 0x1500570079; // MOR 79,1,5,00
|
||||
this.MM[ 10] = 0x1101012000; // MOW 2000,1,1,1 // TEMP: changed to a NOP
|
||||
|
||||
this.MM[ 11] = 0x1008500000; // MRW 1
|
||||
this.MM[ 12] = 0x1000523000; // MRD 3000,1,10,0
|
||||
this.MM[ 13] = 0x1700524000; // MRD 4000,1,7,0
|
||||
this.MM[ 14] = 0x1500534350; // MRR 4350,1,5,0
|
||||
this.MM[ 15] = 0x1100534800; // MRR 4800,1,1,0 // should be a control block
|
||||
|
||||
this.MM[ 16] = 0x1009500000; // MDA 1
|
||||
this.MM[ 17] = 0x7777009999; // HLT 9999,7777
|
||||
|
||||
this.MM[ 79] = 0x1900000000; // preface for 19 words, 80-98
|
||||
this.MM[ 99] = 0x4000000000; // preface for 40 words, 100-139
|
||||
@ -4358,6 +4280,10 @@ B220Processor.prototype.loadDefaultProgram = function loadDefaultProgram() {
|
||||
this.MM[ 199] = 0x9900000000; // preface for 99 words, 200-298
|
||||
this.MM[ 299] = 0x0000000000; // preface for 100 words, 300-399
|
||||
|
||||
this.MM[2000] = 0x9920012002; // end-of-tape control word
|
||||
this.MM[2001] = 0x9999999999; // storage for end-of-tape block state
|
||||
this.MM[2002] = 0x9999008421; // HLT: target for end-of-tape control branch
|
||||
|
||||
// Simple counter speed test
|
||||
this.MM[ 80] = 0x0000120082; // ADD 82
|
||||
this.MM[ 81] = 0x0000300080; // BUN 80
|
||||
|
||||
@ -35,17 +35,9 @@ function B220MagTapeControl(p) {
|
||||
|
||||
this.boundControlFinished = B220Util.bindMethod(this, B220MagTapeControl.prototype.controlFinished);
|
||||
this.boundTapeUnitFinished = B220Util.bindMethod(this, B220MagTapeControl.prototype.tapeUnitFinished);
|
||||
this.boundReadReceiveBlock = B220Util.bindMethod(this, B220MagTapeControl.prototype.readReceiveBlock);
|
||||
this.boundWriteTerminate = B220Util.bindMethod(this, B220MagTapeControl.prototype.writeTerminate);
|
||||
this.boundWriteSendBlock = B220Util.bindMethod(this, B220MagTapeControl.prototype.writeSendBlock);
|
||||
this.boundWriteInitiate = B220Util.bindMethod(this, B220MagTapeControl.prototype.writeInitiate);
|
||||
this.boundSearchComplete = B220Util.bindMethod(this, B220MagTapeControl.prototype.searchComplete);
|
||||
this.boundSwitch_Click = B220Util.bindMethod(this, B220MagTapeControl.prototype.switch_Click);
|
||||
|
||||
this.currentUnit = null; // stashed tape unit object
|
||||
this.memoryBlockCallback = null; // stashed block-sending/receiving call-back function
|
||||
this.memoryTerminateCallback = null;// stashed memory-sending terminate call-back function
|
||||
this.tapeBlock = new Float64Array(101);
|
||||
// block buffer for tape I/O
|
||||
|
||||
/* Set up the tape units from the system configuration. These can be any
|
||||
combination of Tape Storage Units (DataReaders) and DataFiles. The indexes
|
||||
@ -69,10 +61,10 @@ function B220MagTapeControl(p) {
|
||||
u = this.config.getNode("MagTape.units", x);
|
||||
switch (u.type.substring(0, 2)) {
|
||||
case "MT":
|
||||
this.tapeUnit[x] = new B220MagTapeDrive(u.type, x, this.config);
|
||||
this.tapeUnit[x] = new B220MagTapeDrive(u.type, x, this, this.config);
|
||||
break;
|
||||
case "DF":
|
||||
this.tapeUnit[x] = new B220DataFile(u.type, x, this.config);
|
||||
this.tapeUnit[x] = new B220DataFile(u.type, x, this, this.config);
|
||||
break;
|
||||
default:
|
||||
this.tapeUnit[x] = null;
|
||||
@ -90,13 +82,11 @@ B220MagTapeControl.prototype.$$ = function $$(e) {
|
||||
B220MagTapeControl.prototype.clear = function clear() {
|
||||
/* Initializes (and if necessary, creates) the panel state */
|
||||
|
||||
this.MISC = 0; // Miscellaneous control register
|
||||
this.C = 0; // C register (block number, etc.)
|
||||
this.C = 0; // C register (unit, block count, etc.)
|
||||
this.T = 0; // T register
|
||||
|
||||
this.unitNr = 0; // current unit number from command
|
||||
this.unitIndex = 0; // current index into this.tapeUnit[]
|
||||
this.blockCount = 0; // number of blocks for current operation
|
||||
this.blockWords = 0; // number of words/block for current operation
|
||||
|
||||
this.controlBusy = false; // control unit is busy with read/write/search
|
||||
@ -144,6 +134,16 @@ B220MagTapeControl.prototype.queuePendingOperation = function queuePendingOperat
|
||||
this.pendingArgs = args;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.dequeuePendingOperation = function dequeuePendingOperation() {
|
||||
/* Dequeues and reinitiates a pending tape operation */
|
||||
var args = this.pendingArgs; // pending Arguments object
|
||||
var callee = this.pendingCallee; // pending method to call
|
||||
|
||||
this.pendingCallee = this.pendingArgs = null;
|
||||
callee.apply(this, args);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.loadCommand = function loadCommand(dReg, releaseProcessor, callee, args) {
|
||||
/* If the control unit or the tape unit addressed by the unit field in dReg
|
||||
@ -153,8 +153,8 @@ B220MagTapeControl.prototype.loadCommand = function loadCommand(dReg, releasePro
|
||||
calls the releaseProcessor call-back and returns false. If the control and
|
||||
tape unit are ready for their next operation, loads the contents of the processor's
|
||||
D register passed to the operation routines into the T, C, and MISC registers.
|
||||
Sets this.unitNr, this.unitIndex, this.blockCount, and this.blockWords from
|
||||
the digits in T. Then returns true */
|
||||
Sets this.unitNr, this.unitIndex, and this.blockWords from the digits in T.
|
||||
Sets this.currentUnit to the current tape unit object. Then returns true */
|
||||
var c; // scratch
|
||||
var t = dReg%0x10000000000; // scratch
|
||||
var ux; // internal unit index
|
||||
@ -164,31 +164,33 @@ B220MagTapeControl.prototype.loadCommand = function loadCommand(dReg, releasePro
|
||||
if (this.controlBusy) {
|
||||
this.queuePendingOperation(callee, args);
|
||||
} else {
|
||||
this.MISC = 0;
|
||||
this.T = t;
|
||||
this.unitNr = (t - t%0x1000000000)/0x1000000000;
|
||||
t = (t - t%0x10000)/0x10000;
|
||||
c = t%0x10; // low-order digit of op code
|
||||
t = (t - t%0x100)/0x100; // control digits from instruction
|
||||
this.blockWords = t%0x100;
|
||||
this.blockCount = ((t - this.blockWords)/0x100)%0x10;
|
||||
if (this.blockWords == 0) {
|
||||
this.blockWords = 100;
|
||||
} else {
|
||||
if (this.blockWords > 0) {
|
||||
this.blockWords = B220Processor.bcdBinary(this.blockWords);
|
||||
} else {
|
||||
this.blockWords = 100;
|
||||
}
|
||||
|
||||
this.C = this.unitNr*0x100000 + t*0x10 + c;
|
||||
this.regMisc.update(this.MISC);
|
||||
this.clearMisc();
|
||||
this.regC.update(this.C);
|
||||
this.regT.update(this.T);
|
||||
this.unitIndex = ux = this.findDesignate(this.unitNr);
|
||||
if (ux < 0) {
|
||||
this.reportStatus(2); // drive not ready, not present
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, true);
|
||||
} else if (this.tapeUnit[ux].busy) {
|
||||
this.queuePendingOperation(callee, args);
|
||||
} else {
|
||||
result = true;
|
||||
this.currentUnit = this.tapeUnit[ux];
|
||||
if (this.currentUnit.busy || this.currentUnit.rewindLock) {
|
||||
this.queuePendingOperation(callee, args);
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,8 +203,6 @@ B220MagTapeControl.prototype.controlFinished = function controlFinished(alarm) {
|
||||
back to simulate the amount of time the control unit is busy with an I/O.
|
||||
If alarm is true, sets the Processor's Magnetic Tape Check alarm.
|
||||
If another operation is pending, initiates that operation */
|
||||
var args; // pending Arguments object
|
||||
var callee; // pending method to call
|
||||
|
||||
//console.log(this.mnemonic + " controlFinished: " + alarm + ", busy=" + this.controlBusy);
|
||||
if (alarm) {
|
||||
@ -211,20 +211,19 @@ B220MagTapeControl.prototype.controlFinished = function controlFinished(alarm) {
|
||||
|
||||
this.controlBusy = false;
|
||||
if (this.pendingCallee !== null) {
|
||||
callee = this.pendingCallee;
|
||||
args = this.pendingArgs;
|
||||
this.pendingCallee = this.pendingArgs = null;
|
||||
callee.apply(this, args);
|
||||
this.dequeuePendingOperation();
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.tapeUnitFinished = function tapeUnitFinished(alarm) {
|
||||
B220MagTapeControl.prototype.tapeUnitFinished = function tapeUnitFinished() {
|
||||
/* Call-back function passed to tape unit methods to signal when the unit has
|
||||
completed its asynchronous operation */
|
||||
|
||||
if (!this.controlBusy) { // if the control unit is currently idle...
|
||||
this.controlFinished(alarm); // initiate any pending operation
|
||||
if (this.pendingCallee !== null) {
|
||||
this.dequeuePendingOperation();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -252,10 +251,58 @@ B220MagTapeControl.prototype.decrementBlockCount = function decrementBlockCount(
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.ClearBtn_onClick = function ClearBtn_onClick(ev) {
|
||||
/* Handle the click event for the tape control CLEAR button */
|
||||
B220MagTapeControl.prototype.clearMisc = function clearMisc() {
|
||||
/* Resets this.regMisc and the individual lamps for that register */
|
||||
var bitNr;
|
||||
var m = this.regMisc;
|
||||
|
||||
this.clearUnit();
|
||||
m.update(0);
|
||||
for (bitNr=m.bits-1; bitNr>= 0; --bitNr) {
|
||||
m.lamps[bitNr].set(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.reportStatus = function reportStatus(code) {
|
||||
/* Sets bits in the MISC register to indicate various drive and control unit
|
||||
status and error conditions */
|
||||
|
||||
switch (code) {
|
||||
case 1: // report tape unit ready
|
||||
this.TX2Lamp.set(0);
|
||||
this.TX10Lamp.set(0);
|
||||
break;
|
||||
case 2: // report tape unit not ready
|
||||
this.TX2Lamp.set(1);
|
||||
this.TX10Lamp.set(1);
|
||||
break;
|
||||
case 4: // read check
|
||||
this.TYC1Lamp.set(1);
|
||||
this.TYC2Lamp.set(1);
|
||||
break;
|
||||
} // switch code
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.switch_Click = function switch_Click(ev) {
|
||||
/* Handle the click event for buttons and switches */
|
||||
|
||||
switch(ev.target.id) {
|
||||
case "ClearBtn":
|
||||
this.clearUnit();
|
||||
break;
|
||||
case "Misc_RightClear":
|
||||
this.clearMisc();
|
||||
break;
|
||||
case "C_RightClear":
|
||||
this.C = 0;
|
||||
this.regC.update(0);
|
||||
break;
|
||||
case "T_RightClear":
|
||||
this.T = 0;
|
||||
this.regT.update(0);
|
||||
break;
|
||||
} // switch target.id
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@ -304,276 +351,219 @@ B220MagTapeControl.prototype.magTapeOnLoad = function magTapeOnLoad() {
|
||||
this.TX2Lamp = this.regMisc.lamps[0];
|
||||
this.TX2Lamp.setCaption("TX2", true);
|
||||
|
||||
// C Register
|
||||
this.regC = new PanelRegister(this.$$("CRegPanel"), 6*4, 4, "C_", "C");
|
||||
|
||||
// T Register
|
||||
// Full Registers
|
||||
this.regC = new PanelRegister(this.$$("CRegPanel"), 6*4, 4, "C_", "C");
|
||||
this.regT = new PanelRegister(this.$$("TRegPanel"), 10*4, 4, "T_", "T");
|
||||
|
||||
|
||||
// Events
|
||||
|
||||
this.window.addEventListener("beforeunload", B220MagTapeControl.prototype.beforeUnload);
|
||||
this.$$("ClearBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220MagTapeControl.prototype.ClearBtn_onClick));
|
||||
this.$$("ClearBtn").addEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regMisc.rightClearBar.addEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regC.rightClearBar.addEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regT.rightClearBar.addEventListener("click", this.boundSwitch_Click, false);
|
||||
|
||||
this.clearUnit();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.readTerminate = function readTerminate() {
|
||||
/* Terminates the read operation, sets the control to not-busy, and signals
|
||||
the processor we are finished with the I/O */
|
||||
B220MagTapeControl.prototype.search = function search(dReg, releaseProcessor, bReg, fetchWord) {
|
||||
/* Searches a tape unit for a block with a keyWord matching the word at the
|
||||
operand address in memory. "bReg is the contents of the B register for a
|
||||
search, or 0 for a full-word search. This routine is used by MTS and MFS */
|
||||
var alarm = false; // error result
|
||||
var blocksLeft = true; // true => more blocks to process
|
||||
var searchWord; // target word to search for
|
||||
var that = this; // local self-reference
|
||||
|
||||
this.controlBusy = false;
|
||||
this.currentUnit.readTerminate();
|
||||
};
|
||||
function signalControl(controlWord) {
|
||||
/* Call-back function to send the EOT or control word to the Processor
|
||||
and release it for the next operation */
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.readReceiveBlock = function readReceiveBlock(block, abortRead) {
|
||||
/* Receives the next block read by the tape unit. Sends the block to the
|
||||
processor for storage in memory, updates the block counter, and if not
|
||||
finished, requests the next block from the tape. Termination is a little
|
||||
tricky here, as readTerminate() must be called to release the drive before
|
||||
the block is stored in memory (and p.executeComplete() called to advance to
|
||||
the next instruction, but if the memory call-back tells us the processor
|
||||
has been cleared, we must release the drive after the attempt to store the
|
||||
block in memory. Mess with the sequencing below at your peril */
|
||||
var lastBlock;
|
||||
var t = B220Processor.bcdBinary(this.T);
|
||||
releaseProcessor(false, true, controlWord);
|
||||
}
|
||||
|
||||
if (abortRead) {
|
||||
this.readTerminate();
|
||||
this.memoryBlockCallback(null, true);
|
||||
} else {
|
||||
// Decrement the block counter in the T register:
|
||||
t = (t + 990)%1000; // subtract 1 from the counter field without overflow
|
||||
this.T = B220Processor.binaryBCD(t);
|
||||
this.regT.update(this.T);
|
||||
function blockReady(alarm, control, controlWord, readBlock, completed) {
|
||||
/* Call-back function when the drive is ready to send the next block
|
||||
of data, or when it has encountered an error such as EOT. "alarm"
|
||||
indicates that an error has occurred and the operation is to be aborted.
|
||||
"control" inidicates that an EOT or control block was encountered, and
|
||||
"controlWord" is to be passed to the Processor for handling. Otherwise,
|
||||
if there are more blocks to write, fetches the next block from the
|
||||
Processor and calls the drive's "readBlock" function, Finally calls
|
||||
"completed" to finish the operation */
|
||||
|
||||
// If there are more blocks to read, request the next one
|
||||
lastBlock = (t < 10);
|
||||
if (lastBlock) {
|
||||
this.readTerminate();
|
||||
abortRead = this.memoryBlockCallback(block, true);
|
||||
if (alarm) {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, true);
|
||||
completed(true); // drive detected an error
|
||||
} else if (control) {
|
||||
setCallback(that.mnemonic, that, 0, signalControl, controlWord);
|
||||
completed(false);
|
||||
} else if (blocksLeft) {
|
||||
blocksLeft = that.decrementBlockCount(); // set to false on last block
|
||||
readBlock(storeWord, record, controlEnabled);// read the next block
|
||||
} else {
|
||||
abortRead = this.memoryBlockCallback(block, false);
|
||||
if (abortRead) { // processor was cleared
|
||||
this.readTerminate();
|
||||
} else { // at least one block left to go
|
||||
this.currentUnit.readBlock(this.boundReadReceiveBlock);
|
||||
}
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, false);
|
||||
completed(false); // normal termination
|
||||
}
|
||||
}
|
||||
|
||||
if (this.loadCommand(dReg, releaseProcessor, search, arguments)) {
|
||||
this.controlBusy = true;
|
||||
searchWord = fetchWord(true);
|
||||
if (searchWord < 0) {
|
||||
alarm = true;
|
||||
} else {
|
||||
alarm = this.currentUnit.searchBlock(blockReady, this.boundControlFinished);
|
||||
}
|
||||
|
||||
if (alarm) {
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
this.controlFinished(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.read = function read(unitNr, blocks, blockSender) {
|
||||
/* Initiates a read on the designated unit. "blocks" is the number of blocks
|
||||
to read in BCD; "blockSender" is the call-back function to send a block of data
|
||||
to the processor. "terminator" is the call-back function to tell the Processor
|
||||
the I/O is finished. Returns true if the control is still busy with another command
|
||||
or the unit is busy, and does not do the read */
|
||||
var result = false; // return value
|
||||
var unit; // tape unit object
|
||||
var ux; // internal unit index
|
||||
B220MagTapeControl.prototype.read = function read(dReg, releaseProcessor, record, storeWord) {
|
||||
/* Reads the number of blocks indicated in dReg. If "record" is true (MRR),
|
||||
block lengths (preface words) are stored into the word in memory preceding
|
||||
the data read from tape. "storeWord" is a function to store a word to the
|
||||
Processor's memory. This routine is used by MRD and MRR */
|
||||
var alarm = false; // error result
|
||||
var blocksLeft = true; // true => more blocks to process
|
||||
var controlEnabled = false; // true => control blocks will be recognized
|
||||
var that = this; // local self-reference
|
||||
|
||||
if (this.controlBusy) {
|
||||
result = true;
|
||||
} else {
|
||||
this.C = unitNr;
|
||||
this.regC.update(unitNr);
|
||||
ux = this.findDesignate(unitNr);
|
||||
if (ux < 0) {
|
||||
result = true;
|
||||
function signalControl(controlWord) {
|
||||
/* Call-back function to send the EOT or control word to the Processor
|
||||
and release it for the next operation */
|
||||
|
||||
releaseProcessor(false, true, controlWord);
|
||||
}
|
||||
|
||||
function blockReady(alarm, control, controlWord, readBlock, completed) {
|
||||
/* Call-back function when the drive is ready to send the next block
|
||||
of data, or when it has encountered an error such as EOT. "alarm"
|
||||
indicates that an error has occurred and the operation is to be aborted.
|
||||
"control" inidicates that an EOT or control block was encountered, and
|
||||
"controlWord" is to be passed to the Processor for handling. Otherwise,
|
||||
if there are more blocks to write, fetches the next block from the
|
||||
Processor and calls the drive's "readBlock" function, Finally calls
|
||||
"completed" to finish the operation */
|
||||
|
||||
if (alarm) {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, true);
|
||||
completed(true); // drive detected an error
|
||||
} else if (control) {
|
||||
setCallback(that.mnemonic, that, 0, signalControl, controlWord);
|
||||
completed(false);
|
||||
} else if (blocksLeft) {
|
||||
blocksLeft = that.decrementBlockCount(); // set to false on last block
|
||||
readBlock(storeWord, record, controlEnabled);// read the next block
|
||||
} else {
|
||||
this.controlBusy = true;
|
||||
this.currentUnit = unit = this.tapeUnit[ux];
|
||||
this.MISC = B220Processor.binaryBCD(unit.laneNr);
|
||||
this.regMisc.update(this.MISC);
|
||||
this.T = blocks*0x10 + unitNr;
|
||||
this.regT.update(this.T);
|
||||
this.memoryBlockCallback = blockSender;
|
||||
result = unit.readInitiate(this.boundReadReceiveBlock);
|
||||
if (result) {
|
||||
this.controlBusy = false;
|
||||
}
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, false);
|
||||
completed(false); // normal termination
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.writeTerminate = function writeTerminate(abortWrite) {
|
||||
/* Called by the drive after the last block is written to release the
|
||||
control unit and terminate the I/O. Note that "abortWrite" is not used, but
|
||||
exists for signature compatibility with writeSendBlock() */
|
||||
|
||||
this.recordLamp.set(0);
|
||||
this.controlBusy = false;
|
||||
this.memoryTerminateCallback();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.writeSendBlock = function writeSendBlock(abortWrite) {
|
||||
/* Called by the tape drive when it is ready for the next block to be written.
|
||||
Retrieves the next buffered block from the Processor and passes it to the drive.
|
||||
Unless this is the last block to write, the drive will call this again after
|
||||
tape motion is complete. Note that this.memoryBlockCallback() will return true
|
||||
if the processor has been cleared and the I/O must be aborted */
|
||||
var aborted; // true if processor aborted the I/O
|
||||
var lastBlock = abortWrite; // true if this will be the last block
|
||||
var t = B220Processor.bcdBinary(this.T);
|
||||
|
||||
// First, decrement the block counter in the T register:
|
||||
t = (t + 990)%1000; // subtract 1 from the counter field without overflow
|
||||
this.T = B220Processor.binaryBCD(t);
|
||||
this.regT.update(this.T);
|
||||
if (t < 10) {
|
||||
lastBlock = true;
|
||||
}
|
||||
|
||||
aborted = this.memoryBlockCallback(this.tapeBlock, lastBlock);
|
||||
if (abortWrite || aborted) {
|
||||
this.writeTerminate(false);
|
||||
} else if (lastBlock) {
|
||||
this.currentUnit.writeBlock(this.tapeBlock, this.boundWriteTerminate, true);
|
||||
} else {
|
||||
this.currentUnit.writeBlock(this.tapeBlock, this.boundWriteSendBlock, false);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.writeInitiate = function writeInitiate(blockReceiver, terminator) {
|
||||
/* Call-back function called by the Processor once the initial block to be
|
||||
written is buffered in one of the high-speed loops. Once this block is
|
||||
buffered, the drive can start tape motion and begin writing to tape */
|
||||
|
||||
this.memoryBlockCallback = blockReceiver;
|
||||
this.memoryTerminateCallback = terminator;
|
||||
this.currentUnit.writeInitiate(this.boundWriteSendBlock);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.write = function write(unitNr, blocks, receiveInitiate) {
|
||||
/* Initiates a write on the designated unit. "blocks" is the number of blocks
|
||||
to write in BCD; "receiveInitiate" is the call-back function to begin memory
|
||||
transfer from the processor. Returns true if the control is still busy with
|
||||
another command or the unit is busy, and does not do the write */
|
||||
var result = false; // return value
|
||||
var unit; // tape unit object
|
||||
var ux; // internal unit index
|
||||
|
||||
if (this.controlBusy) {
|
||||
result = true;
|
||||
} else {
|
||||
this.C = unitNr;
|
||||
this.regC.update(unitNr);
|
||||
ux = this.findDesignate(unitNr);
|
||||
if (ux < 0) {
|
||||
result = true;
|
||||
} else {
|
||||
this.controlBusy = true;
|
||||
this.currentUnit = unit = this.tapeUnit[ux];
|
||||
this.MISC = B220Processor.binaryBCD(unit.laneNr);
|
||||
this.regMisc.update(this.MISC);
|
||||
this.T = blocks*0x10 + unitNr;
|
||||
this.regT.update(this.T);
|
||||
result = unit.writeReadyTest();
|
||||
if (result) {
|
||||
this.controlBusy = false;
|
||||
} else {
|
||||
receiveInitiate(this.boundWriteInitiate);
|
||||
}
|
||||
if (this.loadCommand(dReg, releaseProcessor, read, arguments)) {
|
||||
this.controlBusy = true;
|
||||
controlEnabled = (this.blockWords%2 == 0); // low-order bit of v-digit
|
||||
alarm = this.currentUnit.readBlock(blockReady, this.boundControlFinished);
|
||||
if (alarm) {
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
this.controlFinished(true);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.searchComplete = function searchComplete(success) {
|
||||
/* Resets the busy status at the completion of a search */
|
||||
var d; // scratch digit
|
||||
|
||||
if (success) {
|
||||
// rotate T one digit right at end of successful search
|
||||
d = this.T % 0x10;
|
||||
this.T = d*0x1000 + (this.T - d)/0x10;
|
||||
this.regT.update(this.T);
|
||||
}
|
||||
|
||||
this.controlBusy = false;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.search = function search(unitNr, laneNr, addr) {
|
||||
/* Initiates a search on the designated unit. "laneNr" is the lane number in
|
||||
BCD; "addr" is the number of the block to search for in BCD. The search
|
||||
Takes place in the control unit and drive independently of the processor.
|
||||
Returns true if the control is still busy with another command or the unit
|
||||
is busy, and does not do the search */
|
||||
var block = B220Processor.bcdBinary(addr);
|
||||
var lane = B220Processor.bcdBinary(laneNr);
|
||||
var result = false; // return value
|
||||
var unit; // tape unit object
|
||||
var ux; // internal unit index
|
||||
|
||||
if (this.controlBusy) {
|
||||
result = true;
|
||||
} else {
|
||||
this.C = unitNr;
|
||||
this.regC.update(unitNr);
|
||||
this.MISC = laneNr;
|
||||
this.regMisc.update(laneNr);
|
||||
this.T = addr;
|
||||
this.regT.update(addr);
|
||||
ux = this.findDesignate(unitNr);
|
||||
if (ux < 0) {
|
||||
result = true;
|
||||
} else {
|
||||
this.controlBusy = true;
|
||||
unit = this.tapeUnit[ux];
|
||||
result = unit.search(lane, block, this.boundSearchComplete,
|
||||
this.boundDirectionLampSet, this.boundTestDisabled);
|
||||
if (result) {
|
||||
this.controlBusy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.initialWrite = function initialWrite(dReg, releaseProcessor, fetchBlock) {
|
||||
/* Initial-writes the number of blocks and of the size indicated in dReg.
|
||||
This routine is used by MIW */
|
||||
B220MagTapeControl.prototype.overwrite = function overwrite(dReg, releaseProcessor, record, fetchWord) {
|
||||
/* Overwrites the number of blocks and of the size indicated in dReg. If
|
||||
"record" is true (MOR), block lengths (preface words) are taken from the
|
||||
word in memory preceding the data to be written. Otherwise, block lengths
|
||||
are taken from the instruction control digits. "fetchWord" is a function to
|
||||
read a word from the Processor's memory. This routine is used by MOW and MOR */
|
||||
var alarm = false; // error result
|
||||
var blocksLeft = true; // true => more blocks to process
|
||||
var that = this; // local self-reference
|
||||
var unit = null; // selected tape unit
|
||||
var words;
|
||||
|
||||
function signalControl(controlWord) {
|
||||
/* Call-back function to send the EOT control word to the Processor
|
||||
and release it for the next operation */
|
||||
|
||||
releaseProcessor(false, true, controlWord);
|
||||
}
|
||||
|
||||
function blockReady(alarm, control, controlWord, writeBlock, completed) {
|
||||
/* Call-back function when the drive is ready to receive the next block
|
||||
of data, or when it has encountered an error such as EOT. "alarm"
|
||||
indicates that an error has occurred and the operation is to be aborted.
|
||||
"control" inidicates that an EOT block with a preface mismatch occurred,
|
||||
and "controlWord" is to be passed to the Processor for handling.
|
||||
Otherwise, if there are more blocks to write, fetches the next block
|
||||
from the Processor and calls the drive's "writeBlock" function, Finally
|
||||
calls "completed" to finish the operation */
|
||||
|
||||
if (alarm) {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, true);
|
||||
completed(true); // drive detected an error
|
||||
} else if (control) {
|
||||
setCallback(that.mnemonic, that, 0, signalControl, controlWord);
|
||||
completed(false);
|
||||
} else if (blocksLeft) {
|
||||
blocksLeft = that.decrementBlockCount(); // set to false on last block
|
||||
writeBlock(fetchWord, words); // write the next block
|
||||
} else {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, false);
|
||||
completed(false); // normal termination
|
||||
}
|
||||
}
|
||||
|
||||
if (this.loadCommand(dReg, releaseProcessor, overwrite, arguments)) {
|
||||
this.controlBusy = true;
|
||||
if (this.blockWords < this.currentUnit.minBlockWords && this.blockWords > 1) {
|
||||
alarm = true; // invalid block length
|
||||
} else {
|
||||
words = (record ? 0 : this.blockWords);
|
||||
alarm = this.currentUnit.overwriteBlock(blockReady, this.boundControlFinished);
|
||||
}
|
||||
|
||||
if (alarm) {
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
this.controlFinished(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.initialWrite = function initialWrite(dReg, releaseProcessor, record, fetchWord) {
|
||||
/* Initial-writes the number of blocks and of the size indicated in dReg.
|
||||
If "record" is true (MIR), block lengths (preface words) are taken from the
|
||||
word in memory preceding the data to be written. Otherwise, block lengths
|
||||
are taken from the instruction control digits. fetchWord" is a function to
|
||||
read a word from the Processor's memory. This routine is used by MIW and MIR */
|
||||
var alarm = false; // error result
|
||||
var blocksLeft = true; // true => more blocks to process
|
||||
var that = this; // local self-reference
|
||||
var words;
|
||||
|
||||
function blockReady(alarm, writeBlock, completed) {
|
||||
/* Call-back function when the drive is ready to receive the next block
|
||||
of data, or when it has encountered an error such as EOT. If there are
|
||||
more blocks to write, fetches the next block from the Processor and calls
|
||||
the drive's "writeBlock" function, otherwise calls "completed" to finish
|
||||
the operation */
|
||||
of data, or when it has encountered an error such as EOT. "alarm"
|
||||
indicates that an error has occurred and the operation is to be aborted.
|
||||
Otherwise, if there are more blocks to write, fetches the next block
|
||||
from the Processor and calls the drive's "writeBlock" function. Finally
|
||||
calls "completed" to finish the operation */
|
||||
|
||||
if (alarm) {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, true);
|
||||
completed(true); // drive detected an error
|
||||
} else if (blocksLeft) {
|
||||
blocksLeft = that.decrementBlockCount(); // set to false on last block
|
||||
if (that.blockWords < unit.minBlockWords && that.blockWords > 1) {
|
||||
completed(true); // invalid block size
|
||||
} else if (fetchBlock(that.tapeBlock, that.blockWords)) {
|
||||
completed(true); // Processor cleared or memory address error
|
||||
} else {
|
||||
writeBlock(that.tapeBlock, that.blockWords); // write next block
|
||||
}
|
||||
writeBlock(fetchWord, words); // write the next block
|
||||
} else {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, false);
|
||||
completed(false); // normal termination
|
||||
@ -582,70 +572,16 @@ B220MagTapeControl.prototype.initialWrite = function initialWrite(dReg, releaseP
|
||||
|
||||
if (this.loadCommand(dReg, releaseProcessor, initialWrite, arguments)) {
|
||||
this.controlBusy = true;
|
||||
unit = this.tapeUnit[this.unitIndex];
|
||||
alarm = unit.initialWriteBlock(blockReady, this.boundControlFinished);
|
||||
if (alarm) {
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
controlFinished(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.initialWriteRecord = function initialWriteRecord(dReg, releaseProcessor, fetchBlock) {
|
||||
/* Initial-writes the number of blocks indicated in dReg. Block lengths
|
||||
(preface words) are taken from the word in memory preceding the data to be
|
||||
written. This routine is used by MIR */
|
||||
var alarm = false; // error result
|
||||
var blocksLeft = true; // true => more blocks to process
|
||||
var that = this; // local self-reference
|
||||
var unit = null; // selected tape unit
|
||||
|
||||
function blockReady(alarm, writeBlock, completed) {
|
||||
/* Call-back function when the drive is ready to receive the next block
|
||||
of data, or when it has encountered an error such as EOT. If there are
|
||||
more blocks to write, fetches the next block and its size from the
|
||||
Processor and calls the drive's "writeBlock" function, otherwise calls
|
||||
"completed" to finish the operation */
|
||||
var words; // words to write for block
|
||||
|
||||
if (alarm) {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, true);
|
||||
completed(true); // drive detected an error
|
||||
} else if (blocksLeft) {
|
||||
blocksLeft = that.decrementBlockCount(); // set to false on last block
|
||||
if (fetchBlock(that.tapeBlock, 1)) { // fetch the preface word
|
||||
completed(true); // Processor cleared or memory address error
|
||||
} else {
|
||||
words = that.tapeBlock[0]; // convert preface to binary
|
||||
words = ((words - words%0x100000000)/0x100000000)%0x100;
|
||||
if (words) {
|
||||
words = (words >>> 4)*10 + words%0x10;
|
||||
} else {
|
||||
words = 100; // preface == 0 => 100
|
||||
}
|
||||
|
||||
if (words < unit.minBlockWords && words > 1) {
|
||||
completed(true); // invalid block size
|
||||
} else if (fetchBlock(that.tapeBlock, words)) {
|
||||
completed(true); // Processor cleared or memory address error
|
||||
} else {
|
||||
writeBlock(that.tapeBlock, words); // write next block
|
||||
}
|
||||
}
|
||||
if (this.blockWords < this.currentUnit.minBlockWords && this.blockWords > 1) {
|
||||
alarm = true; // invalid block length
|
||||
} else {
|
||||
setCallback(that.mnemonic, that, 0, releaseProcessor, false);
|
||||
completed(false); // normal termination
|
||||
words = (record ? 0 : this.blockWords);
|
||||
alarm = this.currentUnit.initialWriteBlock(blockReady, this.boundControlFinished);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.loadCommand(dReg, releaseProcessor, initialWriteRecord, arguments)) {
|
||||
this.controlBusy = true;
|
||||
unit = this.tapeUnit[this.unitIndex];
|
||||
alarm = unit.initialWriteBlock(blockReady, this.boundControlFinished);
|
||||
if (alarm) {
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
controlFinished(true);
|
||||
this.controlFinished(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -655,7 +591,6 @@ B220MagTapeControl.prototype.positionForward = function positionForward(dReg, re
|
||||
/* Positions the tape forward the number of blocks indicated in dReg */
|
||||
var alarm = false; // error result
|
||||
var that = this; // local self-reference
|
||||
var unit = null; // selected tape unit
|
||||
|
||||
function blockFinished(nextBlock, completed) {
|
||||
/* Call-back function when the drive has finished spacing one block
|
||||
@ -671,8 +606,7 @@ B220MagTapeControl.prototype.positionForward = function positionForward(dReg, re
|
||||
|
||||
if (this.loadCommand(dReg, releaseProcessor, positionForward, arguments)) {
|
||||
this.controlBusy = true;
|
||||
unit = this.tapeUnit[this.unitIndex];
|
||||
alarm = unit.positionForward(blockFinished, this.boundControlFinished);
|
||||
alarm = this.currentUnit.positionForward(blockFinished, this.boundControlFinished);
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
}
|
||||
};
|
||||
@ -682,7 +616,6 @@ B220MagTapeControl.prototype.positionBackward = function positionBackward(dReg,
|
||||
/* Positions the tape backward the number of blocks indicated in dReg */
|
||||
var alarm = false; // error result
|
||||
var that = this; // local self-reference
|
||||
var unit = null; // selected tape unit
|
||||
|
||||
function blockFinished(nextBlock, completed) {
|
||||
/* Call-back function when the drive has finished spacing one block
|
||||
@ -698,8 +631,7 @@ B220MagTapeControl.prototype.positionBackward = function positionBackward(dReg,
|
||||
|
||||
if (this.loadCommand(dReg, releaseProcessor, positionBackward, arguments)) {
|
||||
this.controlBusy = true;
|
||||
unit = this.tapeUnit[this.unitIndex];
|
||||
alarm = unit.positionBackward(blockFinished, this.boundControlFinished);
|
||||
alarm = this.currentUnit.positionBackward(blockFinished, this.boundControlFinished);
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
}
|
||||
};
|
||||
@ -713,13 +645,13 @@ B220MagTapeControl.prototype.positionAtEnd = function positionAtEnd(dReg, releas
|
||||
|
||||
if (this.loadCommand(dReg, releaseProcessor, positionAtEnd, arguments)) {
|
||||
this.controlBusy = true;
|
||||
alarm = this.tapeUnit[this.unitIndex].positionAtEnd(this.boundControlFinished);
|
||||
alarm = this.currentUnit.positionAtEnd(this.boundControlFinished);
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.laneSelect = function laneSelect(dReg, releaseProcessor) {
|
||||
B220MagTapeControl.prototype.laneSelect = function laneSelect(dReg, releaseProcessor, fetchWord) {
|
||||
/* Selects the tape lane of the designated unit. Returns an alarm if the
|
||||
unit does not exist or is not ready */
|
||||
var alarm = false; // error result
|
||||
@ -728,13 +660,14 @@ B220MagTapeControl.prototype.laneSelect = function laneSelect(dReg, releaseProce
|
||||
if (this.loadCommand(dReg, releaseProcessor,laneSelect, arguments)) {
|
||||
this.controlBusy = true;
|
||||
laneNr = ((this.C - this.C%0x100)/0x100)%2;
|
||||
alarm = this.tapeUnit[this.unitIndex].laneSelect(laneNr, this.boundControlFinished);
|
||||
fetchWord(true); // memory access for MTS/MFS not used by MLS
|
||||
alarm = this.currentUnit.laneSelect(laneNr, this.boundControlFinished);
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.rewind = function rewind(dReg, releaseProcessor) {
|
||||
B220MagTapeControl.prototype.rewind = function rewind(dReg, releaseProcessor, fetchWord) {
|
||||
/* Initiates rewind of the designated unit. Returns an alarm if the unit
|
||||
does not exist or is not ready */
|
||||
var alarm = false; // error result
|
||||
@ -745,7 +678,8 @@ B220MagTapeControl.prototype.rewind = function rewind(dReg, releaseProcessor) {
|
||||
this.controlBusy = true;
|
||||
laneNr = ((this.C - this.C%0x100)/0x100)%2;
|
||||
lockout = ((this.C - this.C%0x10)/0x10)%2;
|
||||
alarm = this.tapeUnit[this.unitIndex].rewind(laneNr, lockout, this.boundTapeUnitFinished);
|
||||
fetchWord(true); // memory access for MTS/MFS not used by MRW/MDA
|
||||
alarm = this.currentUnit.rewind(laneNr, lockout);
|
||||
setCallback(this.mnemonic, this, 50, this.controlFinished, false);
|
||||
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
|
||||
}
|
||||
@ -795,7 +729,7 @@ B220MagTapeControl.prototype.clearUnit = function clearUnit() {
|
||||
/* Clears the internal state of the control unit */
|
||||
|
||||
this.clear();
|
||||
this.regMisc.update(this.MISC);
|
||||
this.clearMisc();
|
||||
this.regC.update(this.C);
|
||||
this.regT.update(this.T);
|
||||
};
|
||||
@ -814,6 +748,10 @@ B220MagTapeControl.prototype.shutDown = function shutDown() {
|
||||
}
|
||||
}
|
||||
|
||||
this.window.removeEventListener("beforeunload", B220MagTapeControl.prototype.beforeUnload);
|
||||
this.window.removeEventListener("beforeunload", B220MagTapeControl.prototype.beforeUnload, false);
|
||||
this.$$("ClearBtn").removeEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regMisc.rightClearBar.removeEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regC.rightClearBar.removeEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regT.rightClearBar.removeEventListener("click", this.boundSwitch_Click, false);
|
||||
this.window.close();
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
CACHE MANIFEST
|
||||
# retro-220 emulator 0.03a, 2017-10-19 08:45
|
||||
# retro-220 emulator 0.03b, 2017-11-02 12:30
|
||||
CACHE:
|
||||
../emulator/B220Processor.js
|
||||
B220.css
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user