1
0
mirror of https://github.com/pkimpel/retro-220.git synced 2026-03-27 10:20:49 +00:00

Commit 220 emulator version 0.3a:

1. Commit initial (incomplete) implementation of magnetic tape drives (TSU) and control: MLS, MRW, MDA, MIW, MIR, MPF, MPB, MPE, MIB, MIE.
2. Change B220SetCallback.js "setImmediate" mechanism to use DOM Promises instead of window.postMessage().
3. Minor styling and window positioning changes.
This commit is contained in:
Paul Kimpel
2017-10-19 09:18:48 -07:00
parent c465da8eef
commit d518d6e044
24 changed files with 3496 additions and 245 deletions

View File

@@ -224,9 +224,6 @@ function B220Processor(config, devices) {
this.TAT = new B220Processor.FlipFlop(this, false); // magnetic tape alarm toggle
this.UET = new B220Processor.FlipFlop(this, false); // unequal comparison toggle (HIT=UET=0 => off)
// Mag-Tape Control Unit switch
this.tswSuppressB = 0; // Suppress B-register modification on input
// Left/Right Maintenance Panel
this.leftPanelOpen = false;
this.rightPanelOpen = false;
@@ -245,10 +242,9 @@ function B220Processor(config, devices) {
this.boundCardatronOutputFinished = B220Processor.bindMethod(this, B220Processor.prototype.cardatronOutputFinished);
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.boundMagTapeInitiateSend = B220Processor.bindMethod(this, B220Processor.prototype.magTapeInitiateSend);
this.boundMagTapeSendBlock = B220Processor.bindMethod(this, B220Processor.prototype.magTapeSendBlock);
this.boundMagTapeTerminateSend = B220Processor.bindMethod(this, B220Processor.prototype.magTapeTerminateSend);
this.clear(); // Create and initialize the processor state
@@ -260,7 +256,7 @@ function B220Processor(config, devices) {
* Global Constants *
***********************************************************************/
B220Processor.version = "0.03";
B220Processor.version = "0.03a";
B220Processor.tick = 1000/200000; // milliseconds per clock cycle (200KHz)
B220Processor.cyclesPerMilli = 1/B220Processor.tick;
@@ -1056,7 +1052,7 @@ B220Processor.prototype.setPaperTapeCheck = function setPaperTapeCheck(value) {
/**************************************/
B220Processor.prototype.setHighSpeedPrinterCheck = function setHighSpeedPrinterCheck(value) {
/* Sets the Cardatron Check alarm */
/* Sets the High Speed Printer Check alarm */
if (!this.ALARMSW) {
this.HAT.set(value);
@@ -2755,11 +2751,11 @@ B220Processor.prototype.cardatronOutputFinished = function cardatronOutputFinish
/**************************************/
B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(word) {
/* Handles a word coming from the Cardatron input unit. Negative values for
the word indicates this is the last word and the I/O is finished. The word
is stored into the D register and is handled according to the sign digit in
the D register. The last word received (typically a "pusher" word of zeroes)
is abandoned and not acted upon. Returns -1 if further data transfer is to
be terminated, 0 otherwise */
the word indicates this is the last word and the I/O is finished. Otherwise,
the word is stored into the D register and is handled according to the sign
digit in the D register. The last word received (typically a "pusher" word
of zeroes) is abandoned and not acted upon. Returns -1 if further data
transfer is to be terminated, 0 otherwise */
var returnCode = 0; // default is to continue receiving
var sign; // D-register sign digit
@@ -2836,95 +2832,70 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
***********************************************************************/
/**************************************/
B220Processor.prototype.magTapeInitiateSend = function magTapeInitiateSend(writeInitiate) {
/* Performs the initial memory block-to-loop operation after the tape control
unit has determined the drive is ready and not busy. Once the initial loop is
loaded, calls "writeInitiate" to start tape motion, which in turn will cause
the control to call this.magTapeSendBlock to pass the loop data to the drive
and initiate loading of the alternate loop buffer */
var that = this;
B220Processor.prototype.magTapeComplete = function magTapeComplete(alarm, control, word) {
/* Call-back routine to signal completion of a magnetic tape operation. If
"alarm" is true, the Magnetic Tape Alarm will be set. If "control" is true,
the contents of "word" are processed as a tape control word and an appropriate
branch is set up. Unconditionally terminates the tape I/O instruction */
var aaaa;
var bbbb;
if (this.togMT3P) { // if false, we've probably been cleared
if (this.CADDR >= 0x8000) {
writeInitiate(this.boundMagTapeSendBlock, this.boundMagTapeTerminateSend);
} else {
this.execTime += performance.now()*B220Processor.wordsPerMilli; // restore time after I/O
this.blockToLoop((this.togMT1BV4 ? 4 : 5), function initialBlockComplete() {
that.execTime -= performance.now()*B220Processor.wordsPerMilli; // suspend time during I/O
writeInitiate(that.boundMagTapeSendBlock, that.boundMagTapeTerminateSend);
});
if (alarm) {
this.setMagneticTapeCheck(true);
} else if (control) {
this.D.set(word);
bbbb = word%0x10000;
aaaa = ((word - bbbb)/0x10000)%0x10000;
if ((word - word%0x10000000000)%2) { // if sign bit is 1,
bbbb = this.bcdAdd(bbbb, this.B.value, 4); // B-adjust the low-order 4 digits
}
this.E.set(aaaa);
this.readMemory();
if (!this.MET.value) {
this.IB.set(this.IB.value - this.IB.value%0x100000000 +
(this.C.value%0x10000)*0x10000 + this.P.value%0x10000);
this.writeMemory();
this.P.set(bbbb);
}
}
this.ioComplete(true);
};
/**************************************/
B220Processor.prototype.magTapeSendBlock = function magTapeSendBlock(lastBlock) {
/* Sends a block of data from a loop buffer to the tape control unit and
initiates the load of the alternate loop buffer. this.togMT1BV4 and
this.togMT1BV5 control alternation of the loop buffers. "lastBlock" indicates
this will be the last block requested by the control unit and no further
blocks should be buffered. If the C-register address is 8000 or higher, the
loop is not loaded from main memory, and the current contents of the loop
are written to tape. Since tape block writes take 46 ms, they are much
longer than any memory-to-loop transfer, so this routine simply exits after
the next blockToLoop is initiated, and the processor then waits for the tape
control unit to request the next block, by which time the blockToLoop will
have completed. Returns null if the processor has been cleared and the I/O
must be aborted */
var loop;
var that = this;
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
function blockFetchComplete() {
that.execTime -= performance.now()*B220Processor.wordsPerMilli; // suspend time again during I/O
}
//console.log("TSU " + this.selectedUnit + " W, Len " + words +
// ", ADDR=" + this.CADDR.toString(16));
//console.log("TSU " + this.selectedUnit + " W, L" + (this.togMT1BV4 ? 4 : 5) +
// ", ADDR=" + this.CADDR.toString(16) +
// " : " + block[0].toString(16) + ", " + block[19].toString(16));
if (!this.togMT3P) {
loop = null;
if (!this.AST.value) {
result = true;
} else {
// Select the appropriate loop to send data to 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 (!lastBlock) {
this.execTime += performance.now()*B220Processor.wordsPerMilli; // restore time after I/O
// Flip the loop-buffer toggles
this.togMT1BV5 = this.togMT1BV4;
this.togMT1BV4 = 1-this.togMT1BV4;
// Block the loop buffer from main memory if appropriate
if (this.CADDR < 0x8000) {
this.blockToLoop((this.togMT1BV4 ? 4 : 5), blockFetchComplete);
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 {
blockFetchComplete();
buffer[x] = this.IB.value;
++x;
}
}
this.A.set(loop[loop.length-1]); // for display only
this.D.set(0); // for display only
}
return loop; // give the loop data to the control unit
};
/**************************************/
B220Processor.prototype.magTapeTerminateSend = function magTapeTerminateSend() {
/* Called by the tape control unit after the last block has been completely
written to tape. Terminates the write instruction */
if (this.togMT3P) { // if false, we've probably been cleared
this.togMT3P = 0;
this.togMT1BV4 = this.togMT1BV5 = 0;
this.execTime += performance.now()*B220Processor.wordsPerMilli; // restore time after I/O
this.schedule();
}
this.C.set(this.C.value - this.C.value%0x10000 + this.CADDR);
return result;
};
/**************************************/
@@ -3676,9 +3647,32 @@ B220Processor.prototype.execute = function execute() {
this.operationComplete();
break;
case 0x50: //--------------------- MT* Magnetic tape search/field search/lane select/rewind
this.setProgramCheck(1);
this.operationComplete();
case 0x50: //--------------------- MTS/MFS/MLS/MRW/MDA Magnetic tape search/field search/lane select/rewind
this.opTime = 0.160;
if (!this.magTape) {
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
}
break;
case 0x51: //--------------------- MTC/MFC Magnetic tape scan/field scan
@@ -3697,13 +3691,31 @@ B220Processor.prototype.execute = function execute() {
break;
case 0x54: //--------------------- MIW Magnetic tape initial write
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) & 0x0F;
this.CCONTROL = this.CADDR; // copy C address into control digits
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
this.ioInitiate();
this.magTape.initialWrite(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendBlock);
}
break;
case 0x55: //--------------------- MIR Magnetic tape initial write, 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) & 0x0F;
this.CCONTROL = this.CADDR; // copy C address into control digits
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
this.ioInitiate();
this.magTape.initialWriteRecord(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendBlock);
}
break;
case 0x56: //--------------------- MOW Magnetic tape overwrite
@@ -3716,13 +3728,47 @@ B220Processor.prototype.execute = function execute() {
this.operationComplete();
break;
case 0x58: //--------------------- MPF/MPB Magnetic tape position forward/backward/at end
this.setProgramCheck(1);
this.operationComplete();
case 0x58: //--------------------- MPF/MPB/MIE Magnetic tape position forward/backward/at end
this.opTime = 0.130;
if (!this.magTape) {
this.setMagneticTapeCheck(true); // no tape control
this.operationComplete();
} else {
this.selectedUnit = (this.CCONTROL >>> 12) & 0x0F;
this.ioInitiate();
switch (this.CCONTROL%0x10) {
case 1: // MPB: position tape backward
this.magTape.positionBackward(this.D.value, this.boundMagTapeComplete);
break;
case 2: // MPE: position tape at end
this.magTape.positionAtEnd(this.D.value, this.boundMagTapeComplete);
break;
default: // MPF: position tape forward
this.magTape.positionForward(this.D.value, this.boundMagTapeComplete);
break;
} // switch on operation variant
}
break;
case 0x59: //--------------------- MIB/MIE Magnetic tape interrogate, branch/end of tape, branch
this.setProgramCheck(1);
if (!this.magTape) {
this.opTime = 0.01;
} else if (this.magTape.controlBusy) {
this.opTime = 0.01;
} else {
opTime = 0.14;
if (this.CCONTROL%0x10 == 1) { // MIE
if (this.magTape.testUnitAtMagneticEOT(this.D.value)) {
this.P.set(this.CADDR);
this.opTime += 0.020;
}
} else { // MIB
if (this.magTape.testUnitReady(this.D.value)) {
this.P.set(this.CADDR);
this.opTime += 0.020;
}
}
}
this.operationComplete();
break;
@@ -3913,14 +3959,6 @@ B220Processor.prototype.execute = function execute() {
}
break;
case 0x52: //---------------- MTRW Magnetic Tape Rewind
if (this.magTape) {
this.selectedUnit = (this.CCONTROL >>> 4) & 0x0F;
if (this.magTape.rewind(this.selectedUnit)) {
this.OFT.set(1); // control or tape unit busy/not-ready
}
}
break;
default: //---------------- (unimplemented instruction -- alarm)
break;
} // switch this.COP
@@ -4132,6 +4170,7 @@ B220Processor.prototype.stop = function stop() {
this.execLimit = 0; // kill the time slice
this.SST.set(0);
this.RUT.set(0);
this.AST.set(0);
// Stop the timers
this.clockIn();
@@ -4169,7 +4208,11 @@ B220Processor.prototype.setStop = function setStop() {
the end of the Execute cycle, then stop */
if (this.poweredOn) {
this.RUT.set(0);
if (this.RUT.value) {
this.RUT.set(0);
} else {
this.stop();
}
}
};
@@ -4250,7 +4293,9 @@ B220Processor.prototype.tcuClear = function tcuClear() {
/* Clears the Tape Control Unit */
if (this.poweredOn) {
//?? TBD ??
if (this.magTape) {
this.magTape.clearUnit();
}
}
};
@@ -4297,6 +4342,22 @@ B220Processor.prototype.powerDown = function powerDown() {
B220Processor.prototype.loadDefaultProgram = function loadDefaultProgram() {
/* Loads a set of default demo programs to the memory drum */
// TEMP // Tape tests
this.MM[ 0] = 0x1008500000; // MRW 1
this.MM[ 1] = 0x1002580000; // MPE 1
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[ 79] = 0x1900000000; // preface for 19 words, 80-98
this.MM[ 99] = 0x4000000000; // preface for 40 words, 100-139
this.MM[ 140] = 0x5800000000; // preface for 58 words, 141-198
this.MM[ 199] = 0x9900000000; // preface for 99 words, 200-298
this.MM[ 299] = 0x0000000000; // preface for 100 words, 300-399
// Simple counter speed test
this.MM[ 80] = 0x0000120082; // ADD 82
this.MM[ 81] = 0x0000300080; // BUN 80

View File

@@ -36,14 +36,15 @@
<!--
<script src="./B220DataFile.js"></script>
-->
<script src="./B220MagTapeDrive.js"></script>
<script src="./B220MagTapeControl.js"></script>
-->
<script src="./B220ConsoleKeyboard.js"></script>
<script src="./B220ConsolePrinter.js"></script>
<script src="./B220PaperTapePunch.js"></script>
<script src="./B220PaperTapeReader.js"></script>
<script src="./B220ControlConsole.js"></script>
<script src="./B220.js"></script>

View File

@@ -60,13 +60,11 @@ window.addEventListener("load", function() {
devices.CardatronControl = null;
}
/********************
if (config.getNode("MagTape.hasMagTape")) {
devices.MagTapeControl = new B220MagTapeControl(processor);
} else {
devices.MagTapeControl = null;
}
********************/
// Control Console must be instantiated last
devices.ControlConsole = new B220ControlConsole(processor, systemShutDown);

View File

@@ -38,7 +38,7 @@
#ClearBtnCaption {
bottom: 4px;
right: 4px;
width: 40px}
width: 32px}
#OutputUnitLamp {
top: 8px;

View File

@@ -445,7 +445,7 @@ DIV.redButton1 {
width: 14px;
height: 14px;
font-size: 4px;
background-image: radial-gradient(circle, #C00, #F00);
background-image: radial-gradient(circle, #C00, #E00, #F00);
border-radius: 50%;
border: 10px solid #CCC}
DIV.redButton2 {
@@ -453,7 +453,7 @@ DIV.redButton2 {
width: 8px;
height: 8px;
font-size: 4px;
background-image: radial-gradient(circle, #C00, #F00);
background-image: radial-gradient(circle, #C00, #E00, #F00);
border-radius: 50%;
border: 6px solid #CCC}
DIV.redButton3 {
@@ -461,7 +461,7 @@ DIV.redButton3 {
width: 20px;
height: 20px;
font-size: 4px;
background-image: radial-gradient(circle, #C00, #F00);
background-image: radial-gradient(circle, #C00, #E00, #F00);
border-radius: 50%;
border: 2px solid #CCC}
DIV.blackButton1 {
@@ -469,7 +469,7 @@ DIV.blackButton1 {
width: 14px;
height: 14px;
font-size: 4px;
background-image: radial-gradient(circle, #000, #333);
background-image: radial-gradient(circle, #333, #111, #000);
border-radius: 50%;
border: 10px solid #CCC}
DIV.blackButton3 {
@@ -477,7 +477,7 @@ DIV.blackButton3 {
width: 20px;
height: 20px;
font-size: 4px;
background-image: radial-gradient(circle, #000, #333);
background-image: radial-gradient(circle, #333, #111, #000);
border-radius: 50%;
border: 2px solid #CCC}

View File

@@ -84,12 +84,14 @@
#EndOfPaper.hidden {
display: none}
/***** TTY Control Panel *****/
#FormatControlsDiv {
position: absolute;
overflow: visible;
display: none;
left: calc(50% - 312px);
top: 48px;
left: 2px;
top: 4px;
z-index: 10;
height: 216px;
width: 624px;

View File

@@ -48,7 +48,7 @@ function B220ConsolePrinter(mnemonic, unitIndex, config) {
this.printerLine = 0;
this.printerCol = 0;
this.window = window.open("../webUI/B220ConsolePrinter.html", mnemonic,
"location=no,scrollbars=no,resizable,width=640,height=300," +
"location=no,scrollbars=no,resizable,width=640,height=240," +
"left=" + left + ",top=" + top);
this.window.addEventListener("load", B220Util.bindMethod(this,
B220ConsolePrinter.prototype.printerOnLoad));

View File

@@ -0,0 +1,57 @@
/***********************************************************************
* retro-220/webUI B220MagTapeControl.css
************************************************************************
* Copyright (c) 2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* Burroughs 220 emulator Magnetic Tape Control style sheet.
************************************************************************
* 2017-07-09 P.Kimpel
* Original version, from retro-205 D205MagTapeControl.css.
***********************************************************************/
DIV.panelRegCaption { /* Overrides class in B220Common.css */
border-top: none}
#mtControlBody {
height: 100%;
min-height: 100%;
overflow: hidden;
padding: 0}
#PanelSurface {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: 0}
#ClearBtn {
bottom: 60px;
left: 8px;
border: 10px solid #CCC;
box-shadow: 3px 3px 2px #999}
#ClearBtnCaption {
bottom: 48px;
left: 8px;
width: 32px}
#MiscRegPanel {
left: 52px;
top: 4px;
width: 144px;
height: 128px}
#CRegPanel {
left: 208px;
top: 4px;
width: 192px;
height: 128px}
#TRegPanel {
left: 412px;
top: 4px;
width: 288px;
height: 128px}

View File

@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>retro-220 Mag Tape Control Unit</title>
<!--
/***********************************************************************
* retro-220/webUI B220MagTapeControl.html
************************************************************************
* Copyright (c) 2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* Burroughs 220 Magnetic Tape Control page.
************************************************************************
* 2017-07-09 P.Kimpel
* Original version, from retro-205 D205MagTapeControl.html.
***********************************************************************/
-->
<meta name="Author" content="Paul Kimpel">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B220Common.css">
<link id=consoleStyleSheet rel=stylesheet type="text/css" href="B220MagTapeControl.css">
</head>
<body id=mtControlBody class=panelBody>
<div id=PanelSurface class=panelSurface>
<div id=ClearBtn class=redButton1>&nbsp;</div>
<div id=ClearBtnCaption class=caption>CLEAR</div>
<div id=MiscRegPanel class=panelRegister></div>
<div id=CRegPanel class=panelRegister></div>
<div id=TRegPanel class=panelRegister></div>
</div>
</body>
</html>

819
webUI/B220MagTapeControl.js Normal file
View File

@@ -0,0 +1,819 @@
/***********************************************************************
* retro-220/webUI B220MagTapeControl.js
************************************************************************
* Copyright (c) 2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* Burroughs 220 MagTape Control unit module.
************************************************************************
* 2017-07-09 P.Kimpel
* Original version, from retro-205 D205MagTapeControl.js.
***********************************************************************/
"use strict";
/**************************************/
function B220MagTapeControl(p) {
/* Constructor for the MagTapeControl object */
var left = 0; // control window left position
var top = 412; // control window top-from-bottom position
var u; // unit configuration object
var x; // unit index
this.config = p.config; // System configuration object
this.mnemonic = "MCU";
this.p = p; // B220Processor object
// Do not call this.clear() here -- call this.clearUnit() from onLoad instead
this.doc = null;
this.window = window.open("../webUI/B220MagTapeControl.html", this.mnemonic,
"location=no,scrollbars=no,resizable,width=712,height=144,top=" +
(screen.availHeight - top) + ",left=" + left);
this.window.addEventListener("load",
B220Util.bindMethod(this, B220MagTapeControl.prototype.magTapeOnLoad));
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.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
into this array are physical unit numbers used internally -- unit designate
is set on the tape unit itself */
this.tapeUnit = [
null, // 0=not used
null, // tape unit A
null, // tape unit B
null, // tape unit C
null, // tape unit D
null, // tape unit E
null, // tape unit F
null, // tape unit G
null, // tape unit H
null, // tape unit I
null]; // tape unit J
for (x=1; x<this.tapeUnit.length; ++x) {
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);
break;
case "DF":
this.tapeUnit[x] = new B220DataFile(u.type, x, this.config);
break;
default:
this.tapeUnit[x] = null;
break;
} // switch u.type
} // for x
}
/**************************************/
B220MagTapeControl.prototype.$$ = function $$(e) {
return this.doc.getElementById(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.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
this.pendingCallee = null; // method to call for a pending operation
this.pendingArgs = null; // Arguments object for a pending operation
};
/**************************************/
B220MagTapeControl.prototype.findDesignate = function findDesignate(u) {
/* Searches this.tapeUnit[] to find the internal index of the unit that is
designated as "u". If found, returns the internal index; if not found,
returns -1. If more than one ready unit with the same designate is found,
returns -2 */
var index = -1;
var unit;
var x;
for (x=this.tapeUnit.length-1; x>=0; --x) {
unit = this.tapeUnit[x];
if (unit && unit.ready) {
if (unit.unitDesignate == u) {
if (index == -1) {
index = x;
} else {
index = -2;
break; // out of for loop
}
}
}
} // for x
return index;
};
/**************************************/
B220MagTapeControl.prototype.queuePendingOperation = function queuePendingOperation(callee, args) {
/* Queues a pending tape operation */
//console.log(this.mnemonic + " queuePendingOperation: " + args[0].toString(16));
if (this.pendingCallee !== null) {
throw new Error("More than one pending tape control operation");
}
this.pendingCallee = callee;
this.pendingArgs = 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
are currently busy, queues the args parameter (an Arguments object) in
this.pendingCallee and -Args, and returns false. If the control is idle but
the tape unit is not ready or not present, or two units have the same designate,
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 */
var c; // scratch
var t = dReg%0x10000000000; // scratch
var ux; // internal unit index
var result = false; // return value
//console.log(this.mnemonic + " loadCommand: " + dReg.toString(16));
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 {
this.blockWords = B220Processor.bcdBinary(this.blockWords);
}
this.C = this.unitNr*0x100000 + t*0x10 + c;
this.regMisc.update(this.MISC);
this.regC.update(this.C);
this.regT.update(this.T);
this.unitIndex = ux = this.findDesignate(this.unitNr);
if (ux < 0) {
setCallback(this.mnemonic, this, 0, releaseProcessor, true);
} else if (this.tapeUnit[ux].busy) {
this.queuePendingOperation(callee, args);
} else {
result = true;
}
}
return result;
};
/**************************************/
B220MagTapeControl.prototype.controlFinished = function controlFinished(alarm) {
/* Releases the busy status of the control. Typically used as a timed call-
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) {
this.p.setMagneticTapeCheck(true);
}
this.controlBusy = false;
if (this.pendingCallee !== null) {
callee = this.pendingCallee;
args = this.pendingArgs;
this.pendingCallee = this.pendingArgs = null;
callee.apply(this, args);
}
};
/**************************************/
B220MagTapeControl.prototype.tapeUnitFinished = function tapeUnitFinished(alarm) {
/* 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
}
};
/**************************************/
B220MagTapeControl.prototype.decrementBlockCount = function decrementBlockCount() {
/* Decrements the block-count digit in the C register. Returns true if the
remaining block count is non-zero, false otherwise */
var c1 = this.C; // will hold two high-order digits of C: uu0000
var c2 = c1%0x10000; // four low-order digits of C: bddd, b=block count
var result = true;
c1 -= c2;
if (c2 < 0x1000) {
c2 += 0x9000; // decrement 0x0ddd to 0x9ddd as count=0 => 10
} else {
c2 -= 0x1000; // decrement 0xddd..0x9ddd
if (c2 < 0x1000) {
result = false; // decremented 0x1ddd to 0x0ddd: no more blocks
}
}
this.C = c1+c2;
this.regC.update(this.C);
return result;
};
/**************************************/
B220MagTapeControl.prototype.ClearBtn_onClick = function ClearBtn_onClick(ev) {
/* Handle the click event for the tape control CLEAR button */
this.clearUnit();
};
/**************************************/
B220MagTapeControl.prototype.beforeUnload = function beforeUnload(ev) {
var msg = "Closing this window will make the panel unusable.\n" +
"Suggest you stay on the page and minimize this window instead";
ev.preventDefault();
ev.returnValue = msg;
return msg;
};
/**************************************/
B220MagTapeControl.prototype.magTapeOnLoad = function magTapeOnLoad() {
/* Initializes the MagTape Control window and user interface */
var body;
var box;
var e;
var x;
this.doc = this.window.document;
body = this.$$("PanelSurface");
// Misc Register
this.regMisc = new PanelRegister(this.$$("MiscRegPanel"), 4*4, 4, "Misc_", " ");
this.regMisc.lamps[15].setCaption("MCL", true);
this.regMisc.lamps[14].setCaption("MC6", true);
this.TYC1Lamp = this.regMisc.lamps[13];
this.TYC1Lamp.setCaption("TYC", true);
this.TYC2Lamp = this.regMisc.lamps[12];
this.TYC2Lamp.setCaption("TYC", true);
this.TCFLamp = this.regMisc.lamps[10]; // not in this physical position on a 220
this.TCFLamp.setCaption("TCF", true);
this.TPCLamp = this.regMisc.lamps[7];
this.TPCLamp.setCaption("TPC", true);
this.regMisc.lamps[6].setCaption("TSX", true);
this.regMisc.lamps[5].setCaption("1R6", true);
this.TX1Lamp = this.regMisc.lamps[4];
this.TX1Lamp.setCaption("TX1", true);
this.TX10Lamp = this.regMisc.lamps[3];
this.TX10Lamp.setCaption("TX10", true);
this.TX8Lamp = this.regMisc.lamps[2];
this.TX8Lamp.setCaption("TX8", true);
this.TX4Lamp = this.regMisc.lamps[1];
this.TX4Lamp.setCaption("TX4", true);
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
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.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 */
this.controlBusy = false;
this.currentUnit.readTerminate();
};
/**************************************/
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);
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);
// If there are more blocks to read, request the next one
lastBlock = (t < 10);
if (lastBlock) {
this.readTerminate();
abortRead = this.memoryBlockCallback(block, true);
} 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);
}
}
}
};
/**************************************/
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
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);
this.memoryBlockCallback = blockSender;
result = unit.readInitiate(this.boundReadReceiveBlock);
if (result) {
this.controlBusy = false;
}
}
}
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);
}
}
}
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 */
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 from the Processor and calls
the drive's "writeBlock" function, otherwise 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
}
} else {
setCallback(that.mnemonic, that, 0, releaseProcessor, false);
completed(false); // normal termination
}
}
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
}
}
} else {
setCallback(that.mnemonic, that, 0, releaseProcessor, false);
completed(false); // normal termination
}
}
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);
}
}
};
/**************************************/
B220MagTapeControl.prototype.positionForward = function positionForward(dReg, releaseProcessor) {
/* 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
forward. If there are more blocks to space, calls "nextBlock", otherwise
calls "completed" to finish the operation */
if (that.decrementBlockCount()) {
nextBlock(blockFinished);
} else {
completed(false);
}
}
if (this.loadCommand(dReg, releaseProcessor, positionForward, arguments)) {
this.controlBusy = true;
unit = this.tapeUnit[this.unitIndex];
alarm = unit.positionForward(blockFinished, this.boundControlFinished);
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
}
};
/**************************************/
B220MagTapeControl.prototype.positionBackward = function positionBackward(dReg, releaseProcessor) {
/* 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
backward. If there are more blocks to space, calls "nextBlock", otherwise
calls "completed" to finish the operation */
if (that.decrementBlockCount()) {
nextBlock(blockFinished);
} else {
completed(false);
}
}
if (this.loadCommand(dReg, releaseProcessor, positionBackward, arguments)) {
this.controlBusy = true;
unit = this.tapeUnit[this.unitIndex];
alarm = unit.positionBackward(blockFinished, this.boundControlFinished);
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
}
};
/**************************************/
B220MagTapeControl.prototype.positionAtEnd = function positionAtEnd(dReg, releaseProcessor) {
/* Positions the tape to the end of recorded information (i.e., when a gap
longer than inter-block gap is detected. Leaves the tape at the end of the
prior recorded block */
var alarm = false; // error result
if (this.loadCommand(dReg, releaseProcessor, positionAtEnd, arguments)) {
this.controlBusy = true;
alarm = this.tapeUnit[this.unitIndex].positionAtEnd(this.boundControlFinished);
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
}
};
/**************************************/
B220MagTapeControl.prototype.laneSelect = function laneSelect(dReg, releaseProcessor) {
/* 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
var laneNr; // lane to select (0, 1)
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);
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
}
};
/**************************************/
B220MagTapeControl.prototype.rewind = function rewind(dReg, releaseProcessor) {
/* Initiates rewind of the designated unit. Returns an alarm if the unit
does not exist or is not ready */
var alarm = false; // error result
var laneNr; // lane to select (0, 1)
var lockout; // lockout after rewind (0, 1)
if (this.loadCommand(dReg, releaseProcessor, rewind, arguments)) {
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);
setCallback(this.mnemonic, this, 50, this.controlFinished, false);
setCallback(this.mnemonic, this, 0, releaseProcessor, alarm);
}
};
/**************************************/
B220MagTapeControl.prototype.testUnitReady = function testUnitReady(dReg) {
/* Interrogates status of the designated unit. Returns true if ready */
var result = false; // return value
var ux; // internal unit index
ux = ((dReg - dReg%0x1000000000)/0x1000000000)%0x10;
ux = this.findDesignate(ux);
if (ux >= 0) {
if (this.tapeUnit[ux].ready) {
if (!this.tapeUnit[ux].busy) {
result = true;
}
}
}
return result;
};
/**************************************/
B220MagTapeControl.prototype.testUnitAtMagneticEOT = function testUnitAtMagneticEOT(dReg) {
/* Interrogates status of the designated unit. Returns true if ready and at
Magnetic-End-of-Tape */
var result = false; // return value
var ux; // internal unit index
ux = ((dReg - dReg%0x1000000000)/0x1000000000)%0x10;
ux = this.findDesignate(ux);
if (ux >= 0) {
if (this.tapeUnit[ux].ready) {
if (this.tapeUnit[ux].atEOT) {
result = true;
}
}
}
return result;
};
/**************************************/
B220MagTapeControl.prototype.clearUnit = function clearUnit() {
/* Clears the internal state of the control unit */
this.clear();
this.regMisc.update(this.MISC);
this.regC.update(this.C);
this.regT.update(this.T);
};
/**************************************/
B220MagTapeControl.prototype.shutDown = function shutDown() {
/* Shuts down the panel */
var x;
if (this.tapeUnit) {
for (x=this.tapeUnit.length-1; x>=0; --x) {
if (this.tapeUnit[x]) {
this.tapeUnit[x].shutDown();
this.tapeUnit[x] = null;
}
}
}
this.window.removeEventListener("beforeunload", B220MagTapeControl.prototype.beforeUnload);
this.window.close();
};

294
webUI/B220MagTapeDrive.css Normal file
View File

@@ -0,0 +1,294 @@
/***********************************************************************
* retro-220/webUI B220MagTapeDrive.css
************************************************************************
* Copyright (c) 2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* Burroughs 220 emulator Magnetic Tape Drive
* web interface style sheet.
************************************************************************
* 2017-07-09 P.Kimpel
* Original version, from retro-205 D205MagTapeDrive.css.
***********************************************************************/
#magTapeBody {
height: 100%;
min-height: 100%;
overflow: hidden;
padding: 0}
#MTDiv {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: 0px}
DIV.annunciator {
color: #F93;
padding-top: 4px;
padding-bottom: 4px;
text-align: center;
position: absolute}
DIV.annunciatorLit {
background-color: black}
SELECT {
text-align: center}
#RWLLamp {
top: 18px;
left: 10px;
box-shadow: 3px 3px 2px #999}
#RWLLampCaption {
top: 10px;
left: 0px;
width: 48px}
#NotWriteLamp {
top: 18px;
left: 58px;
box-shadow: 3px 3px 2px #999}
#NotWriteLampCaption {
top: 10px;
left: 48px;
width: 48px}
#NotReadyLamp {
top: 18px;
left: 106px;
box-shadow: 3px 3px 2px #999}
#NotReadyLampCaption {
top: 10px;
left: 96px;
width: 48px}
#DesignatedLamp {
top: 18px;
left: 154px;
box-shadow: 3px 3px 2px #999}
#DesignatedLampCaption {
top: 3px;
left: 144px;
width: 48px}
#TransportPowerCaption {
top: 4px;
left: 192px;
width: 96px}
#TransportOnLamp {
top: 18px;
left: 202px;
box-shadow: 3px 3px 2px #999}
#TransportOnLampCaption {
top: 10px;
left: 192px;
width: 48px}
#TransportStandbyLamp {
top: 18px;
left: 250px;
box-shadow: 3px 3px 2px #999}
#TransportStandbyLampCaption {
top: 10px;
left: 240px;
width: 48px}
#LoadBtn {
top: 64px;
left: 12px;
box-shadow: 3px 3px 2px #999}
#LoadBtnCaption {
top: 56px;
left: 0px;
width: 48px}
#UnloadBtn {
top: 64px;
left: 60px;
box-shadow: 3px 3px 2px #999}
#UnloadBtnCaption {
top: 56px;
left: 48px;
width: 48px}
#RewindBtn {
top: 64px;
left: 108px;
box-shadow: 3px 3px 2px #999}
#RewindBtnCaption {
top: 56px;
left: 96px;
width: 48px}
#TransportPowerBtnCaption {
top: 58px;
left: 192px;
width: 96px}
#TransportOnBtn {
top: 64px;
left: 204px;
box-shadow: 3px 3px 2px #999}
#TransportOnBtnCaption {
top: 56px;
left: 192px;
width: 48px}
#TransportStandbyBtn {
top: 64px;
left: 252px;
box-shadow: 3px 3px 2px #999}
#TransportStandbyBtnCaption {
top: 56px;
left: 240px;
width: 48px}
#RWLRBtn {
top: 104px;
left: 12px;
box-shadow: 3px 3px 2px #999}
#RWLRBtnCaption {
top: 96px;
left: 0px;
width: 48px}
#WriteBtn {
top: 104px;
left: 60px;
box-shadow: 3px 3px 2px #999}
#WriteBtnCaption {
top: 96px;
left: 48px;
width: 48px}
#NotWriteBtn {
top: 104px;
left: 108px;
box-shadow: 3px 3px 2px #999}
#NotWriteBtnCaption {
top: 96px;
left: 96px;
width: 48px}
#UnitDesignate {
position: absolute;
top: 106px;
left: 204px;
width: 72px;
box-shadow: 3px 3px 2px #999}
#UnitDesignateCaption {
top: 96px;
left: 192px;
width: 96px}
#MTReel {
position: absolute;
height: 48px;
visibility: hidden;
border-radius: 50%;
top: 8px;
right: 16px}
#MTUnloadedLight {
top: 60px;
right: 8px;
width: 64px}
#MTAtBOTLight {
top: 78px;
right: 8px;
width: 64px}
#MTAtEOTLight {
top: 96px;
right: 8px;
width: 64px}
#MTRewindingLight {
top: 114px;
right: 8px;
width: 64px}
#MTStatusDiv {
position: absolute;
bottom: 4px;
left: 8px;
right: 8px}
#MTFileName {
width: 100%;
font-family: DejaVuSansWeb, sans-serif;
color: black;
background-color: inherit;
border: none}
#MTReelBar {
margin-top: 4px;
width: 100%;
height: 16px;
border: 1px solid white}
#MTReelBarCaption {
position: absolute;
right: 4px;
top: 24px;
z-index: 1;
height: 12px;
color: black;
font-weight: bold}
/* Tape Load Panel */
#MTLoadFileGroup {
position: absolute;
top: 8px;
left: 8px;
right: 8px}
#MTLoadFileSelector {
border: 1px solid white;
color: white;
width: 100%}
#MTLoadFormatGroup {
position: absolute;
top: 32px;
left: 0}
#MTLoadFormatSelect {
border: 1px solid white}
#MTLoadWriteEnableCheck {
border: 1px solid white}
#MTLoadNotes {
position: absolute;
top: 60px;
width: 300px;
left: 0}
#MTLoadButtonGroup {
position: absolute;
top: 60px;
right: 0}
#MTLoadCancelBtn {
background-image: none;
background-color: #900;
height: 20px;
bottom: 0;
right: 64px}
#MTLoadOKBtn {
background-image: none;
background-color: #060;
height: 20px;
bottom: 0;
right: 0}

102
webUI/B220MagTapeDrive.html Normal file
View File

@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>220 Emulator Magnetic Tape Drive</title>
<!--
/***********************************************************************
* retro-220/webUI B220MagTapeDrive.html
************************************************************************
* Copyright (c) 2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* Burroughs 220 Magnetic Tape Drive device page.
*
* Implements the 220 magnetic tape drive storage unit peripheral.
*
************************************************************************
* 2017-07-09 P.Kimpel
* Original version, from retro-205 D205MagTapeDrive.html.
***********************************************************************/
-->
<meta name="Author" content="Paul Kimpel">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B220Common.css">
<link id=tapeDriveStyleSheet rel=stylesheet type="text/css" href="B220MagTapeDrive.css">
</head>
<body id=magTapeBody class=deviceBody>
<div id=MTDiv class=panelSurface>
<div id=RWLLampCaption class=caption>RWL</div>
<div id=NotWriteLampCaption class=caption>NOT WRITE</div>
<div id=NotReadyLampCaption class=caption>NOT READY</div>
<div id=DesignatedLampCaption class=caption>UNIT<br>DESIGNATE</div>
<div id=TransportPowerCaption class=caption>TRANSPORT POWER</div>
<div id=TransportOnLampCaption class=caption>ON</div>
<div id=TransportStandbyLampCaption class=caption>STANDBY</div>
<div id=LoadBtn class=redButton3>&nbsp;</div>
<div id=LoadBtnCaption class=caption>LOAD</div>
<div id=UnloadBtn class=blackButton3>&nbsp;</div>
<div id=UnloadBtnCaption class=caption>UNLOAD</div>
<div id=RewindBtn class=redButton3>&nbsp;</div>
<div id=RewindBtnCaption class=caption>REWIND</div>
<select id=UnitDesignate>
<option value="">LOCAL
<option value=1>1
<option value=2>2
<option value=3>3
<option value=4>4
<option value=5>5
<option value=6>6
<option value=7>7
<option value=8>8
<option value=9>9
<option value=0>10
</select>
<div id=UnitDesignateCaption class=caption>UNIT DESIGNATE</div>
<div id=RWLRBtn class=blackButton3>&nbsp;</div>
<div id=RWLRBtnCaption class=caption>RWLR</div>
<div id=WriteBtn class=redButton3>&nbsp;</div>
<div id=WriteBtnCaption class=caption>WRITE</div>
<div id=NotWriteBtn class=blackButton3>&nbsp;</div>
<div id=NotWriteBtnCaption class=caption>NOT WRITE</div>
<div id=TransportOnBtn class=redButton3>&nbsp;</div>
<div id=TransportOnBtnCaption class=caption>ON</div>
<div id=TransportStandbyBtn class=blackButton3>&nbsp;</div>
<div id=TransportStandbyBtnCaption class=caption>ST'DBY</div>
<img id=MTReel src="./resources/MagTapeReel.jpg">
<div id=MTUnloadedLight class=annunciator>UNLOADED</div>
<div id=MTAtBOTLight class=annunciator>AT BOT</div>
<div id=MTAtEOTLight class=annunciator>AT EOT</div>
<div id=MTRewindingLight class=annunciator>REWINDING</div>
<div id=MTStatusDiv>
<input id=MTFileName type=text READONLY><br>
<meter id=MTReelBar min=0 max=100 value=0 title="Tape remaining on supply reel"></meter>
<label id=MTReelBarCaption for=MTReelBar>SUPPLY REEL</label>
</div>
</div>
</body>
</html>

1899
webUI/B220MagTapeDrive.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>220 Emulator Magnetic Tape Loader</title>
<!--
/***********************************************************************
* retro-220/webUI B220MagTapeLoadPanel.html
************************************************************************
* Copyright (c) 2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* Burroughs 220 Magnetic Tape Drive Loader page.
*
* Implements a dialog to load blank tapes or tape-image files for the
* magnetic tape drive device.
*
************************************************************************
* 2017-07-09 P.Kimpel
* Original version, from retro-205 D205MagTapeLoadPanel.html.
***********************************************************************/
-->
<meta name="Author" content="Paul Kimpel">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B220Common.css">
<link id=tapeLoadStyleSheet rel=stylesheet type="text/css" href="B220MagTapeDrive.css">
</head>
<body class=deviceBody>
<div id=MTLoadFileGroup>
<input id=MTLoadFileSelector type=file size=60>
<div id=MTLoadFormatGroup>
Format
<select id=MTLoadFormatSelect>
<option value="edited" selected>(Edited tape)
<option value="10">10-word blocks
<option value="20">20-word blocks
<option value="30">30-word blocks
<option value="40">40-word blocks
<option value="50">50-word blocks
<option value="60">60-word blocks
<option value="70">70-word blocks
<option value="80">80-word blocks
<option value="90">90-word blocks
<option value="100">100-word blocks
</select>
&nbsp;&nbsp;
<input id=MTLoadWriteEnableCheck type=checkbox value="1">
<label for=MTLoadWriteEnableCheck>Write Enabled</label>
</div>
<div id=MTLoadNotes>
To load a blank tape, simply click <b>OK</b>; otherwise
select a tape-image file before clicking <b>OK</b>.
</div>
<div id=MTLoadButtonGroup>
<button id=MTLoadCancelBtn class="large redButton">Cancel</button>
&nbsp;
<button id=MTLoadOKBtn class="large greenButton">OK</button>
</div>
</div>
</body>
</html>

View File

@@ -1,5 +1,5 @@
CACHE MANIFEST
# retro-220 emulator 0.03, 2017-05-29 13:30
# retro-220 emulator 0.03a, 2017-10-19 08:45
CACHE:
../emulator/B220Processor.js
B220.css
@@ -30,13 +30,13 @@ B220ControlConsole.js
#B220DataFile.js
B220DiagMonitor.html
B220FramePaper.html
#B220MagTapeControl.css
#B220MagTapeControl.html
#B220MagTapeControl.js
#B220MagTapeDrive.css
#B220MagTapeDrive.html
#B220MagTapeDrive.js
#B220MagTapeLoadPanel.html
B220MagTapeControl.css
B220MagTapeControl.html
B220MagTapeControl.js
B220MagTapeDrive.css
B220MagTapeDrive.html
B220MagTapeDrive.js
B220MagTapeLoadPanel.html
B220PanelUtil.js
B220PaperTapePunch.css
B220PaperTapePunch.html
@@ -60,7 +60,7 @@ resources/DejaVuSans-webfont.ttf
resources/DejaVuSans-webfont.woff
resources/DejaVuSansMono-webfont.ttf
resources/DejaVuSansMono-webfont.woff
#resources/MagTapeReel.jpg
resources/MagTapeReel.jpg
resources/Organ-Switch-Down.png
resources/Organ-Switch-Up.png
resources/retro-220-Logo.png

View File

@@ -824,7 +824,6 @@ PanelRegister.prototype.drawBox = function drawBox(col, lamps, rows, leftStyle,
leftStyle and rightStyle specify the left and right borders of the box using
standard CSS border syntax. Returns the box element */
var box = document.createElement("div");
var rightBias = (rightStyle ? 1 : 0);
box.style.position = "absolute";
box.style.left = (this.xCoord(col) - (PanelRegister.hSpacing-PanelRegister.lampDiameter)/2 + 1).toString() + "px";

View File

@@ -44,7 +44,8 @@
position: absolute;
width: 24px;
left: 56px;
top: 14px}
top: 14px;
box-shadow: 3px 3px 2px #999}
#ReadyLampCaption {
width: 36px;
left: 52px;
@@ -57,7 +58,8 @@
right: 8px;
top: 18px;
color: white;
background-color: #333}
background-color: #333;
box-shadow: 3px 3px 2px #999}
#UnitDesignateKnobCaption {
width: 64px;
right: 8px;

View File

@@ -15,7 +15,7 @@
/**************************************/
function B220PaperTapePunch(mnemonic, unitIndex, config) {
/* Constructor for the Console Paper Tape Punch object */
var top = unitIndex*32 + 360;
var top = unitIndex*32 + 264;
var left = (unitIndex-1)*32;
this.config = config; // System configuration object

View File

@@ -44,7 +44,8 @@
position: absolute;
width: 24px;
left: 56px;
top: 14px}
top: 14px;
box-shadow: 3px 3px 2px #999}
#ReadyLampCaption {
width: 36px;
left: 52px;
@@ -75,7 +76,8 @@
right: 8px;
top: 18px;
color: white;
background-color: #333}
background-color: #333;
box-shadow: 3px 3px 2px #999}
#UnitDesignateKnobCaption {
width: 64px;
right: 8px;

View File

@@ -18,7 +18,7 @@
/**************************************/
function B220PaperTapeReader(mnemonic, unitIndex, config) {
/* Constructor for the PaperTapeReader object */
var top = unitIndex*32 + 360;
var top = unitIndex*32 + 264;
var left = (unitIndex-1)*32 + 250;
this.config = config; // System configuration object

View File

@@ -18,8 +18,8 @@
* minimum they use, and their precision in activating the call-back function
* once the actual delay is established varies even more. This module will use
* setTimeout() if the requested delay time is above a certain threshold, and
* a setImmediate-like mechanism (based on window.postMessage) if the requested
* delay is below that threshold.
* a setImmediate-like mechanism (based on Promise) if the requested delay is
* below that threshold.
*
* To help compensate for the fact that the call-back function may be called
* sooner than requested, and that due either to other activity or to browser
@@ -43,9 +43,9 @@
* earlier or later than the specified delay. The string "category" (which
* may be empty, null, or undefined) defines the category under which the
* average delay difference will be maintained. setCallBack returns a
* numeric token identifying the call-back event, which can be used
* with clearCallback(). Note that passing a string in lieu of a function
* object is not permitted.
* numeric token identifying the call-back event, which can be used with
* clearCallback() to cancel the callback. Note that passing a string in
* lieu of a function object is not permitted.
*
* clearCallBack(token)
*
@@ -77,6 +77,8 @@
* Original version, cloned from retro-205 emulator D205SetCallback.js.
* 2017-02-18 P.Kimpel
* Redesign yet again the delay adjustment mechanism -- from 205 project.
* 2017-10-16 P.Kimpel
* Replace window.postMessage yield mechanism with one based on Promise().
***********************************************************************/
"use strict";
@@ -89,7 +91,6 @@
var perf = global.performance; // cached window.performance object
var pool = []; // pool of reusable callback objects
var poolLength = 0; // length of active entries in pool
var secretPrefix = "retro-205.webUI." + Date.now().toString(16);
/**************************************/
function activateCallback(token) {
@@ -140,7 +141,7 @@
/* Sets up and schedules a callback for function "fcn", called with context
"context", after a delay of "delay" ms. An optional "arg" value will be passed
to "fcn". If the delay is less than "minTimeout", a setImmediate-like mechanism
based on window.postsMessage() will be used; otherwise the environment's standard
based on DOM Promise() will be used; otherwise the environment's standard
setTimeout mechanism will be used */
var adj = 0; // adjustment to delay and delayDev[]
var categoryName = (category || "NUL").toString();
@@ -213,25 +214,12 @@
thisCallback.cancelToken = global.setTimeout(activateCallback, delay, token);
} else {
thisCallback.cancelToken = 0;
global.postMessage(secretPrefix + tokenName, "*");
Promise.resolve(token).then(activateCallback);
}
return token;
}
/**************************************/
function onMessage(ev) {
/* Handler for the global.onmessage event. Activates the callback */
var payload;
if (ev.source === global) {
payload = ev.data.toString();
if (payload.substring(0, secretPrefix.length) === secretPrefix) {
activateCallback(payload.substring(secretPrefix.length));
}
}
}
/**************************************/
function getCallbackState(optionMask) {
/* Diagnostic function. Returns an object that, depending upon bits in
@@ -270,7 +258,7 @@
}
/********** Outer block of anonymous closure **********/
if (!global.setCallback && global.postMessage && !global.importScripts) {
if (!global.setCallback && !global.importScripts) {
// Attach to the prototype of global, if possible, otherwise to global itself
var attachee = global;
@@ -282,7 +270,6 @@
}
*****/
global.addEventListener("message", onMessage, false);
attachee.setCallback = setCallback;
attachee.clearCallback = clearCallback;
attachee.getCallbackState = getCallbackState;

View File

@@ -89,7 +89,6 @@
#ConsoleInputTable,
#ConsoleOutputTable,
#CardatronTable,
#MagTapeOptionsTable,
#MagTapeTable {
border-spacing: 0;
border-collapse: collapse}
@@ -100,8 +99,6 @@
#ConsoleOutputTable TD,
#CardatronTable TH,
#CardatronTable TD,
#MagTapeOptionsTable TH,
#MagTapeOptionsTable TD,
#MagTapeTable TH,
#MagTapeTable TD {
padding-left: 4px;

View File

@@ -925,19 +925,10 @@
<div class=heading>Magnetic Tape Unit Selection:</div>
<table id=MagTapeOptionsTable>
<tbody>
<tr>
<td class=center>
<input id=SuppressBMod type=checkbox value=1 checked>
<td class=center>
<label for=SuppressBMod>Suppress B-Register Modification
</table>
<table id=MagTapeTable>
<thead>
<tr>
<th>Unit<th>Type<th>Designate<th>Remote<th>Rewind-Ready<th>Not-Write
<th>Unit<th>Type<th>Designate
<tbody>
<tr>
<td class=center>A
@@ -959,12 +950,6 @@
<option value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape1Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape1RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape1NotWrite type=checkbox value=1>
<tr>
<td class=center>B
<td class=center>
@@ -985,12 +970,6 @@
<option value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape2Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape2RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape2NotWrite type=checkbox value=1>
<tr>
<td class=center>C
<td class=center>
@@ -1011,12 +990,6 @@
<option value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape3Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape3RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape3NotWrite type=checkbox value=1>
<tr>
<td class=center>D
<td class=center>
@@ -1037,12 +1010,6 @@
<option value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape4Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape4RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape4NotWrite type=checkbox value=1>
<tr>
<td class=center>E
<td class=center>
@@ -1063,12 +1030,6 @@
<option value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape5Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape5RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape5NotWrite type=checkbox value=1>
<tr>
<td class=center>F
<td class=center>
@@ -1089,12 +1050,6 @@
<option value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape6Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape6RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape6NotWrite type=checkbox value=1>
<tr>
<td class=center>G
<td class=center>
@@ -1115,12 +1070,6 @@
<option value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape7Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape7RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape7NotWrite type=checkbox value=1>
<tr>
<td class=center>H
<td class=center>
@@ -1141,12 +1090,6 @@
<option selected value=8>8
<option value=9>9
<option value=0>0
<td class=center>
<input id=MagTape8Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape8RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape8NotWrite type=checkbox value=1>
<tr>
<td class=center>I
<td class=center>
@@ -1167,12 +1110,6 @@
<option value=8>8
<option selected value=9>9
<option value=0>0
<td class=center>
<input id=MagTape9Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape9RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape9NotWrite type=checkbox value=1>
<tr>
<td class=center>J
<td class=center>
@@ -1193,12 +1130,6 @@
<option value=8>8
<option value=9>9
<option selected value=0>0
<td class=center>
<input id=MagTape10Remote type=checkbox value=1 checked>
<td class=center>
<input id=MagTape10RewindReady type=checkbox value=1 checked>
<td class=center>
<input id=MagTape10NotWrite type=checkbox value=1>
</table>
<p>&nbsp;</p>
</div>

View File

@@ -107,11 +107,11 @@ B220SystemConfig.defaultConfig = {
hasMagTape: true,
units: [
null, // unit[0] not used
{type: "MTA", designate: 0, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false},
{type: "MTA", designate: 1},
{type: "MTB", designate: 2},
{type: "NONE"},
{type: "NONE"},
{type: "NONE"},
{type: "MTD", designate: 3, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false},
{type: "MTE", designate: 4, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false},
{type: "NONE"},
{type: "NONE"},
{type: "NONE"},
@@ -371,15 +371,11 @@ B220SystemConfig.prototype.loadConfigDialog = function loadConfigDialog() {
cd.MagTape = B220SystemConfig.defaultConfig.MagTape;
}
this.$$("SuppressBMod").checked = !cd.MagTape.suppressBSwitch;
for (x=1; x<=10; ++x) {
unit = cd.MagTape.units[x];
prefix = "MagTape" + x;
this.setListValue(prefix + "Type", unit.type);
this.$$(prefix + "Designate").selectedIndex = unit.designate;
this.$$(prefix + "Remote").checked = unit.remoteSwitch;
this.$$(prefix + "RewindReady").checked = unit.rewindReadySwitch;
this.$$(prefix + "NotWrite").checked = unit.notWriteSwitch;
this.$$(prefix + "Designate").selectedIndex = unit.designate-1;
} // for x
this.$$("MessageArea").textContent = "220 System Configuration loaded.";
@@ -509,17 +505,13 @@ B220SystemConfig.prototype.saveConfigDialog = function saveConfigDialog() {
// Magnetic Tape units
cd.MagTape.hasMagTape = false;
cd.MagTape.suppressBSwitch = !this.$$("SuppressBMod").checked;
for (x=1; x<=10; ++x) {
unit = cd.MagTape.units[x];
prefix = "MagTape" + x;
e = this.$$(prefix + "Type");
unit.type = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value);
unit.designate = this.$$(prefix + "Designate").selectedIndex;
unit.remoteSwitch = this.$$(prefix + "Remote").checked;
unit.rewindReadySwitch = this.$$(prefix + "RewindReady").checked;
unit.notWriteSwitch = this.$$(prefix + "NotWrite").checked;
unit.designate = this.$$(prefix + "Designate").selectedIndex+1;
if (unit.type != "NONE") {
cd.MagTape.hasMagTape = true;
}