From a95b75bc88f0eee6e07a75d1adb62984fbe64f1b Mon Sep 17 00:00:00 2001 From: Paul Kimpel Date: Mon, 29 May 2017 14:03:42 -0700 Subject: [PATCH] Commit retro-220 version 0.03: 1. Implementation Paper Tape Reader devices and op codes. 2. Commit standard and inverse-format paper tape loaders for WINTER.PI program. 3. Fix positioning of Cardatron and TTY/Paper Tape Punch device windows. --- README.md | 4 +- emulator/B220Processor.js | 398 +++++++++++-------- software/examples/WINTER.PI.Load-Inverse.pt | 81 ++++ software/examples/WINTER.PI.Load.pt | 80 ++++ webUI/B220.html | 3 +- webUI/B220CardatronControl.js | 7 +- webUI/B220CardatronInput.js | 7 +- webUI/B220CardatronOutput.js | 5 +- webUI/B220ControlConsole.js | 62 ++- webUI/B220Manifest.appcache | 8 +- webUI/B220PaperTapePunch.css | 60 +-- webUI/B220PaperTapePunch.js | 57 ++- webUI/B220PaperTapeReader.css | 108 +++++ webUI/B220PaperTapeReader.html | 61 +++ webUI/B220PaperTapeReader.js | 412 ++++++++++++++++++++ webUI/B220SystemConfig.css | 3 + webUI/B220SystemConfig.html | 294 +++++++++++++- webUI/B220SystemConfig.js | 220 +++++++---- 18 files changed, 1555 insertions(+), 315 deletions(-) create mode 100644 software/examples/WINTER.PI.Load-Inverse.pt create mode 100644 software/examples/WINTER.PI.Load.pt create mode 100644 webUI/B220PaperTapeReader.css create mode 100644 webUI/B220PaperTapeReader.html create mode 100644 webUI/B220PaperTapeReader.js diff --git a/README.md b/README.md index 5e663ee..c9ce286 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ The contents of this project are licensed under the [MIT License](http://www.ope | Related Sites | URL | | ------------- | ----- | -| Emulator hosting site | http://www.phkimpel.us/ElectroData/220/ | +| Emulator hosting site | http://www.phkimpel.us/Burroughs-220/ | | Burroughs 205/220 blog | http://datatron.blogspot.com | -| Datatron 205 site | http://www.phkimpel.us/ElectroData/205/ | +| Datatron 205 site | http://www.phkimpel.us/ElectroData-205/ | | Documents at bitsavers | http://bitsavers.org/pdf/burroughs/electrodata/220/ | diff --git a/emulator/B220Processor.js b/emulator/B220Processor.js index 9ff9797..30d539f 100644 --- a/emulator/B220Processor.js +++ b/emulator/B220Processor.js @@ -237,9 +237,9 @@ function B220Processor(config, devices) { this.boundConsoleOutputSign = B220Processor.bindMethod(this, B220Processor.prototype.consoleOutputSign); this.boundConsoleOutputChar = B220Processor.bindMethod(this, B220Processor.prototype.consoleOutputChar); this.boundConsoleOutputFinished = B220Processor.bindMethod(this, B220Processor.prototype.consoleOutputFinished); - this.boundConsoleInputDigit = B220Processor.bindMethod(this, B220Processor.prototype.consoleInputDigit); - this.boundConsoleReceiveDigit = B220Processor.bindMethod(this, B220Processor.prototype.consoleReceiveDigit); - this.boundConsoleReceiveSingleDigit = B220Processor.bindMethod(this, B220Processor.prototype.consoleReceiveSingleDigit); + this.boundConsoleInputReceiveChar = B220Processor.bindMethod(this, B220Processor.prototype.consoleInputReceiveChar); + this.boundConsoleInputInitiateNormal = B220Processor.bindMethod(this, B220Processor.prototype.consoleInputInitiateNormal); + this.boundConsoleInputInitiateInverse = B220Processor.bindMethod(this, B220Processor.prototype.consoleInputInitiateInverse); this.boundCardatronOutputWord= B220Processor.bindMethod(this, B220Processor.prototype.cardatronOutputWord); this.boundCardatronOutputFinished = B220Processor.bindMethod(this, B220Processor.prototype.cardatronOutputFinished); @@ -260,7 +260,7 @@ function B220Processor(config, devices) { * Global Constants * ***********************************************************************/ -B220Processor.version = "0.02"; +B220Processor.version = "0.03"; B220Processor.tick = 1000/200000; // milliseconds per clock cycle (200KHz) B220Processor.cyclesPerMilli = 1/B220Processor.tick; @@ -2470,8 +2470,7 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar this.CADDR = this.C.value%0x10000; printChar(0x35, this.boundConsoleOutputSign); } - } else if (this.PZT.value) { - // Output alphabetically + } else if (this.PZT.value) { // Output alphabetically 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 @@ -2483,8 +2482,7 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar this.EWT.set(1); } printChar(d, this.boundConsoleOutputChar); - } else { - // Output numerically + } else { // Output numerically if (this.DPT.value && !this.LEADINGZEROESSW) { // decimal point may be needed d = this.CCONTROL >>> 12; @@ -2529,130 +2527,191 @@ B220Processor.prototype.consoleOutputFinished = function consoleOutputFinished() }; /**************************************/ -B220Processor.prototype.consoleInputDigit = function consoleInputDigit() { - // Solicits the next input digit from the Control Console */ +B220Processor.prototype.consoleInputFinishWord = function consoleInputFinishWord(result) { + /* Finishes the receipt of a word from the Console paper tape reader and + either stores it in memory or shunts it to the C register for execution. + Updates the C register as necessary and decides whether to initiate receipt + of another word */ + var d; + var w; - this.togTF = 0; // for display only, reset finish pulse - this.execTime -= performance.now()*B220Processor.wordsPerMilli; // mark time during I/O - this.console.readDigit(this.boundConsoleReceiveDigit); -}; + if (this.sDigit) { // decrement word count + d = this.bcdAdd(this.CCONTROL, 0x990, 3); + this.CCONTROL += d - this.CCONTROL%0x1000; + this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR); + } -/**************************************/ -B220Processor.prototype.consoleReceiveDigit = function consoleReceiveDigit(digit) { - /* Handles an input digit coming from the Control Console keyboard or - paper-tape reader. Negative values indicate a finish pulse; otherwise - the digit is data read from the device. Data digits are rotated into - the D register; finish pulses are handled according to the sign digit - in the D register */ - var sign; // register sign digit - var word; // register word less sign + if (this.COP == 0x05) { // read inverse: permute the sign digit + d = this.D.value%0x10; + w = (this.D.value - d)/0x10; + this.D.set(w + d*0x10000000000); + if (d == 2) { // alphanumeric translation is invalid for inverse mode + this.setPaperTapeCheck(1); + this.ioComplete(true); + return; // >>> ALARM ERROR EXIT <<< + } + } else { // sign digit in normal position + w = this.D.value%0x10000000000; + d = (this.D.value - w)/0x10000000000; + } - this.execTime += performance.now()*B220Processor.wordsPerMilli; // restore time after I/O - if (digit >= 0) { - this.togTC1 = 1-this.togTC1; // for display only - this.togTC2 = 1-this.togTC2; // for display only - this.D.set((this.D.value % 0x10000000000)*0x10 + digit); - this.consoleInputDigit(); - } else { - this.togTF = 1; - this.togTC1 = this.togTC2 = 0; // for display only - word = this.D.value%0x10000000000; - sign = (this.D.value - word)/0x10000000000; // get D-sign - - if (sign & 0x04) { - // D-sign is 4, 5, 6, 7: execute a "tape control" command - this.execTime += 2; - this.togTF = 0; // for display only - this.togSTART = 1-((sign >>> 1)%2); // whether to continue in input mode - this.setTimingToggle(0); // Execute mode - this.togCOUNT = 1; - this.togBTOAIN = 0; - this.togADDAB = 1; // for display only - this.togADDER = 1; // for display only - this.togDPCTR = 1; // for display only - this.togCLEAR = 1-(sign%2); - this.togSIGN = ((this.A.value - this.A.value%0x10000000000)/0x10000000000)%2; // display only - sign &= 0x08; - - // Increment the destination address (except on the first word) - this.SHIFTCONTROL = 0x01; // for display only - this.SHIFT = 0x13; // for display only - if (this.togCOUNT) { - this.CCONTROL = this.bcdAdd(this.CADDR, 1, 4); - } - - this.CCONTROL = (this.D.value - word%0x1000000)/0x1000000; - this.rDigit = (this.CCONTROL >>> 8) & 0x0F; - // do not set this.selectedUnit from the word -- keep the same unit - - // Shift D5-D10 into C1-C6, modify by B as necessary, and execute - this.D.set(sign*0x100000 + (word - word%0x1000000)/0x1000000); - if (this.togCLEAR) { - word = this.bcdAdd(word%0x1000000, 0, 11); - } else { - word = this.bcdAdd(word%0x1000000, this.B.value, 11) % 0x1000000; - } - this.SHIFT = 0x19; // for display only - this.C.set(word*0x10000 + this.CCONTROL); // put C back together - this.CADDR = word % 0x10000; - this.COP = (word - this.CADDR)/0x10000; - this.execute(); - } else { - // D-sign is 0, 1, 2, 3: store word, possibly modified by B - this.execTime += 3; - this.setTimingToggle(1); // Fetch mode - this.togCOUNT = this.togBTOAIN; - this.togBTOAIN = 1; - this.togADDAB = 1; // for display only - this.togADDER = 1; // for display only - this.togDPCTR = 1; // for display only - this.togCLEAR = 1-((sign >>> 1)%2); - this.togSIGN = sign%2; - - // Increment the destination address (except on the first word) - this.SHIFTCONTROL = 0x01; // for display only - this.SHIFT = 0x15; // for display only - if (this.togCOUNT) { - this.CADDR = this.bcdAdd(this.CADDR, 1, 4); - } - this.CCONTROL = this.CADDR; - this.C.set((this.COP*0x10000 + this.CADDR)*0x10000 + this.CCONTROL); - - // Modify the word by B as necessary and store it - this.D.set((sign & 0x0C)*0x10000000000 + word); - if (this.togCLEAR) { - this.A.set(this.bcdAdd(this.D.value, 0, 11)); - } else { - this.A.set(this.bcdAdd(this.D.value, this.B.value, 11)); - } + if (this.rDigit & d & 0x08) { // B-modify word before storing + this.D.set(w + (d&0x07)*0x10000000000); + this.IB.set(this.D.value - w%0x10000 + this.bcdAdd(w, this.B.value, 4)); + this.C10.set(0); + } else { // store word as-is + this.IB.set(this.D.value); + } + if (this.rDigit == 1 && (d & 0x0E) == 0x06) { // control word to C register + this.ioComplete(false); // terminate I/O but do not restart Processor yet + this.fetch(true); // set up to execute control word + // Schedule the Processor to give the reader a chance to finish its operation. + setCallback(this.mnemonic, this, 0, this.schedule); + } else { // just store the word + this.writeMemory(); + if (this.MET.value) { // memory address error + this.ioComplete(true); + } else if (this.sDigit && this.CCONTROL%0x1000 < 0x10) { // word count exhausted + this.ioComplete(true); + } else { // initiate input of another word this.D.set(0); - word = this.A.value % 0x10000000000; - sign = (((this.A.value - word)/0x10000000000) & 0x0E) | (sign%2); - this.A.set(sign*0x10000000000 + word); - this.writeMemory(this.boundConsoleInputDigit, false); + if (this.COP == 0x05) { + d = this.console.inputUnitSelect(this.selectedUnit, this.boundConsoleInputInitiateInverse); + } else { + d = this.console.inputUnitSelect(this.selectedUnit, this.boundConsoleInputInitiateNormal); + } + if (d < 0) { // no unit available -- set alarm and quit + this.setPaperTapeCheck(1); + this.ioComplete(true); + } } } }; /**************************************/ -B220Processor.prototype.consoleReceiveSingleDigit = function consoleReceiveSingleDigit(digit) { - /* Handles a single input digit coming from the Control Console keyboard - or paper-tape reader, as in the case of Digit Add (10). Negative values - indicate a finish pulse, which is ignored, and causes another digit to be - solicited from the Console; otherwise the digit is (virtually) moved to - the D register and then (actually) added to the A register */ +B220Processor.prototype.consoleInputInitiateNormal = function consoleInputInitiateNormal(result) { + /* Initiates the receipt into a word of characters from the Console tape + reader in normal (sign-first) mode. Increments the C register operand address, + rotates the sign digit into the D register, and determines whether the word + should be translated numerically or alphanumerically */ + var code = result.code; + + this.clockIn(); + if (this.AST.value) { // if false, we've probably been cleared + this.E.set(this.CADDR); + this.C.inc(); + this.CADDR = this.C.value%0x10000; + + switch (code) { + case 0x17: // invalid character/parity error + this.setPaperTapeCheck(1); + this.ioComplete(true); + break; + case 0x35: // end-of-word + this.consoleInputFinishWord(result); + break; + case 0x82: // sign=2, set alpha translation + this.PZT.set(!this.HOLDPZTZEROSW); + this.D.set(2); + result.readChar(this.boundConsoleInputReceiveChar); + break; + default: // anything else, set numeric translation + this.PZT.set(0); + if ((code & 0xF0) == 0x80) {// it's a numeric sign -- okay + this.D.set(code%0x10); + result.readChar(this.boundConsoleInputReceiveChar); + } else if (code == 0) { // we'll take a space as a zero + this.D.set(0); + result.readChar(this.boundConsoleInputReceiveChar); + } else { // sign is non-numeric -- invalid + this.D.set(0); + this.setPaperTapeCheck(1); + this.ioComplete(true); + } + break; + } // switch code + } +}; + +/**************************************/ +B220Processor.prototype.consoleInputInitiateInverse = function consoleInputInitiateInverse(result) { + /* Initiates the receipt into a word of characters from the Console tape + reader in inverse (sign-last) mode. Increments the C register operand address, + rotates the sign digit into the D register, and sets PZT for numeric translation */ + var code = result.code; + + this.clockIn(); + if (this.AST.value) { // if false, we've probably been cleared + this.E.set(this.CADDR); + this.C.inc(); + this.CADDR = this.C.value%0x10000; + + switch (code) { + case 0x17: // invalid character/parity error + this.setPaperTapeCheck(1); + this.ioComplete(true); + break; + case 0x35: // end-of-word + this.consoleInputFinishWord(result); + break; + default: // anything else, set numeric translation + this.PZT.set(0); + if ((code & 0xF0) == 0x80) {// it's a numeric code -- okay + this.D.set(code%0x10); + result.readChar(this.boundConsoleInputReceiveChar); + } else if (code == 0) { // we'll take a space as a zero + this.D.set(0); + result.readChar(this.boundConsoleInputReceiveChar); + } else { // digit is non-numeric -- invalid + this.D.set(0); + this.setPaperTapeCheck(1); + this.ioComplete(true); + } + break; + } // switch code + } +}; + +/**************************************/ +B220Processor.prototype.consoleInputReceiveChar = function consoleInputReceiveChar(result) { + /* Handles an input character coming from the Console paper-tape reader. + result.code is the B220 character code read from the device. result.readChar + is the callback function to request the next character. Data digits are + rotated into the D register; end-of-word (0x35) codes are handled according + to the sign digit in the D register */ + var code = result.code; // character received var sign; // register sign digit var word; // register word less sign - if (digit < 0) { // ignore finish pulse and just re-solicit - this.console.readDigit(this.boundConsoleReceiveSingleDigit); - } else { - this.execTime += performance.now()*B220Processor.wordsPerMilli + 4; // restore time after I/O - this.togSTART = 0; - this.D.set(digit); - this.integerAdd(false, false); - this.schedule(); + this.clockIn(); + if (this.AST.value) { // if false, we've probably been cleared + switch (code) { + case 0x17: // invalid character/parity error + this.setPaperTapeCheck(1); + this.ioComplete(true); + break; + case 0x35: // end-of-word + this.consoleInputFinishWord(result); + break; + default: // anything else, accumulate digits in word + if (this.PZT.value) { // alphanumeric translation + this.D.set((this.D.value % 0x1000000000)*0x100 + code); + result.readChar(this.boundConsoleInputReceiveChar); + } else { // numeric translation + if ((code & 0xF0) == 0x80) {// it's a numeric code -- okay + this.D.set((this.D.value % 0x10000000000)*0x10 + code%0x10); + result.readChar(this.boundConsoleInputReceiveChar); + } else if (code == 0) { // we'll take a space as a zero + this.D.set((this.D.value % 0x10000000000)*0x10); + result.readChar(this.boundConsoleInputReceiveChar); + } else { // code is non-numeric -- invalid + this.setPaperTapeCheck(1); + this.ioComplete(true); + } + } + break; + } // switch code } }; @@ -3072,18 +3131,60 @@ B220Processor.prototype.execute = function execute() { break; case 0x03: //--------------------- PRD Paper tape read - this.setProgramCheck(1); - this.operationComplete(); + this.opTime = 0.185; // just a guess... + d = this.CCONTROL >>> 12; // get unit number + if (d == 0) { + d = 10; // xlate unit 0 to unit 10 + } + + this.selectedUnit = d; + this.rDigit = this.CCONTROL & 0x0F; + this.sDigit = 1; // use word count in C (32) + this.D.set(0); + this.ioInitiate(); + d = this.console.inputUnitSelect(this.selectedUnit, this.boundConsoleInputInitiateNormal); + if (d < 0) { // no unit available -- set alarm and quit + this.setPaperTapeCheck(1); + this.ioComplete(true); + } break; case 0x04: //--------------------- PRB Paper tape read, branch - this.setProgramCheck(1); - this.operationComplete(); + this.opTime = 0.185; // just a guess... + d = this.CCONTROL >>> 12; // get unit number + if (d == 0) { + d = 10; // xlate unit 0 to unit 10 + } + + this.selectedUnit = d; + this.rDigit = (this.CCONTROL & 0x0E) | 1; // force recognition of control words + this.sDigit = 0; // do not use word count in C (32) + this.D.set(0); + this.ioInitiate(); + d = this.console.inputUnitSelect(this.selectedUnit, this.boundConsoleInputInitiateNormal); + if (d < 0) { // no unit available -- set alarm and quit + this.setPaperTapeCheck(1); + this.ioComplete(true); + } break; case 0x05: //--------------------- PRI Paper tape read, inverse format - this.setProgramCheck(1); - this.operationComplete(); + this.opTime = 0.185; // just a guess... + d = this.CCONTROL >>> 12; // get unit number + if (d == 0) { + d = 10; // xlate unit 0 to unit 10 + } + + this.selectedUnit = d; + this.rDigit = (this.CCONTROL & 0x0E) | 1; // force recognition of control words + this.sDigit = 1; // use word count in C (32) + this.D.set(0); + this.ioInitiate(); + d = this.console.inputUnitSelect(this.selectedUnit, this.boundConsoleInputInitiateInverse); + if (d < 0) { // no unit available -- set alarm and quit + this.setPaperTapeCheck(1); + this.ioComplete(true); + } break; case 0x06: //--------------------- PWR Paper tape write @@ -3093,6 +3194,7 @@ B220Processor.prototype.execute = function execute() { d = 10; // xlate unit 0 to unit 10 } + this.selectedUnit = d; this.ioInitiate(); d = this.console.outputUnitSelect(d, this.boundConsoleOutputSign); if (d < 0) { // no unit available -- set alarm and quit @@ -3107,6 +3209,7 @@ B220Processor.prototype.execute = function execute() { d = 10; // xlate unit 0 to unit 10 } + this.selectedUnit = d; d = this.console.outputUnitSelect(d, B220Processor.emptyFunction); if (d < 0) { // if not ready, continue in sequence this.opTime = 0.015; @@ -3762,11 +3865,6 @@ B220Processor.prototype.execute = function execute() { switch (-1) { - case 0x00: //---------------- PTR Paper-tape/keyboard read - this.D.set(0); - this.togSTART = 1; - this.consoleInputDigit(); - break; case 0x40: //---------------- MTR Magnetic Tape Read if (!this.magTape) { @@ -3823,46 +3921,6 @@ B220Processor.prototype.execute = function execute() { } } break; - - case 0x54: //---------------- CDW Card Write (Cardatron) - if (!this.cardatron) { - //this.schedule(); - } else { - this.tog3IO = 1; - this.kDigit = (this.CCONTROL >>> 8) & 0x0F; - this.selectedUnit = (this.CCONTROL >>> 4) & 0x07; - this.SHIFT = 0x19; // start at beginning of a word - this.execTime -= performance.now()*B220Processor.wordsPerMilli; // mark time during I/O - this.cardatron.outputInitiate(this.selectedUnit, this.kDigit, (this.CCONTROL >>> 12) & 0x0F, - this.boundCardatronOutputWord, this.boundCardatronOutputFinished); - } - break; - - case 0x55: //---------------- CDWI Card Write Interrogate - this.selectedUnit = (this.CCONTROL >>> 4) & 0x07; - if (this.cardatron && this.cardatron.outputReadyInterrogate(this.selectedUnit)) { - this.R.set(this.CCONTROL*0x1000000); - this.setTimingToggle(0); // stay in Execute - this.OFT.set(1); // set overflow - this.COP = 0x28; // make into a CC - this.C.set((this.COP*0x10000 + this.CADDR)*0x10000 + this.CCONTROL); - } - break; - - case 0x58: //---------------- CDWF Card Write Format - if (!this.cardatron) { - //this.schedule(); - } else { - this.tog3IO = 1; - this.kDigit = (this.CCONTROL >>> 8) & 0x0F; - this.selectedUnit = (this.CCONTROL >>> 4) & 0x07; - this.SHIFT = 0x19; // start at beginning of a word - this.execTime -= performance.now()*B220Processor.wordsPerMilli; // mark time during I/O - this.cardatron.outputFormatInitiate(this.selectedUnit, this.kDigit, - this.boundCardatronOutputWord, this.boundCardatronOutputFinished); - } - break; - default: //---------------- (unimplemented instruction -- alarm) break; } // switch this.COP diff --git a/software/examples/WINTER.PI.Load-Inverse.pt b/software/examples/WINTER.PI.Load-Inverse.pt new file mode 100644 index 0000000..30db49a --- /dev/null +++ b/software/examples/WINTER.PI.Load-Inverse.pt @@ -0,0 +1,81 @@ +61000050500 +1005710 +4005650 +1005630 +14800100 +1505750 +4205650 +00004010001 +12105060 +1005650 +1405740 +14005680 +3705620 +4605660 +1005650 +4005640 +4205640 +00001010001 +1405630 +14900100 +1205660 +4005660 +14800100 +12705680 +1505680 +00014010001 +4005660 +12705680 +1005640 +1305730 +4005640 +3605340 +1405660 +14005660 +12105160 +142705650 +1005660 +14800100 +1505630 +1205670 +14005670 +14800030 +1205760 +4900010 +14900010 +1205760 +4900010 +14900010 +1205760 +4900010 +14900010 +1205760 +4900020 +24300000 +4005640 +100905640 +4052605690 +1005690 +1805700 +13405080 +100905770 +4605690 +3005080 +75570 +100000 +0 +0 +0 +0 +0 +0 +500 +28000 +0 +10 +20 +50 +800 +10000405776 +20202021616 +60000300500 diff --git a/software/examples/WINTER.PI.Load.pt b/software/examples/WINTER.PI.Load.pt new file mode 100644 index 0000000..a434d21 --- /dev/null +++ b/software/examples/WINTER.PI.Load.pt @@ -0,0 +1,80 @@ +61000040500 +00000100571 +00000400565 +00000100563 +00001480010 +00000150575 +00000420565 +10000401000 +00001210506 +00000100565 +00000140574 +00001400568 +00000370562 +00000460566 +00000100565 +00000400564 +00000420564 +10000101000 +00000140563 +00001490010 +00000120566 +00000400566 +00001480010 +00001270568 +00000150568 +10001401000 +00000400566 +00001270568 +00000100564 +00000130573 +00000400564 +00000360534 +00000140566 +00001400566 +00001210516 +00014270565 +00000100566 +00001480010 +00000150563 +00000120567 +00001400567 +00001480003 +00000120576 +00000490001 +00001490001 +00000120576 +00000490001 +00001490001 +00000120576 +00000490001 +00001490001 +00000120576 +00000490002 +00002430000 +00000400564 +00010090564 +00405260569 +00000100569 +00000180570 +00001340508 +00010090577 +00000460569 +00000300508 +00000007557 +00000010000 +00000000000 +00000000000 +00000000000 +00000000000 +00000000000 +00000000000 +00000000050 +00000002800 +00000000000 +00000000001 +00000000002 +00000000005 +00000000080 +2___|| +60000300500 diff --git a/webUI/B220.html b/webUI/B220.html index a278847..8e08fd4 100644 --- a/webUI/B220.html +++ b/webUI/B220.html @@ -38,13 +38,12 @@ - - --> + diff --git a/webUI/B220CardatronControl.js b/webUI/B220CardatronControl.js index 6639fce..aa48b4b 100644 --- a/webUI/B220CardatronControl.js +++ b/webUI/B220CardatronControl.js @@ -15,7 +15,7 @@ /**************************************/ function B220CardatronControl(p) { /* Constructor for the CardatronControl object */ - var left = 660; // left window margin + var left = 600; // left window margin var u; // unit config object var x; // unit index @@ -27,7 +27,8 @@ function B220CardatronControl(p) { this.doc = null; this.window = window.open("../webUI/B220CardatronControl.html", this.mnemonic, - "location=no,scrollbars=no,resizable,width=140,height=140,top=0,left=" + left); + "location=no,scrollbars=no,resizable,width=140,height=140,left=" + left + + ",top=" + (screen.availHeight-140)); this.window.addEventListener("load", B220Util.bindMethod(this, B220CardatronControl.prototype.cardatronOnLoad)); @@ -168,6 +169,8 @@ B220CardatronControl.prototype.cardatronOnLoad = function cardatronOnLoad() { B220Util.bindMethod(this, B220CardatronControl.prototype.ClearBtn_onClick)); this.clear(); + + this.window.moveTo(this.window.screenX, screen.availHeight - this.window.outerHeight); }; /**************************************/ diff --git a/webUI/B220CardatronInput.js b/webUI/B220CardatronInput.js index 8956a4e..96e8424 100644 --- a/webUI/B220CardatronInput.js +++ b/webUI/B220CardatronInput.js @@ -65,7 +65,8 @@ function B220CardatronInput(mnemonic, unitIndex, config) { this.formatSelectList = null; this.window = window.open("../webUI/B220CardatronInput.html", mnemonic, "location=no,scrollbars,resizable,width=" + w + ",height=" + h + - ",left=" + (unitIndex*24) + ",top=" + (unitIndex*24)); + ",left=" + ((unitIndex-1)*32) + + ",top=" + (screen.availHeight - h - (unitIndex-1)*32)); this.window.addEventListener("load", B220Util.bindMethod(this, B220CardatronInput.prototype.readerOnLoad), false); } @@ -522,7 +523,7 @@ B220CardatronInput.prototype.finishCardRead = function finishCardRead() { c = card.charCodeAt(col); // translate char to buffer code if (c < 0x80) { c = this.cardFilter[c]; - } else if (c == 0xA4) { // the "lozenge" ("¤") + } else if (c == 0xA4) { // the "lozenge" ("¤") c = this.cardFilter[0x3C]; // use the code for "<" } else { c = 0; @@ -632,6 +633,8 @@ B220CardatronInput.prototype.readerOnLoad = function readerOnLoad() { this.window.resizeBy(de.scrollWidth - this.window.innerWidth + 4, // kludge for right-padding/margin de.scrollHeight - this.window.innerHeight); + + this.window.moveTo(0, screen.availHeight - this.window.outerHeight - (this.unitIndex-1)*32); }; /**************************************/ diff --git a/webUI/B220CardatronOutput.js b/webUI/B220CardatronOutput.js index b0fd032..3bd8dd3 100644 --- a/webUI/B220CardatronOutput.js +++ b/webUI/B220CardatronOutput.js @@ -68,7 +68,7 @@ function B220CardatronOutput(mnemonic, unitIndex, config) { this.window = window.open("../webUI/B220CardatronOutput.html", mnemonic, "location=no,scrollbars,resizable,width=" + w + ",height=" + h + ",left=" + (screen.availWidth - w) + - ",top=" + (screen.availHeight - h - (unitIndex-1)*24)); + ",top=" + (screen.availHeight - h - (unitIndex-3)*32)); this.window.addEventListener("load", B220Util.bindMethod(this, B220CardatronOutput.prototype.deviceOnLoad), false); } @@ -786,6 +786,9 @@ B220CardatronOutput.prototype.deviceOnLoad = function deviceOnLoad() { this.$$("COGreenbarCheck").addEventListener("click", B220Util.bindMethod(this, B220CardatronOutput.prototype.COGreenbarCheck_onClick), false); } + + this.window.moveTo(screen.availWidth - this.window.outerWidth, + screen.availHeight - this.window.outerHeight - (7-this.unitIndex)*32); }; /**************************************/ diff --git a/webUI/B220ControlConsole.js b/webUI/B220ControlConsole.js index d2a5f62..641278b 100644 --- a/webUI/B220ControlConsole.js +++ b/webUI/B220ControlConsole.js @@ -18,6 +18,7 @@ function B220ControlConsole(p, systemShutdown) { var h = 600; var w = 1064; var mnemonic = "ControlConsole"; + var inputConfig = p.config.getNode("ConsoleInput"); var outputConfig = p.config.getNode("ConsoleOutput"); var u; var x; @@ -36,8 +37,34 @@ function B220ControlConsole(p, systemShutdown) { this.boundResetTimer = B220Util.bindMethod(this, B220ControlConsole.prototype.resetTimer); this.boundUpdatePanel = B220Util.bindMethod(this, B220ControlConsole.prototype.updatePanel); + // Configure the console input unit objects. These are paper-tape readers. + this.inputUnit = [ + null, // unit[0] not used + null, // 1=unit A + null, // 2=unit B + null, // 3=unit C + null, // 4=unit D + null, // 5=unit E + null, // 6=unit F + null, // 7=unit G + null, // 8=unit H + null, // 9=unit I + null]; //10=unit J + + for (x=1; x + + + +retro-220 Emulator Paper Tape Reader + + + + + + + + + + +
+
REMOTE
+
LOCAL
+ +
READY
+ +
HI
+
LOW
+
SPEED
+ +
UNIT DESIGNATE
+ + + + + +
+ + + \ No newline at end of file diff --git a/webUI/B220PaperTapeReader.js b/webUI/B220PaperTapeReader.js new file mode 100644 index 0000000..ec6ba5c --- /dev/null +++ b/webUI/B220PaperTapeReader.js @@ -0,0 +1,412 @@ +/*********************************************************************** +* retro-220/webUI B220PaperTapeReader.js +************************************************************************ +* Copyright (c) 2017, Paul Kimpel. +* Licensed under the MIT License, see +* http://www.opensource.org/licenses/mit-license.php +************************************************************************ +* Burroughs 220 Paper Tape Reader module. +* +* Defines the paper tape input devices. +* +************************************************************************ +* 2017-05-27 P.Kimpel +* Original version, from retro-205 D205ConsoleInput.js. +***********************************************************************/ +"use strict"; + +/**************************************/ +function B220PaperTapeReader(mnemonic, unitIndex, config) { + /* Constructor for the PaperTapeReader object */ + var top = unitIndex*32 + 360; + var left = (unitIndex-1)*32 + 250; + + this.config = config; // System configuration object + this.mnemonic = mnemonic; // Unit mnemonic + this.unitIndex = unitIndex; // Unit index into console output units + this.inTimer = 0; // input setCallback() token + + this.charPeriod = B220PaperTapeReader.highSpeedPeriod; + // paper-tape reader speed [ms/char] + this.nextCharTime = 0; // next time a character can be read + this.unitMask = 0; // unit selection mask + + this.boundFlipSwitch = B220Util.bindMethod(this, B220PaperTapeReader.prototype.flipSwitch); + this.boundReadTapeChar = B220Util.bindMethod(this, B220PaperTapeReader.prototype.readTapeChar); + + this.readResult = { // object passed back to Processor for each read + code: 0, + readChar: this.boundReadTapeChar + }; + + this.clear(); + + // Create the reader window and onload event + this.doc = null; + this.tapeSupplyBar = null; + this.tapeView = null; + this.window = window.open("../webUI/B220PaperTapeReader.html", mnemonic, + "location=no,scrollbars=no,resizable,width=420,height=160,left=" + left + ",top=" + top); + this.window.addEventListener("load", + B220Util.bindMethod(this, B220PaperTapeReader.prototype.readerOnload), false); +} + +/**************************************/ +B220PaperTapeReader.offSwitchImage = "./resources/ToggleDown.png"; +B220PaperTapeReader.onSwitchImage = "./resources/ToggleUp.png"; + +B220PaperTapeReader.lowSpeedPeriod = 1000/500; + // low reader speed: 500 cps +B220PaperTapeReader.highSpeedPeriod = 1000/1000; + // high reader speed: 1000 cps +B220PaperTapeReader.startupTime = 5; // reader start-up delay, ms +B220PaperTapeReader.idleTime = 50; // idle time before reader requires start-up delay, ms + +// Translate ANSI character codes to B220 charater codes. + // Note that ANSI new-line sequences are used for end-of-word characters, + // so "|" translates to B220 carriage-return (16). To avoid space-expansion + // of tabs, "~" translates to tab (26). "_" translates to the "blank" code (02). + // "^" translates to form-feed (15). +B220PaperTapeReader.xlate220 = [ + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x16, 0x17, 0x15, 0x16, 0x17, 0x17, // 00-0F + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // 10-1F + 0x00, 0x17, 0x17, 0x33, 0x13, 0x24, 0x10, 0x34, 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, // 20-2F + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x17, 0x13, 0x04, 0x33, 0x17, 0x17, // 30-3F + 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, // 40-4F + 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x17, 0x17, 0x17, 0x15, 0x02, // 50-5F + 0x17, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, // 60-6F + 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x17, 0x16, 0x17, 0x26, 0x17, // 70-7F + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // 80-8F + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // 90-9F + 0x17, 0x17, 0x17, 0x17, 0x04, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // A0-AF + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // B0-BF + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // C0-CF + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // D0-DF + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, // E0-EF + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17];// F0-FF + +/**************************************/ +B220PaperTapeReader.prototype.clear = function clear() { + /* Initializes (and if necessary, creates) the reader unit state */ + + this.ready = false; // a tape has been loaded into the reader + this.busy = false; // a request for a digit is outstanding + this.pendingReceiver = null; // stashed digit-receiver function + + this.buffer = ""; // reader input buffer (paper-tape reel) + this.bufLength = 0; // current input buffer length (characters) + this.bufIndex = 0; // 0-relative offset to next character to be read +}; + +/**************************************/ +B220PaperTapeReader.prototype.$$ = function $$(e) { + return this.doc.getElementById(e); +}; + +/**************************************/ +B220PaperTapeReader.prototype.PRTapeSupplyBar_onclick = function PRTapeSupplyBar_onclick(ev) { + /* Handle the click event for the "input hopper" meter bar */ + + if (!this.ready) { + if (this.window.confirm((this.bufLength-this.bufIndex).toString() + " of " + this.bufLength.toString() + + " characters remaining to read.\nDo you want to clear the reader input?")) { + this.tapeView.value = ""; + this.setReaderEmpty(); + } + } +}; + +/**************************************/ +B220PaperTapeReader.prototype.fileSelector_onChange = function fileSelector_onChange(ev) { + /* Handle the onchange event when files are selected. For each + file, load it and add it to the input buffer of the reader */ + var tape; + var f = ev.target.files; + var that = this; + var x; + + function fileLoader_onLoad(ev) { + /* Handle the onload event for a Text FileReader */ + + if (that.bufIndex >= that.bufLength) { + that.buffer = ev.target.result; + } else { + switch (that.buffer.charAt(that.buffer.length-1)) { + case "\r": + case "\n": + break; // do nothing -- the last word has a delimiter + default: + that.buffer += "\n"; // so the next tape starts on a new line + break; + } + that.buffer = that.buffer.substring(that.bufIndex) + ev.target.result; + } + + that.bufIndex = 0; + that.bufLength = that.buffer.length; + that.$$("PRTapeSupplyBar").value = that.bufLength; + that.$$("PRTapeSupplyBar").max = that.bufLength; + that.setReaderReady(true); + if (that.busy && that.ready) { // reinitiate the pending read + that.readTapeChar(that.pendingReceiver); + that.receiver = null; + } + } + + for (x=f.length-1; x>=0; x--) { + tape = new FileReader(); + tape.onload = fileLoader_onLoad; + tape.readAsText(f[x]); + } +}; + +/**************************************/ +B220PaperTapeReader.prototype.setReaderReady = function setReaderReady(ready) { + /* Sets the reader to a ready or not-ready status */ + + this.ready = ready && this.remoteSwitch.state && (this.bufIndex < this.bufLength); + this.readyLamp.set(this.ready ? 1 : 0); +}; + +/**************************************/ +B220PaperTapeReader.prototype.setReaderEmpty = function setReaderEmpty() { + /* Sets the reader to a not-ready status and empties the buffer */ + + this.setReaderReady(false); + this.tapeSupplyBar.value = 0; + this.buffer = ""; // discard the input buffer + this.bufLength = 0; + this.bufIndex = 0; + this.fileSelector.value = null; // reset the control so the same file can be reloaded +}; + +/**************************************/ +B220PaperTapeReader.prototype.beforeUnload = function beforeUnload(ev) { + var msg = "Closing this window will make the device unusable.\n" + + "Suggest you stay on the page and minimize this window instead"; + + ev.preventDefault(); + ev.returnValue = msg; + return msg; +}; + + +/**************************************/ +B220PaperTapeReader.prototype.flipSwitch = function flipSwitch(ev) { + /* Handler for switch clicks */ + var id = ev.target.id; + var prefs = this.config.getNode("ConsoleInput.units", this.unitIndex); + var x; + + switch (id) { + case "RemoteSwitch": + this.remoteSwitch.flip(); + prefs.remote = this.remoteSwitch.state; + this.setReaderReady(this.remoteSwitch.state != 0); + this.fileSelector.disabled = (this.remoteSwitch.state != 0); + break; + case "SpeedSwitch": + this.speedSwitch.flip(); + prefs.speed = this.speedSwitch.state; + this.charPeriod = (this.speedSwitch.state ? B220PaperTapeReader.highSpeedPeriod : B220PaperTapeReader.lowSpeedPeriod); + break; + case "UnitDesignateKnob": + x = this.unitDesignateKnob.selectedIndex; + if (x < 0) { + x = this.unitDesignateKnob.length-1; + this.unitMask = 0; + } else { + this.unitMask = B220Processor.pow2[x]; + prefs.unitMask = this.unitMask + } + break; + } + + this.config.putNode("ConsoleInput.units", prefs, this.unitIndex); + ev.preventDefault(); + ev.stopPropagation(); +}; + +/**************************************/ +B220PaperTapeReader.prototype.readerOnload = function readerOnload() { + /* Initializes the reader window and user interface */ + var body; + var mask; + var prefs = this.config.getNode("ConsoleInput.units", this.unitIndex); + var x; + + this.doc = this.window.document; + //de = this.doc.documentElement; + this.doc.title = "retro-220 - Reader - " + this.mnemonic; + + this.fileSelector = this.$$("PRFileSelector"); + this.tapeSupplyBar = this.$$("PRTapeSupplyBar"); + this.tapeView = this.$$("PRTapeView"); + + body = this.$$("PaperTapeReader") + this.remoteSwitch = new ToggleSwitch(body, null, null, "RemoteSwitch", + B220PaperTapeReader.offSwitchImage, B220PaperTapeReader.onSwitchImage); + this.remoteSwitch.set(prefs.remote); + + this.readyLamp = new ColoredLamp(body, null, null, "ReadyLamp", "blueLamp lampCollar", "blueLit"); + this.setReaderReady(this.remoteSwitch.state != 0); + + this.speedSwitch = new ToggleSwitch(body, null, null, "SpeedSwitch", + B220PaperTapeReader.offSwitchImage, B220PaperTapeReader.onSwitchImage); + this.speedSwitch.set(prefs.speed); + this.charPeriod = (this.speedSwitch.state ? B220PaperTapeReader.highSpeedPeriod : B220PaperTapeReader.lowSpeedPeriod); + + this.unitDesignateKnob = this.$$("UnitDesignateKnob"); + mask = 0x001; + this.unitMask = prefs.unitMask; + if (this.unitMask == 0) { + this.unitDesignateKnob.selectedIndex = this.unitDesignateKnob.length-1; // OFF + } else { + for (x=0; x= bufLength) { // end of buffer -- send finish + this.sendTapeChar(0x20, 0x35, receiver); + this.setReaderEmpty(); + break; // out of do loop + } else { + c = this.buffer.charCodeAt(x) % 0x100; + if (c == 0x0D) { // carriage return -- send EOW and check for LF + if (++x < bufLength && this.buffer.charCodeAt(x) == 0x0A) { + ++x; + } + this.sendTapeChar(0x20, 0x35, receiver); + if (x >= bufLength) { + this.setReaderEmpty(); + } + break; // out of do loop + } else if (c == 0x0A) { // line feed -- send EOW + ++x; + this.sendTapeChar(0x20, 0x35, receiver); + if (x >= bufLength) { + this.setReaderEmpty(); + } + break; // out of do loop + } else { // translate character and send its code + ++x; + this.sendTapeChar(c, B220PaperTapeReader.xlate220[c], receiver); + break; // out of do loop + } + } + } while (true); + + this.tapeSupplyBar.value = bufLength-x; + this.bufIndex = x; + } +}; + +/**************************************/ +B220PaperTapeReader.prototype.shutDown = function shutDown() { + /* Shuts down the device */ + + if (this.inTimer) { + clearCallback(this.inTimer); + } + + if (this.window) { + this.window.removeEventListener("beforeunload", B220PaperTapeReader.prototype.beforeUnload, false); + this.window.close(); + this.window = null; + } +}; diff --git a/webUI/B220SystemConfig.css b/webUI/B220SystemConfig.css index e9939bb..1ac94cf 100644 --- a/webUI/B220SystemConfig.css +++ b/webUI/B220SystemConfig.css @@ -86,6 +86,7 @@ #SystemMemorySize { text-align: center} +#ConsoleInputTable, #ConsoleOutputTable, #CardatronTable, #MagTapeOptionsTable, @@ -93,6 +94,8 @@ border-spacing: 0; border-collapse: collapse} +#ConsoleInputTable TH, +#ConsoleInputTable TD, #ConsoleOutputTable TH, #ConsoleOutputTable TD, #CardatronTable TH, diff --git a/webUI/B220SystemConfig.html b/webUI/B220SystemConfig.html index 3b54b5d..423fe7c 100644 --- a/webUI/B220SystemConfig.html +++ b/webUI/B220SystemConfig.html @@ -43,8 +43,8 @@ -
System Properties:
+
System Properties:
Word Memory Size + +
Console Input:
+ + + + + + + + + + + + + + +
PositionType12345678910 +
1 + + + + + + + + + + + + + + + + + + + + + + + +
2 + + + + + + + + + + + + + + + + + + + + + + + +
3 + + + + + + + + + + + + + + + + + + + + + + + +
4 + + + + + + + + + + + + + + + + + + + + + + + +
5 + + + + + + + + + + + + + + + + + + + + + + + +
6 + + + + + + + + + + + + + + + + + + + + + + + +
7 + + + + + + + + + + + + + + + + + + + + + + + +
8 + + + + + + + + + + + + + + + + + + + + + + + +
9 + + + + + + + + + + + + + + + + + + + + + + + +
10 + + + + + + + + + + + + + + + + + + + + + + +
+ +
Console Output:
@@ -517,6 +806,7 @@  
+
Cardatron Unit Selection:
@@ -910,7 +1200,9 @@
+

 

+ \ No newline at end of file diff --git a/webUI/B220SystemConfig.js b/webUI/B220SystemConfig.js index fec8f74..3594e81 100644 --- a/webUI/B220SystemConfig.js +++ b/webUI/B220SystemConfig.js @@ -39,6 +39,88 @@ B220SystemConfig.prototype.configStorageName = "retro-220-Config"; B220SystemConfig.prototype.configVersion = 1; B220SystemConfig.prototype.flushDelay = 60000; // flush timer setting, ms +B220SystemConfig.defaultConfig = { + version: this.configVersion, + memorySize: 5000, // 11-digit words + + ControlConsole: { + PCS1SW: 0, // Program Control Switches 1-0 + PCS2SW: 0, + PCS3SW: 0, + PCS4SW: 0, + PCS5SW: 0, + PCW6SW: 0, + PCS7SW: 0, + PCS8SW: 0, + PCS9SW: 0, + PCS0SW: 0, + SONSW: 0, // S-register on + SUNITSSW: 0, // S-register units + STOCSW: 0, // S-to-C stop + STOPSW: 0}, // S-to-P stop + + ConsoleInput: { + units: [ + null, // unit[0] not used + {type: "PTRA", unitMask: 0x002, remote: 1, speed: 0}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"} + ]}, + + ConsoleOutput: { + units: [ + {type: "TTYA", unitMask: 0x001, remote: 1, format: 0, zeroSuppress: 0, mapMemory: 0, + columns: 72, tabs: "9,17,25,33,41,49,57,65,73,81"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"} + ]}, + + Cardatron: { + hasCardatron: true, + units: [ + null, // unit[0] not used + {type: "CR1", formatSelect: 0, formatCol: 1}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "NONE"}, + {type: "LP2", algolGlyphs: true, greenBar: true, zeroSuppressCols: ""}, + {type: "CP1", algolGlyphs: true, greenBar: false, zeroSuppressCols: ""} + ]}, + + MagTape: { + hasMagTape: true, + units: [ + null, // unit[0] not used + {type: "MTA", designate: 0, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false}, + {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"}, + {type: "NONE"}, + {type: "NONE"} + ]} + }; + + /**************************************/ B220SystemConfig.prototype.$$ = function $$(id) { return this.window.document.getElementById(id); @@ -53,73 +135,7 @@ B220SystemConfig.prototype.createConfigData = function createConfigData() { var prefs; var s; - this.configData = { - version: this.configVersion, - memorySize: 5000, // 11-digit words - - ControlConsole: { - PCS1SW: 0, // Program Control Switches 1-0 - PCS2SW: 0, - PCS3SW: 0, - PCS4SW: 0, - PCS5SW: 0, - PCW6SW: 0, - PCS7SW: 0, - PCS8SW: 0, - PCS9SW: 0, - PCS0SW: 0, - SONSW: 0, // S-register on - SUNITSSW: 0, // S-register units - STOCSW: 0, // S-to-C stop - STOPSW: 0}, // S-to-P stop - - ConsoleOutput: { - units: [ - {type: "TTYA", zeroSuppress: 0, mapMemory: 0, unitMask: 0x001, remote: 1, format: 0, - columns: 72, tabs: "9,17,25,33,41,49,57,65,73,81"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"} - ]}, - - Cardatron: { - hasCardatron: true, - units: [ - null, // unit[0] not used - {type: "CR1", formatSelect: 0, formatCol: 1}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "NONE"}, - {type: "LP2", algolGlyphs: true, greenBar: true, zeroSuppressCols: ""}, - {type: "CP1", algolGlyphs: true, greenBar: false, zeroSuppressCols: ""} - ]}, - - MagTape: { - hasMagTape: true, - suppressBSwitch: false, // false => off => suppress B-register modification - units: [ - null, // unit[0] not used - {type: "MTA", designate: 0, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false}, - {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"}, - {type: "NONE"}, - {type: "NONE"} - ]} - }; - + this.configData = B220SystemConfig.defaultConfig; this.flushHandler(); }; @@ -280,7 +296,29 @@ B220SystemConfig.prototype.loadConfigDialog = function loadConfigDialog() { // System Properties this.setListValue("SystemMemorySize", cd.memorySize.toString()); + // Console Input units + + if (!cd.ConsoleInput) { + cd.ConsoleInput = B220SystemConfig.defaultConfig.ConsoleInput; + } + + for (x=1; x<=10; ++x) { + unit = cd.ConsoleInput.units[x]; + prefix = "ConsoleIn" + x; + this.setListValue(prefix + "Type", unit.type); + mask = 0x001; + for (y=1; y<=10; ++y) { + mask <<= 1; + this.$$(prefix + "_" + y).checked = (unit.unitMask & mask ? true : false); + } // for y + } // for x + // Console Output units + + if (!cd.ConsoleOutput) { + cd.ConsoleOutput = B220SystemConfig.defaultConfig.ConsoleOutput; + } + for (x=0; x<=10; ++x) { unit = cd.ConsoleOutput.units[x]; prefix = "ConsoleOut" + x; @@ -298,6 +336,11 @@ B220SystemConfig.prototype.loadConfigDialog = function loadConfigDialog() { } // for x // Cardatron units + + if (!cd.Cardatron) { + cd.Cardatron = B220SystemConfig.defaultConfig.Cardatron; + } + for (x=1; x<=7; ++x) { unit = cd.Cardatron.units[x]; prefix = "Cardatron" + x; @@ -324,6 +367,10 @@ B220SystemConfig.prototype.loadConfigDialog = function loadConfigDialog() { // Magnetic Tape units + if (!cd.MagTape) { + cd.MagTape = B220SystemConfig.defaultConfig.MagTape; + } + this.$$("SuppressBMod").checked = !cd.MagTape.suppressBSwitch; for (x=1; x<=10; ++x) { unit = cd.MagTape.units[x]; @@ -372,6 +419,28 @@ B220SystemConfig.prototype.saveConfigDialog = function saveConfigDialog() { x = parseInt(e.options[e.selectedIndex], 10); cd.memorySize = (isNaN(x) ? 5000 : x); + // Console Input units + + for (x=1; x<=10; ++x) { + unit = cd.ConsoleInput.units[x]; + prefix = "ConsoleIn" + x; + e = this.$$(prefix + "Type"); + unit.type = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value); + mask = 0x001; + unit.unitMask = 0; + for (y=1; y<=10; ++y) { + mask <<= 1; + if (this.$$(prefix + "_" + y).checked) { + unit.unitMask |= mask; + } + } // for y + + if (unit.type != "NONE") { + unit.remote = (unit.remote || 0); + unit.speed = (unit.speed || 0); + } + } // for x + // Console Output units for (x=0; x<=10; ++x) { @@ -391,10 +460,15 @@ B220SystemConfig.prototype.saveConfigDialog = function saveConfigDialog() { } } // for y - e = this.$$(prefix + "Format"); - unit.format = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value); - unit.columns = (unit.columns ? unit.columns : 72); - unit.tabs = (unit.tabs ? unit.tabs : "1,9,17,25,33,41,49,57,65,73"); + if (unit.type != "NONE") { + unit.remote = (unit.remote || 0); + unit.zeroSuppress = (unit.zeroSuppress || 0); + unit.mapMemory = (unit.mapMemory || 0); + e = this.$$(prefix + "Format"); + unit.format = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value); + unit.columns = (unit.columns ? unit.columns : 72); + unit.tabs = (unit.tabs ? unit.tabs : "1,9,17,25,33,41,49,57,65,73"); + } } // for x // Cardatron units @@ -410,14 +484,18 @@ B220SystemConfig.prototype.saveConfigDialog = function saveConfigDialog() { cd.Cardatron.hasCardatron = true; unit.algolGlyphs = this.$$(prefix + "AlgolGlyphs").checked; unit.greenBar = this.$$(prefix + "Greenbar").checked; + unit.zeroSuppressCols = (unit.zeroSuppressCols || ""); break; case "CP": cd.Cardatron.hasCardatron = true; unit.algolGlyphs = this.$$(prefix + "AlgolGlyphs").checked; unit.greenBar = false; + unit.zeroSuppressCols = (unit.zeroSuppressCols || ""); break; case "CR": cd.Cardatron.hasCardatron = true; + unit.formatSelect = (unit.formatSelect || 0); + unit.formatCol = (unit.formatCol === undefined ? 1 : unit.formatCol) // no break default: unit.algolGlyphs = false;