mirror of
https://github.com/pkimpel/retro-220.git
synced 2026-04-15 16:10:49 +00:00
Commit 220 emulator version 0.4:
1. Minor improvements to magnetic tape implementation and rearrangement of code. 2. Correct Processor CAD/CAA/CSU/CSA operation for operand signs other than 0 or 1. 3. Correct Processor LDB to load only the low-order four digits of the operand into B. 4. Correct Processor SLS shift count; improve mechanization of other shift-left operations. 5. Fix beforeunload event registration for Cardatron and Console devices. 6. Implement "Whippet" mode for Console TTY devices to print at 200 CPS instead of 10 CPS. 7. Expand B220PaperTapePunch translate table to cover all 256 8-bit codes; scroll end of punched data into view. 8. Minor code cleanup in B220PaperTapeReader.
This commit is contained in:
@@ -256,7 +256,7 @@ function B220Processor(config, devices) {
|
||||
* Global Constants *
|
||||
***********************************************************************/
|
||||
|
||||
B220Processor.version = "0.03c";
|
||||
B220Processor.version = "0.04";
|
||||
|
||||
B220Processor.tick = 1000/200000; // milliseconds per clock cycle (200KHz)
|
||||
B220Processor.cyclesPerMilli = 1/B220Processor.tick;
|
||||
@@ -1166,6 +1166,41 @@ B220Processor.prototype.bcdAdd = function bcdAdd(a, d, digits, complement, initi
|
||||
return am;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.clearAdd = function clearAdd(absolute) {
|
||||
/* After accessing memory, algebraically add the addend (IB) to zero. If
|
||||
"absolute" is true, then the sign-bit of the word from memory is forced to the
|
||||
subtract toggle. All values are BCD with the sign in the 11th digit position.
|
||||
Sets the Digit Check alarm as necessary */
|
||||
var am = 0; // augend mantissa
|
||||
var dm; // addend mantissa
|
||||
var dSign; // addend sign
|
||||
|
||||
this.opTime = 0.095;
|
||||
this.E.set(this.CADDR);
|
||||
this.readMemory();
|
||||
if (this.MET.value) { // invalid address
|
||||
this.A.set(am); // sign is zero
|
||||
return; // exit to Operation Complete
|
||||
}
|
||||
|
||||
dm = this.IB.value % 0x10000000000;
|
||||
dSign = ((this.IB.value - dm)/0x10000000000);
|
||||
if (absolute) { // force sign bit to SUT
|
||||
dSign = (dSign & 0x0E) | this.SUT.value;
|
||||
} else if (this.SUT.value) { // complement the sign bit
|
||||
dSign = dSign ^ 0x01;
|
||||
}
|
||||
|
||||
am = this.bcdAdd(am, dm, 11);
|
||||
|
||||
// Set toggles for display purposes and return the result
|
||||
this.DST.set(dSign%2);
|
||||
this.SGT.set(dSign%2);
|
||||
this.D.set(dSign*0x10000000000 + dm);
|
||||
this.A.set(dSign*0x10000000000 + am);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.integerAdd = function integerAdd(absolute, toD) {
|
||||
/* After accessing memory, algebraically add the addend (IB) to the augend (A).
|
||||
@@ -3142,15 +3177,13 @@ B220Processor.prototype.execute = function execute() {
|
||||
|
||||
case 0x10: //--------------------- CAD/CAA Clear add/add absolute
|
||||
this.SUT.set(0);
|
||||
this.A.value = this.IB.value - this.IB.value%0x10000000000; // 0 with sign of IB
|
||||
this.integerAdd(this.CCONTROL % 0x10 == 1, false);
|
||||
this.clearAdd(this.CCONTROL % 0x10 == 1);
|
||||
this.operationComplete();
|
||||
break;
|
||||
|
||||
case 0x11: //--------------------- CSU/CSA Clear subtract/subtract absolute
|
||||
this.SUT.set(1);
|
||||
this.A.value = this.IB.value - this.IB.value%0x10000000000; // 0 with sign of IB
|
||||
this.integerAdd(this.CCONTROL % 0x10 == 1, false);
|
||||
this.clearAdd(this.CCONTROL % 0x10 == 1);
|
||||
this.operationComplete();
|
||||
break;
|
||||
|
||||
@@ -3451,7 +3484,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
if (this.CCONTROL%0x10 == 1) { // Load B complement
|
||||
this.B.set(this.bcdAdd(this.IB.value, 0, 4, 1, 1));
|
||||
} else { // Load B
|
||||
this.B.set(this.IB.value);
|
||||
this.B.set(this.IB.value%0x10000);
|
||||
}
|
||||
}
|
||||
this.operationComplete();
|
||||
@@ -3538,9 +3571,14 @@ B220Processor.prototype.execute = function execute() {
|
||||
case 0x49: //--------------------- SL* Shift (rotate) left A/A and R/A with sign
|
||||
switch (this.CCONTROL%0x10) {
|
||||
case 1: // SLT: Shift Left A and R
|
||||
x = B220Processor.bcdBinary(this.CADDR % 0x20);
|
||||
this.opTime = 0.210 - x*0.005;
|
||||
this.DC.set(B220Processor.binaryBCD(x));
|
||||
x = this.CADDR % 0x20;
|
||||
if (x < 0x10) {
|
||||
this.opTime = 0.210 - x*0.005;
|
||||
} else {
|
||||
this.opTime = 0.160 - (x-0x10)*0.005;
|
||||
}
|
||||
|
||||
this.DC.set(x);
|
||||
w = this.R.value % 0x10000000000; // R sign is not affected
|
||||
this.A.value %= 0x10000000000; // discard the A sign
|
||||
while (this.DC.value < 0x20) {
|
||||
@@ -3553,10 +3591,12 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.R.set(this.R.value - this.R.value%0x10000000000 + w); // restore the R sign
|
||||
break;
|
||||
case 2: // SLS: Shift Left A with Sign
|
||||
x = B220Processor.bcdBinary(this.CADDR % 0x10);
|
||||
x = this.CADDR % 0x10;
|
||||
this.opTime = 0.160 - x*0.005;
|
||||
this.DC.set(B220Processor.binaryBCD(10+x));
|
||||
this.DC.set(0x10+x);
|
||||
w = this.A.value % 0x100000000000; // A sign is included
|
||||
d = w % 0x10; // do one more rotate right
|
||||
w = (w-d)/0x10 + d*0x10000000000; // than the count calls for
|
||||
while (this.DC.value < 0x20) {
|
||||
d = w % 0x10;
|
||||
w = (w-d)/0x10 + d*0x10000000000;
|
||||
@@ -3565,9 +3605,9 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.A.set(w);
|
||||
break;
|
||||
default: // SLA: Shift Left A
|
||||
x = B220Processor.bcdBinary(this.CADDR % 0x10);
|
||||
x = this.CADDR % 0x10;
|
||||
this.opTime = 0.160 - x*0.005;
|
||||
this.DC.set(B220Processor.binaryBCD(10+x));
|
||||
this.DC.set(0x10+x);
|
||||
w = this.A.value % 0x10000000000; // A sign is not affected
|
||||
while (this.DC.value < 0x20) {
|
||||
d = w % 0x10;
|
||||
@@ -3721,7 +3761,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
} else if (this.magTape.controlBusy) {
|
||||
this.opTime = 0.01;
|
||||
} else {
|
||||
opTime = 0.14;
|
||||
this.opTime = 0.14;
|
||||
if (this.CCONTROL%0x10 == 1) { // MIE
|
||||
if (this.magTape.testUnitAtEOT(this.D.value)) {
|
||||
this.P.set(this.CADDR);
|
||||
@@ -4251,41 +4291,6 @@ 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] = 0x1101542000; // MIW 2000,1,1,1 // write an EOT block
|
||||
|
||||
this.MM[ 6] = 0x1008500000; // MRW 1
|
||||
this.MM[ 7] = 0x1000560000; // MOW 0,1,10,100
|
||||
this.MM[ 8] = 0x1750560100; // MOW 100,1,7,50
|
||||
this.MM[ 9] = 0x1500570079; // MOR 79,1,5,00
|
||||
//this.MM[ 10] = 0x1101562000; // MOW 2000,1,1,1
|
||||
this.MM[ 10] = 0x1110562000; // MOW 2000,1,1,10 // TEMP: block-length=10, should fire EOT control word
|
||||
|
||||
this.MM[ 11] = 0x1008500000; // MRW 1
|
||||
this.MM[ 12] = 0x1000523000; // MRD 3000,1,10,0
|
||||
this.MM[ 13] = 0x1700524000; // MRD 4000,1,7,0
|
||||
this.MM[ 14] = 0x1500534350; // MRR 4350,1,5,0
|
||||
this.MM[ 15] = 0x1100534800; // MRR 4800,1,1,0 // should be an EOT block
|
||||
|
||||
this.MM[ 16] = 0x1009500000; // MDA 1
|
||||
this.MM[ 17] = 0x7777009999; // HLT 9999,7777
|
||||
|
||||
this.MM[ 79] = 0x1900000000; // preface for 19 words, 80-98
|
||||
this.MM[ 99] = 0x4000000000; // preface for 40 words, 100-139
|
||||
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
|
||||
|
||||
this.MM[2000] = 0x9920012002; // end-of-tape control word
|
||||
this.MM[2001] = 0x9999999999; // storage for end-of-tape block state
|
||||
this.MM[2002] = 0x9999008421; // HLT: target for end-of-tape control branch
|
||||
this.MM[2003] = 0x0000300011; // branch to read test sequence
|
||||
|
||||
// Simple counter speed test
|
||||
this.MM[ 80] = 0x0000120082; // ADD 82
|
||||
this.MM[ 81] = 0x0000300080; // BUN 80
|
||||
@@ -4469,4 +4474,39 @@ B220Processor.prototype.loadDefaultProgram = function loadDefaultProgram() {
|
||||
this.MM[ 377]= 0x20202021616; // CR CNST 20202021616 NEWLINES
|
||||
|
||||
this.MM[1000]= 0x00000000000; // F DEFN * ARRAY F[2800]
|
||||
|
||||
// TEMP // Tape tests
|
||||
this.MM[ 400] = 0x1008500000; // MRW 1
|
||||
this.MM[ 401] = 0x1002580000; // MPE 1
|
||||
this.MM[ 402] = 0x1000540000; // MIW 0,1,10,100
|
||||
this.MM[ 403] = 0x1750540100; // MIW 100,1,7,50
|
||||
this.MM[ 404] = 0x1500550079; // MIR 79,1,5,00
|
||||
this.MM[ 405] = 0x1101542000; // MIW 2000,1,1,1 // write an EOT block
|
||||
|
||||
this.MM[ 406] = 0x1008500000; // MRW 1
|
||||
this.MM[ 407] = 0x1000560000; // MOW 0,1,10,100
|
||||
this.MM[ 408] = 0x1750560100; // MOW 100,1,7,50
|
||||
this.MM[ 409] = 0x1500570079; // MOR 79,1,5,00
|
||||
//this.MM[ 410] = 0x1101562000; // MOW 2000,1,1,1
|
||||
this.MM[ 410] = 0x1110562000; // MOW 2000,1,1,10 // TEMP: block-length=10, should fire EOT control word
|
||||
|
||||
this.MM[ 411] = 0x1008500000; // MRW 1
|
||||
this.MM[ 412] = 0x1000523000; // MRD 3000,1,10,0
|
||||
this.MM[ 413] = 0x1700524000; // MRD 4000,1,7,0
|
||||
this.MM[ 414] = 0x1500534350; // MRR 4350,1,5,0
|
||||
this.MM[ 415] = 0x1100534800; // MRR 4800,1,1,0 // should be an EOT block
|
||||
|
||||
this.MM[ 416] = 0x1009500000; // MDA 1
|
||||
this.MM[ 417] = 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
|
||||
|
||||
this.MM[2000] = 0x9920012002; // end-of-tape control word
|
||||
this.MM[2001] = 0x9999999999; // storage for end-of-tape block state
|
||||
this.MM[2002] = 0x9999008421; // HLT: target for end-of-tape control branch
|
||||
this.MM[2003] = 0x0000300411; // branch to read test sequence
|
||||
};
|
||||
@@ -18,10 +18,6 @@
|
||||
Burroughs 220 Emulator – Hosting Site Home
|
||||
</h1>
|
||||
|
||||
<p style="text-align:center; font-size:larger; font-weight:bold; color:red">
|
||||
(Under Construction)
|
||||
</p>
|
||||
|
||||
<p>This site hosts the current version of the retro-220 emulator, an implementation of the Burroughs 220 computer system that runs in a web browser.</p>
|
||||
|
||||
<p class=center>
|
||||
@@ -69,7 +65,7 @@
|
||||
Copyright (c) 2017, Paul Kimpel • Licensed under the <a href="LICENSE.txt">MIT License</a>
|
||||
</div>
|
||||
<div id=lastModDiv>Revised
|
||||
2016-12-25
|
||||
2017-11-19
|
||||
</div>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -164,9 +164,9 @@ B220CardatronControl.prototype.cardatronOnLoad = function cardatronOnLoad() {
|
||||
|
||||
// Events
|
||||
|
||||
this.window.addEventListener("beforeunload", B220CardatronControl.prototype.beforeUnload);
|
||||
this.window.addEventListener("beforeunload", B220CardatronControl.prototype.beforeUnload, false);
|
||||
this.$$("ClearBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronControl.prototype.ClearBtn_onClick));
|
||||
B220Util.bindMethod(this, B220CardatronControl.prototype.ClearBtn_onClick), false);
|
||||
|
||||
this.clear();
|
||||
|
||||
@@ -305,6 +305,6 @@ B220CardatronControl.prototype.shutDown = function shutDown() {
|
||||
}
|
||||
}
|
||||
|
||||
this.window.removeEventListener("beforeunload", B220CardatronControl.prototype.beforeUnload);
|
||||
this.window.removeEventListener("beforeunload", B220CardatronControl.prototype.beforeUnload, false);
|
||||
this.window.close();
|
||||
};
|
||||
@@ -615,21 +615,21 @@ B220CardatronInput.prototype.readerOnLoad = function readerOnLoad() {
|
||||
this.clearUnit(); // will actually set the state and lamps correctly
|
||||
|
||||
this.window.addEventListener("beforeunload",
|
||||
B220CardatronInput.prototype.beforeUnload);
|
||||
B220CardatronInput.prototype.beforeUnload, false);
|
||||
this.$$("CIFileSelector").addEventListener("change",
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.fileSelector_onChange));
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.fileSelector_onChange), false);
|
||||
this.$$("FormatColumn").addEventListener("change",
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.format_onChange));
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.format_onChange), false);
|
||||
this.$$("FormatSelect").addEventListener("change",
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.format_onChange));
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.format_onChange), false);
|
||||
this.$$("CIStartBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.CIStartBtn_onClick));
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.CIStartBtn_onClick), false);
|
||||
this.$$("CIStopBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.CIStopBtn_onClick));
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.CIStopBtn_onClick), false);
|
||||
this.$$("ClearBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.ClearBtn_onClick));
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.ClearBtn_onClick), false);
|
||||
this.hopperBar.addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.CIHopperBar_onClick));
|
||||
B220Util.bindMethod(this, B220CardatronInput.prototype.CIHopperBar_onClick), false);
|
||||
|
||||
this.window.resizeBy(de.scrollWidth - this.window.innerWidth + 4, // kludge for right-padding/margin
|
||||
de.scrollHeight - this.window.innerHeight);
|
||||
@@ -896,6 +896,6 @@ B220CardatronInput.prototype.shutDown = function shutDown() {
|
||||
if (this.timer) {
|
||||
clearCallback(this.timer);
|
||||
}
|
||||
this.window.removeEventListener("beforeunload", B220CardatronInput.prototype.beforeUnload);
|
||||
this.window.removeEventListener("beforeunload", B220CardatronInput.prototype.beforeUnload, false);
|
||||
this.window.close();
|
||||
};
|
||||
|
||||
@@ -758,7 +758,7 @@ B220CardatronOutput.prototype.deviceOnLoad = function deviceOnLoad() {
|
||||
this.window.addEventListener("beforeunload",
|
||||
B220CardatronOutput.prototype.beforeUnload, false);
|
||||
this.supply.addEventListener("dblclick",
|
||||
B220Util.bindMethod(this, B220CardatronOutput.prototype.copySupply));
|
||||
B220Util.bindMethod(this, B220CardatronOutput.prototype.copySupply), false);
|
||||
this.$$("COStopBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronOutput.prototype.COStopBtn_onClick), false);
|
||||
this.$$("COStartBtn").addEventListener("click",
|
||||
@@ -772,7 +772,7 @@ B220CardatronOutput.prototype.deviceOnLoad = function deviceOnLoad() {
|
||||
this.$$("COSetZSBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronOutput.prototype.COSetZSBtn_onClick), false);
|
||||
this.$$("ClearBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, B220CardatronOutput.prototype.ClearBtn_onClick));
|
||||
B220Util.bindMethod(this, B220CardatronOutput.prototype.ClearBtn_onClick), false);
|
||||
|
||||
if (!this.isPrinter) {
|
||||
this.$$("COEndOfSupplyBtn").innerHTML = "OUT OF<br>CARDS";
|
||||
@@ -1031,7 +1031,7 @@ B220CardatronOutput.prototype.shutDown = function shutDown() {
|
||||
if (this.timer) {
|
||||
clearCallback(this.timer);
|
||||
}
|
||||
this.window.removeEventListener("beforeunload", B220CardatronOutput.prototype.beforeUnload);
|
||||
this.window.removeEventListener("beforeunload", B220CardatronOutput.prototype.beforeUnload, false);
|
||||
this.window.close();
|
||||
if (this.zsWindow && !this.zsWindow.closed) {
|
||||
this.zsWindow.close();
|
||||
|
||||
@@ -185,6 +185,20 @@
|
||||
top: 66px;
|
||||
width: 220px}
|
||||
|
||||
#SpeedSwitch {
|
||||
position: absolute;
|
||||
left: 60px;
|
||||
top: 160px;
|
||||
width: 24px}
|
||||
#WhippetSpeedCaption {
|
||||
left: 48px;
|
||||
top: 146px;
|
||||
width: 48px}
|
||||
#TTYSpeedCaption {
|
||||
left: 48px;
|
||||
top: 190px;
|
||||
width: 48px}
|
||||
|
||||
#UnitSwitch0 {
|
||||
position: absolute;
|
||||
left: 134px;
|
||||
|
||||
@@ -63,6 +63,9 @@
|
||||
<div id=TabStopsCaption class=caption>TAB STOPS</div>
|
||||
<input id=TabStops class=data type=text maxlength=80 title="comma-delimited list of 1-relative tab stops">
|
||||
|
||||
<div id=WhippetSpeedCaption class=caption>SPEED<br>WHIPPET</div>
|
||||
<div id=TTYSpeedCaption class=caption>TTY</div>
|
||||
|
||||
<div id=UnitSwitch0Caption class=caption>SPO</div>
|
||||
<div id=UnitSwitch1Caption class=caption>1</div>
|
||||
<div id=UnitSwitch2Caption class=caption>2</div>
|
||||
|
||||
@@ -32,12 +32,13 @@ function B220ConsolePrinter(mnemonic, unitIndex, config) {
|
||||
this.unitSwitch = new Array(11); // unit selection switch objects
|
||||
this.tabStop = []; // 0-relative tab stop positions
|
||||
this.zeroSuppress = 0; // zero-suppression switch setting
|
||||
this.charPeriod = 0; // printer speed, ms/char
|
||||
|
||||
this.boundButton_Click = B220Util.bindMethod(this, B220ConsolePrinter.prototype.button_Click);
|
||||
this.boundText_OnChange = B220Util.bindMethod(this, B220ConsolePrinter.prototype.text_OnChange);
|
||||
this.boundFlipSwitch = B220Util.bindMethod(this, B220ConsolePrinter.prototype.flipSwitch);
|
||||
this.boundReceiveSign = B220Util.bindMethod(this, B220ConsolePrinter.prototype.receiveSign);
|
||||
this.boundReceiveChar = B220Util.bindMethod(this, B220ConsolePrinter.prototype.receiveChar);
|
||||
this.boundButton_Click = B220ConsolePrinter.prototype.button_Click.bind(this);
|
||||
this.boundText_OnChange = B220ConsolePrinter.prototype.text_OnChange.bind(this);
|
||||
this.boundFlipSwitch = B220ConsolePrinter.prototype.flipSwitch.bind(this);
|
||||
this.boundReceiveSign = B220ConsolePrinter.prototype.receiveSign.bind(this);
|
||||
this.boundReceiveChar = B220ConsolePrinter.prototype.receiveChar.bind(this);
|
||||
|
||||
this.clear();
|
||||
|
||||
@@ -58,8 +59,8 @@ function B220ConsolePrinter(mnemonic, unitIndex, config) {
|
||||
B220ConsolePrinter.offSwitchImage = "./resources/ToggleDown.png";
|
||||
B220ConsolePrinter.onSwitchImage = "./resources/ToggleUp.png";
|
||||
|
||||
B220ConsolePrinter.charsPerSecond = 10; // Printer speed
|
||||
B220ConsolePrinter.charPeriod = 1000/B220ConsolePrinter.charsPerSecond;
|
||||
B220ConsolePrinter.ttySpeed = 10; // TTY printer speed, char/sec
|
||||
B220ConsolePrinter.whippetSpeed = 200; // Whippet printer speed, char/sec
|
||||
// Inter-character period, ms
|
||||
B220ConsolePrinter.pageSize = 66; // lines/page for form-feed
|
||||
B220ConsolePrinter.maxScrollLines = 15000;
|
||||
@@ -264,7 +265,7 @@ B220ConsolePrinter.prototype.flipSwitch = function flipSwitch(ev) {
|
||||
break;
|
||||
case "MapMemorySwitch":
|
||||
this.mapMemorySwitch.flip();
|
||||
prefs.mapMemory, this.mapMemory = this.mapMemorySwitch.state;
|
||||
prefs.mapMemory = this.mapMemory = this.mapMemorySwitch.state;
|
||||
break;
|
||||
case "RemoteKnob":
|
||||
this.remoteKnob.step();
|
||||
@@ -276,6 +277,15 @@ B220ConsolePrinter.prototype.flipSwitch = function flipSwitch(ev) {
|
||||
prefs.format = this.formatKnob.position;
|
||||
this.format = this.formatKnob.position;
|
||||
break;
|
||||
case "SpeedSwitch":
|
||||
this.speedSwitch.flip();
|
||||
prefs.printerSpeed = this.speedSwitch.state;
|
||||
if (this.speedSwitch.state) {
|
||||
this.charPeriod = 1000/B220ConsolePrinter.whippetSpeed;
|
||||
} else {
|
||||
this.charPeriod = 1000/B220ConsolePrinter.ttySpeed;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
x = id.indexOf("UnitSwitch");
|
||||
if (x == 0) {
|
||||
@@ -394,6 +404,14 @@ B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad() {
|
||||
B220ConsolePrinter.offSwitchImage, B220ConsolePrinter.onSwitchImage);
|
||||
this.mapMemorySwitch.set(prefs.mapMemory);
|
||||
this.mapMemory = this.mapMemorySwitch.state;
|
||||
this.speedSwitch = new ToggleSwitch(body, null, null, "SpeedSwitch",
|
||||
B220ConsolePrinter.offSwitchImage, B220ConsolePrinter.onSwitchImage);
|
||||
this.speedSwitch.set(prefs.printerSpeed);
|
||||
if (this.speedSwitch.state) {
|
||||
this.charPeriod = 1000/B220ConsolePrinter.whippetSpeed;
|
||||
} else {
|
||||
this.charPeriod = 1000/B220ConsolePrinter.ttySpeed;
|
||||
}
|
||||
|
||||
mask = 0x001;
|
||||
this.unitMask = prefs.unitMask;
|
||||
@@ -421,11 +439,11 @@ B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad() {
|
||||
|
||||
// Events
|
||||
this.window.addEventListener("beforeunload",
|
||||
B220ConsolePrinter.prototype.beforeUnload);
|
||||
B220ConsolePrinter.prototype.beforeUnload, false);
|
||||
this.window.addEventListener("resize",
|
||||
B220Util.bindMethod(this, B220ConsolePrinter.prototype.resizeWindow));
|
||||
B220Util.bindMethod(this, B220ConsolePrinter.prototype.resizeWindow), false);
|
||||
this.paper.addEventListener("dblclick",
|
||||
B220Util.bindMethod(this, B220ConsolePrinter.prototype.copyPaper));
|
||||
B220Util.bindMethod(this, B220ConsolePrinter.prototype.copyPaper), false);
|
||||
|
||||
this.$$("OpenPanelBtn").addEventListener("click", this.boundButton_Click);
|
||||
this.$$("ClosePanelBtn").addEventListener("click", this.boundButton_Click);
|
||||
@@ -434,6 +452,7 @@ B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad() {
|
||||
|
||||
this.zeroSuppressSwitch.addEventListener("click", this.boundFlipSwitch);
|
||||
this.mapMemorySwitch.addEventListener("click", this.boundFlipSwitch);
|
||||
this.speedSwitch.addEventListener("click", this.boundFlipSwitch);
|
||||
this.remoteKnob.addEventListener("click", this.boundFlipSwitch);
|
||||
this.formatKnob.addEventListener("click", this.boundFlipSwitch);
|
||||
this.$$("Columns").addEventListener("change", this.boundText_OnChange);
|
||||
@@ -459,7 +478,7 @@ B220ConsolePrinter.prototype.receiveSign = function receiveSign(char, successor)
|
||||
/* Receives the sign character from the processor and handles it according
|
||||
to the value of the sign and the setting of the Map Memory and LZ Suppress
|
||||
switches */
|
||||
var delay = B220ConsolePrinter.charPeriod; // default character delay
|
||||
var delay = this.charPeriod; // default character delay
|
||||
var stamp = performance.now(); // current time
|
||||
|
||||
switch (true) {
|
||||
@@ -506,7 +525,7 @@ B220ConsolePrinter.prototype.receiveSign = function receiveSign(char, successor)
|
||||
B220ConsolePrinter.prototype.receiveChar = function receiveChar(char, successor) {
|
||||
/* Receives a non-sign character from the processor and outputs it. Special handling
|
||||
is provided for tabs, carriage returns, form feeds, and end-of-word characters */
|
||||
var delay = B220ConsolePrinter.charPeriod; // default character delay
|
||||
var delay = this.charPeriod; // default character delay
|
||||
var nextReceiver = this.boundReceiveChar; // default routine to receive next char
|
||||
var stamp = performance.now(); // current time
|
||||
|
||||
@@ -572,7 +591,7 @@ B220ConsolePrinter.prototype.shutDown = function shutDown() {
|
||||
}
|
||||
|
||||
if (this.window) {
|
||||
this.window.removeEventListener("beforeunload", B220ConsolePrinter.prototype.beforeUnload);
|
||||
this.window.removeEventListener("beforeunload", B220ConsolePrinter.prototype.beforeUnload, false);
|
||||
this.window.close();
|
||||
this.window = null;
|
||||
}
|
||||
|
||||
@@ -126,30 +126,15 @@ B220MagTapeControl.prototype.clear = function clear() {
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
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;
|
||||
B220MagTapeControl.prototype.clearMisc = function clearMisc() {
|
||||
/* Resets this.regMisc and the individual lamps for that register */
|
||||
var bitNr;
|
||||
var m = this.regMisc;
|
||||
|
||||
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;
|
||||
m.update(0);
|
||||
for (bitNr=m.bits-1; bitNr>= 0; --bitNr) {
|
||||
m.lamps[bitNr].set(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -175,126 +160,73 @@ B220MagTapeControl.prototype.storeWord = function storeWord(initialStore, word)
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.queuePendingOperation = function queuePendingOperation(callee, args) {
|
||||
/* Queues a pending tape operation */
|
||||
B220MagTapeControl.prototype.reportStatus = function reportStatus(state) {
|
||||
/* Sets bits in the MISC register to indicate various drive and control unit
|
||||
status and error conditions */
|
||||
|
||||
//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.dequeuePendingOperation = function dequeuePendingOperation() {
|
||||
/* Dequeues and reinitiates a pending tape operation */
|
||||
var args = this.pendingArgs; // pending Arguments object
|
||||
var callee = this.pendingCallee; // pending method to call
|
||||
|
||||
this.pendingCallee = this.pendingArgs = null;
|
||||
callee.apply(this, args);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.loadCommand = function loadCommand(dReg, 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 this.releaseProcessor 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, and this.unitIndex from the digits in T. Sets this.
|
||||
currentUnit to the current tape unit object. Then returns true to inidicate
|
||||
the I/O can proceed */
|
||||
var c; // scratch
|
||||
var proceed = false; // return value: true => proceed with I/O
|
||||
var t = dReg%0x10000000000; // temp to partition fields of Processor's D register
|
||||
var ux; // internal unit index
|
||||
|
||||
//console.log(this.mnemonic + " loadCommand: " + dReg.toString(16));
|
||||
if (this.controlBusy) {
|
||||
this.queuePendingOperation(callee, args);
|
||||
} else {
|
||||
this.T = t;
|
||||
this.regT.update(this.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.C = this.unitNr*0x100000 + t*0x10 + c;
|
||||
this.regC.update(this.C);
|
||||
switch (state) {
|
||||
case this.driveState.driveNoError:
|
||||
this.clearMisc();
|
||||
this.unitIndex = ux = this.findDesignate(this.unitNr);
|
||||
if (ux < 0) {
|
||||
this.reportStatus(this.driveState.driveNotReady); // drive not ready, not present
|
||||
this.releaseProcessor(false, 0);
|
||||
} else {
|
||||
this.currentUnit = this.tapeUnit[ux];
|
||||
if (this.currentUnit.busy || this.currentUnit.rewindLock) {
|
||||
this.queuePendingOperation(callee, args);
|
||||
} else {
|
||||
proceed = true;
|
||||
this.driveState.startTime = performance.now();
|
||||
this.driveState.completionDelay = 0;
|
||||
this.driveState.state = this.driveState.driveNoError;
|
||||
break;
|
||||
case this.driveState.driveNotReady:
|
||||
this.TX2Lamp.set(1);
|
||||
this.TX10Lamp.set(1);
|
||||
break;
|
||||
case this.driveState.drivePrefaceCheck:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TPCLamp.set(1);
|
||||
break;
|
||||
case this.driveState.drivePrefaceMismatch:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TCFLamp.set(1);
|
||||
this.C = (this.C & 0x00FFFF) | 0xFF0000;
|
||||
this.regC.update(this.C);
|
||||
break;
|
||||
case this.driveState.driveReadCheck:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TYC1Lamp.set(1);
|
||||
this.TYC2Lamp.set(1);
|
||||
this.C = (this.C & 0xFFF00F) | 0x000F90;
|
||||
this.regC.update(this.C);
|
||||
break;
|
||||
case this.driveState.driveInvalidBlockLength:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TX2Lamp.set(1);
|
||||
this.TX4Lamp.set(1);
|
||||
this.C = (this.C & 0x000F0F) | 0xB010F0;
|
||||
this.regC.update(this.C);
|
||||
break;
|
||||
case this.driveState.driveNotEditedTape:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
break;
|
||||
} // switch code
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
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 proceed;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.releaseControl = function releaseControl(param) {
|
||||
/* Releases the busy status of the control. If an error is present, sets the
|
||||
bits in the MISC register and the Processor's Magnetic Tape Check alarm, as
|
||||
appropriate. If another operation is pending, initiates that operation.
|
||||
Returns but does not use its parameter so that it can be used with
|
||||
Promise.then() */
|
||||
|
||||
this.TFLamp.set(0);
|
||||
this.TBLamp.set(0);
|
||||
this.controlBusy = false;
|
||||
if (this.driveState.state != this.driveState.driveNoError) {
|
||||
this.currentUnit.releaseUnit(this.driveState);
|
||||
this.reportStatus(this.driveState.state);
|
||||
}
|
||||
|
||||
if (this.pendingCallee !== null) {
|
||||
this.dequeuePendingOperation();
|
||||
}
|
||||
|
||||
return param;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.cancelIO = function cancelIO(param) {
|
||||
/* Terminates the current I/O operation by releasing the Processor, tape
|
||||
unit, and tape control unit. Returns but does not use its parameter so it
|
||||
can be used with Promise.then() */
|
||||
|
||||
this.releaseProcessor(false, 0);
|
||||
this.currentUnit.releaseUnit();
|
||||
this.releaseControl();
|
||||
return param;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.tapeUnitFinished = function tapeUnitFinished(param) {
|
||||
/* Call-back function passed to tape unit methods to signal when the unit has
|
||||
completed its asynchronous operation. Returns but does not use "param", so
|
||||
that it can be used with Promise.then() */
|
||||
|
||||
if (!this.controlBusy) { // if the control unit is currently idle...
|
||||
if (this.pendingCallee !== null) {
|
||||
this.dequeuePendingOperation();
|
||||
}
|
||||
}
|
||||
|
||||
return param;
|
||||
return index;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -436,58 +368,126 @@ B220MagTapeControl.prototype.compareKeywordField = function compareKeywordField(
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.clearMisc = function clearMisc() {
|
||||
/* Resets this.regMisc and the individual lamps for that register */
|
||||
var bitNr;
|
||||
var m = this.regMisc;
|
||||
B220MagTapeControl.prototype.queuePendingOperation = function queuePendingOperation(callee, args) {
|
||||
/* Queues a pending tape operation */
|
||||
|
||||
m.update(0);
|
||||
for (bitNr=m.bits-1; bitNr>= 0; --bitNr) {
|
||||
m.lamps[bitNr].set(0);
|
||||
//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.reportStatus = function reportStatus(state) {
|
||||
/* Sets bits in the MISC register to indicate various drive and control unit
|
||||
status and error conditions */
|
||||
B220MagTapeControl.prototype.dequeuePendingOperation = function dequeuePendingOperation() {
|
||||
/* Dequeues and reinitiates a pending tape operation */
|
||||
var args = this.pendingArgs; // pending Arguments object
|
||||
var callee = this.pendingCallee; // pending method to call
|
||||
|
||||
switch (state) {
|
||||
case this.driveState.driveNoError:
|
||||
this.pendingCallee = this.pendingArgs = null;
|
||||
callee.apply(this, args);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.loadCommand = function loadCommand(dReg, 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 this.releaseProcessor 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, and this.unitIndex from the digits in T. Sets this.
|
||||
currentUnit to the current tape unit object. Then returns true to inidicate
|
||||
the I/O can proceed */
|
||||
var c; // scratch
|
||||
var proceed = false; // return value: true => proceed with I/O
|
||||
var t = dReg%0x10000000000; // temp to partition fields of Processor's D register
|
||||
var ux; // internal unit index
|
||||
|
||||
//console.log(this.mnemonic + " loadCommand: " + dReg.toString(16));
|
||||
if (this.controlBusy) {
|
||||
this.queuePendingOperation(callee, args);
|
||||
} else {
|
||||
this.T = t;
|
||||
this.regT.update(this.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.C = this.unitNr*0x100000 + t*0x10 + c;
|
||||
this.regC.update(this.C);
|
||||
this.clearMisc();
|
||||
break;
|
||||
case this.driveState.driveNotReady:
|
||||
this.TX2Lamp.set(1);
|
||||
this.TX10Lamp.set(1);
|
||||
break;
|
||||
case this.driveState.drivePrefaceCheck:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TPCLamp.set(1);
|
||||
break;
|
||||
case this.driveState.drivePrefaceMismatch:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TCFLamp.set(1);
|
||||
this.C = (this.C & 0x00FFFF) | 0xFF0000;
|
||||
this.regC.update(this.C);
|
||||
break;
|
||||
case this.driveState.driveReadCheck:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TYC1Lamp.set(1);
|
||||
this.TYC2Lamp.set(1);
|
||||
this.C = (this.C & 0xFFF00F) | 0x000F90;
|
||||
this.regC.update(this.C);
|
||||
break;
|
||||
case this.driveState.driveInvalidBlockLength:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
this.TX2Lamp.set(1);
|
||||
this.TX4Lamp.set(1);
|
||||
this.C = (this.C & 0x000F0F) | 0xB010F0;
|
||||
this.regC.update(this.C);
|
||||
break;
|
||||
case this.driveState.driveNotEditedTape:
|
||||
this.p.setMagneticTapeCheck(1);
|
||||
break;
|
||||
} // switch code
|
||||
this.unitIndex = ux = this.findDesignate(this.unitNr);
|
||||
if (ux < 0) {
|
||||
this.reportStatus(this.driveState.driveNotReady); // drive not ready, not present
|
||||
this.releaseProcessor(false, 0);
|
||||
} else {
|
||||
this.currentUnit = this.tapeUnit[ux];
|
||||
if (this.currentUnit.busy || this.currentUnit.rewindLock) {
|
||||
this.queuePendingOperation(callee, args);
|
||||
} else {
|
||||
proceed = true;
|
||||
this.driveState.startTime = performance.now();
|
||||
this.driveState.completionDelay = 0;
|
||||
this.driveState.state = this.driveState.driveNoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return proceed;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.releaseControl = function releaseControl(param) {
|
||||
/* Releases the busy status of the control. If an error is present, sets the
|
||||
bits in the MISC register and the Processor's Magnetic Tape Check alarm, as
|
||||
appropriate. If another operation is pending, initiates that operation.
|
||||
Returns but does not use its parameter so that it can be used with
|
||||
Promise.then() */
|
||||
|
||||
this.TFLamp.set(0);
|
||||
this.TBLamp.set(0);
|
||||
this.controlBusy = false;
|
||||
if (this.driveState.state != this.driveState.driveNoError) {
|
||||
this.currentUnit.releaseUnit(this.driveState);
|
||||
this.reportStatus(this.driveState.state);
|
||||
}
|
||||
|
||||
if (this.pendingCallee !== null) {
|
||||
this.dequeuePendingOperation();
|
||||
}
|
||||
|
||||
return param;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.cancelIO = function cancelIO(param) {
|
||||
/* Terminates the current I/O operation by releasing the Processor, tape
|
||||
unit, and tape control unit. Returns but does not use its parameter so it
|
||||
can be used with Promise.then() */
|
||||
|
||||
this.releaseProcessor(false, 0);
|
||||
this.currentUnit.releaseUnit();
|
||||
this.releaseControl();
|
||||
return param;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeControl.prototype.tapeUnitFinished = function tapeUnitFinished(param) {
|
||||
/* Call-back function passed to tape unit methods to signal when the unit has
|
||||
completed its asynchronous operation. Returns but does not use "param", so
|
||||
that it can be used with Promise.then() */
|
||||
|
||||
if (!this.controlBusy) { // if the control unit is currently idle...
|
||||
if (this.pendingCallee !== null) {
|
||||
this.dequeuePendingOperation();
|
||||
}
|
||||
}
|
||||
|
||||
return param;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -568,7 +568,7 @@ B220MagTapeControl.prototype.magTapeOnLoad = function magTapeOnLoad() {
|
||||
|
||||
|
||||
// Events
|
||||
this.window.addEventListener("beforeunload", B220MagTapeControl.prototype.beforeUnload);
|
||||
this.window.addEventListener("beforeunload", B220MagTapeControl.prototype.beforeUnload, false);
|
||||
this.$$("ClearBtn").addEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regMisc.rightClearBar.addEventListener("click", this.boundSwitch_Click, false);
|
||||
this.regC.rightClearBar.addEventListener("click", this.boundSwitch_Click, false);
|
||||
|
||||
@@ -209,13 +209,6 @@ B220MagTapeDrive.prototype.clear = function clear() {
|
||||
this.tapeState = this.tapeUnloaded; // tape drive state
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.nil = function nil() {
|
||||
/* An empty function that just returns */
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.releaseUnit = function releaseUnit(param) {
|
||||
/* Releases the busy status of the unit. Returns but does not use its
|
||||
@@ -255,105 +248,6 @@ B220MagTapeDrive.prototype.setUnitDesignate = function setUnitDesignate(index) {
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.spinReel = function spinReel(inches) {
|
||||
/* Rotates the reel image icon an appropriate amount based on the "inches"
|
||||
of tape to be moved. The rotation is limited to this.maxSpinAngle degrees
|
||||
in either direction so that movement remains apparent to the viewer */
|
||||
var circumference = this.reelCircumference*(1 - this.tapeInches/this.maxTapeInches/2);
|
||||
var degrees = inches/circumference*360;
|
||||
|
||||
if (degrees > this.maxSpinAngle) {
|
||||
degrees = this.maxSpinAngle;
|
||||
} else if (degrees < -this.maxSpinAngle) {
|
||||
degrees = -this.maxSpinAngle;
|
||||
}
|
||||
|
||||
this.reelAngle = (this.reelAngle + degrees)%360;
|
||||
this.reelIcon.style.transform = "rotate(" + this.reelAngle.toFixed(0) + "deg)";
|
||||
|
||||
this.tapeInches += inches;
|
||||
if (this.tapeInches < this.maxTapeInches) {
|
||||
this.reelBar.value = this.maxTapeInches - this.tapeInches;
|
||||
} else {
|
||||
this.reelBar.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.moveTape = function moveTape(inches, delay, successor, param) {
|
||||
/* Delays the I/O during tape motion, during which it animates the reel image
|
||||
icon. At the completion of the "delay" time in milliseconds, "successor" is
|
||||
called with "param" as a parameter */
|
||||
var delayLeft = Math.abs(delay); // milliseconds left to delay
|
||||
var direction = (inches < 0 ? -1 : 1);
|
||||
var inchesLeft = inches; // inches left to move tape
|
||||
var initiallyReady = this.ready; // remember initial ready state to detect change
|
||||
var lastStamp = performance.now(); // last timestamp for spinDelay
|
||||
|
||||
function spinFinish() {
|
||||
this.timer = 0;
|
||||
if (inchesLeft != 0) {
|
||||
this.spinReel(inchesLeft);
|
||||
}
|
||||
successor.call(this, param);
|
||||
}
|
||||
|
||||
function spinDelay() {
|
||||
var motion;
|
||||
var stamp = performance.now();
|
||||
var interval = stamp - lastStamp;
|
||||
|
||||
if (interval <= 0) {
|
||||
interval = this.spinUpdateInterval/2;
|
||||
if (interval > delayLeft) {
|
||||
interval = delayLeft;
|
||||
}
|
||||
}
|
||||
|
||||
if (initiallyReady && !this.ready) { // drive went not ready
|
||||
inchesLeft = 0;
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, spinFinish);
|
||||
} else {
|
||||
delayLeft -= interval;
|
||||
if (delayLeft > this.spinUpdateInterval) {
|
||||
lastStamp = stamp;
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, spinDelay);
|
||||
} else {
|
||||
this.timer = setCallback(this.mnemonic, this, delayLeft, spinFinish);
|
||||
}
|
||||
|
||||
motion = inchesLeft*interval/delayLeft;
|
||||
if (inchesLeft*direction <= 0) { // inchesLeft crossed zero
|
||||
motion = inchesLeft = 0;
|
||||
} else if (motion*direction <= inchesLeft*direction) {
|
||||
inchesLeft -= motion;
|
||||
} else {
|
||||
motion = inchesLeft;
|
||||
inchesLeft = 0;
|
||||
}
|
||||
|
||||
this.spinReel(motion);
|
||||
}
|
||||
}
|
||||
|
||||
spinDelay.call(this);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.moveTapeTo = function moveTapeTo(index, result) {
|
||||
/* Advances the tape to the specified image index and returns a Promise
|
||||
that will resolve when tape motion completes */
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var len = index - this.imgIndex; // number of words passed
|
||||
var delay = len*this.millisPerWord; // amount of tape spin time
|
||||
|
||||
this.imgIndex = index;
|
||||
this.moveTape(len*this.inchesPerWord, delay, resolve, result);
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.setAtBOT = function setAtBOT(atBOT) {
|
||||
/* Controls the at-Beginning-of-Tape state of the tape drive */
|
||||
@@ -478,6 +372,165 @@ B220MagTapeDrive.prototype.setTapeUnloaded = function setTapeUnloaded() {
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.tapeRewind = function tapeRewind(laneNr, lockout) {
|
||||
/* Rewinds the tape. Makes the drive not-ready and delays for an appropriate
|
||||
amount of time depending on how far up-tape we are. Readies the unit again
|
||||
when the rewind is complete unless lockout is truthy. Returns a Promise that
|
||||
resolves when the rewind completes */
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var lastStamp;
|
||||
|
||||
function rewindFinish() {
|
||||
this.timer = 0;
|
||||
this.tapeState = this.tapeLocal;
|
||||
B220Util.removeClass(this.$$("MTRewindingLight"), "annunciatorLit");
|
||||
this.rewindLock = (lockout ? true : false);
|
||||
this.rwlLamp.set(this.rewindLock ? 1 : 0);
|
||||
this.setTapeReady(!this.rewindLock);
|
||||
resolve(this.setLane(laneNr, null));
|
||||
}
|
||||
|
||||
function rewindDelay() {
|
||||
var inches;
|
||||
var stamp = performance.now();
|
||||
var interval = stamp - lastStamp;
|
||||
|
||||
if (interval <= 0) {
|
||||
interval = this.spinUpdateInterval/2;
|
||||
}
|
||||
if (this.tapeInches <= 0) {
|
||||
this.setAtBOT(true);
|
||||
this.timer = setCallback(this.mnemonic, this, 1000, rewindFinish);
|
||||
} else {
|
||||
inches = interval*this.rewindSpeed;
|
||||
lastStamp = stamp;
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, rewindDelay);
|
||||
this.spinReel(-inches);
|
||||
}
|
||||
}
|
||||
|
||||
function rewindStart() {
|
||||
this.designatedLamp.set(0);
|
||||
lastStamp = performance.now();
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, rewindDelay);
|
||||
}
|
||||
|
||||
if (this.timer) {
|
||||
clearCallback(this.timer);
|
||||
this.timer = 0;
|
||||
}
|
||||
|
||||
if (this.tapeState != this.tapeUnloaded && this.tapeState != this.tapeRewinding) {
|
||||
this.busy = true;
|
||||
this.tapeState = this.tapeRewinding;
|
||||
this.setAtEOT(false);
|
||||
B220Util.addClass(this.$$("MTRewindingLight"), "annunciatorLit");
|
||||
this.timer = setCallback(this.mnemonic, this, 1000, rewindStart);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.spinReel = function spinReel(inches) {
|
||||
/* Rotates the reel image icon an appropriate amount based on the "inches"
|
||||
of tape to be moved. The rotation is limited to this.maxSpinAngle degrees
|
||||
in either direction so that movement remains apparent to the viewer */
|
||||
var circumference = this.reelCircumference*(1 - this.tapeInches/this.maxTapeInches/2);
|
||||
var degrees = inches/circumference*360;
|
||||
|
||||
if (degrees > this.maxSpinAngle) {
|
||||
degrees = this.maxSpinAngle;
|
||||
} else if (degrees < -this.maxSpinAngle) {
|
||||
degrees = -this.maxSpinAngle;
|
||||
}
|
||||
|
||||
this.reelAngle = (this.reelAngle + degrees)%360;
|
||||
this.reelIcon.style.transform = "rotate(" + this.reelAngle.toFixed(0) + "deg)";
|
||||
|
||||
this.tapeInches += inches;
|
||||
if (this.tapeInches < this.maxTapeInches) {
|
||||
this.reelBar.value = this.maxTapeInches - this.tapeInches;
|
||||
} else {
|
||||
this.reelBar.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.moveTape = function moveTape(inches, delay, successor, param) {
|
||||
/* Delays the I/O during tape motion, during which it animates the reel image
|
||||
icon. At the completion of the "delay" time in milliseconds, "successor" is
|
||||
called with "param" as a parameter */
|
||||
var delayLeft = Math.abs(delay); // milliseconds left to delay
|
||||
var direction = (inches < 0 ? -1 : 1);
|
||||
var inchesLeft = inches; // inches left to move tape
|
||||
var initiallyReady = this.ready; // remember initial ready state to detect change
|
||||
var lastStamp = performance.now(); // last timestamp for spinDelay
|
||||
|
||||
function spinFinish() {
|
||||
this.timer = 0;
|
||||
if (inchesLeft != 0) {
|
||||
this.spinReel(inchesLeft);
|
||||
}
|
||||
successor.call(this, param);
|
||||
}
|
||||
|
||||
function spinDelay() {
|
||||
var motion;
|
||||
var stamp = performance.now();
|
||||
var interval = stamp - lastStamp;
|
||||
|
||||
if (interval <= 0) {
|
||||
interval = this.spinUpdateInterval/2;
|
||||
if (interval > delayLeft) {
|
||||
interval = delayLeft;
|
||||
}
|
||||
}
|
||||
|
||||
if (initiallyReady && !this.ready) { // drive went not ready
|
||||
inchesLeft = 0;
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, spinFinish);
|
||||
} else {
|
||||
delayLeft -= interval;
|
||||
if (delayLeft > this.spinUpdateInterval) {
|
||||
lastStamp = stamp;
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, spinDelay);
|
||||
} else {
|
||||
this.timer = setCallback(this.mnemonic, this, delayLeft, spinFinish);
|
||||
}
|
||||
|
||||
motion = inchesLeft*interval/delayLeft;
|
||||
if (inchesLeft*direction <= 0) { // inchesLeft crossed zero
|
||||
motion = inchesLeft = 0;
|
||||
} else if (motion*direction <= inchesLeft*direction) {
|
||||
inchesLeft -= motion;
|
||||
} else {
|
||||
motion = inchesLeft;
|
||||
inchesLeft = 0;
|
||||
}
|
||||
|
||||
this.spinReel(motion);
|
||||
}
|
||||
}
|
||||
|
||||
spinDelay.call(this);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.moveTapeTo = function moveTapeTo(index, result) {
|
||||
/* Advances the tape to the specified image index and returns a Promise
|
||||
that will resolve when tape motion completes */
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var len = index - this.imgIndex; // number of words passed
|
||||
var delay = len*this.millisPerWord; // amount of tape spin time
|
||||
|
||||
this.imgIndex = index;
|
||||
this.moveTape(len*this.inchesPerWord, delay, resolve, result);
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.loadTape = function loadTape() {
|
||||
/* Loads a tape into memory based on selections in the MTLoad window */
|
||||
@@ -967,66 +1020,6 @@ B220MagTapeDrive.prototype.unloadTape = function unloadTape() {
|
||||
win.addEventListener("load", unloadSetup, false);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.tapeRewind = function tapeRewind(laneNr, lockout) {
|
||||
/* Rewinds the tape. Makes the drive not-ready and delays for an appropriate
|
||||
amount of time depending on how far up-tape we are. Readies the unit again
|
||||
when the rewind is complete unless lockout is truthy. Returns a Promise that
|
||||
resolves when the rewind completes */
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var lastStamp;
|
||||
|
||||
function rewindFinish() {
|
||||
this.timer = 0;
|
||||
this.tapeState = this.tapeLocal;
|
||||
B220Util.removeClass(this.$$("MTRewindingLight"), "annunciatorLit");
|
||||
this.rewindLock = (lockout ? true : false);
|
||||
this.rwlLamp.set(this.rewindLock ? 1 : 0);
|
||||
this.setTapeReady(!this.rewindLock);
|
||||
resolve(this.setLane(laneNr, null));
|
||||
}
|
||||
|
||||
function rewindDelay() {
|
||||
var inches;
|
||||
var stamp = performance.now();
|
||||
var interval = stamp - lastStamp;
|
||||
|
||||
if (interval <= 0) {
|
||||
interval = this.spinUpdateInterval/2;
|
||||
}
|
||||
if (this.tapeInches <= 0) {
|
||||
this.setAtBOT(true);
|
||||
this.timer = setCallback(this.mnemonic, this, 1000, rewindFinish);
|
||||
} else {
|
||||
inches = interval*this.rewindSpeed;
|
||||
lastStamp = stamp;
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, rewindDelay);
|
||||
this.spinReel(-inches);
|
||||
}
|
||||
}
|
||||
|
||||
function rewindStart() {
|
||||
this.designatedLamp.set(0);
|
||||
lastStamp = performance.now();
|
||||
this.timer = setCallback(this.mnemonic, this, this.spinUpdateInterval, rewindDelay);
|
||||
}
|
||||
|
||||
if (this.timer) {
|
||||
clearCallback(this.timer);
|
||||
this.timer = 0;
|
||||
}
|
||||
|
||||
if (this.tapeState != this.tapeUnloaded && this.tapeState != this.tapeRewinding) {
|
||||
this.busy = true;
|
||||
this.tapeState = this.tapeRewinding;
|
||||
this.setAtEOT(false);
|
||||
B220Util.addClass(this.$$("MTRewindingLight"), "annunciatorLit");
|
||||
this.timer = setCallback(this.mnemonic, this, 1000, rewindStart);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.LoadBtn_onclick = function LoadBtn_onclick(ev) {
|
||||
/* Handle the click event for the LOAD button */
|
||||
@@ -1217,6 +1210,16 @@ B220MagTapeDrive.prototype.startUpBackward = function startUpBackward(driveState
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.reverseDirection = function reverseDirection(driveState) {
|
||||
/* Generates a delay to allow the drive to stop and reverse direction.
|
||||
Returns a Promise that resolves when the delay is complete */
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
setCallback(this.mnemonic, this, this.turnaroundTime, resolve, driveState);
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.reposition = function reposition(driveState) {
|
||||
/* Reverses tape direction after a forward tape operation and repositions
|
||||
@@ -1245,6 +1248,7 @@ B220MagTapeDrive.prototype.reposition = function reposition(driveState) {
|
||||
switch (state) {
|
||||
case 1: // initial state: skip backwards until erase-gap or BOT flaw-marker words
|
||||
if (lane[x] == this.markerEOB) {
|
||||
--x;
|
||||
state = 2;
|
||||
} else if (lane[x] == this.markerFlaw) {
|
||||
state = 0;
|
||||
@@ -1278,16 +1282,6 @@ B220MagTapeDrive.prototype.reposition = function reposition(driveState) {
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.reverseDirection = function reverseDirection(driveState) {
|
||||
/* Generates a delay to allow the drive to stop and reverse direction.
|
||||
Returns a Promise that resolves when the delay is complete */
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
setCallback(this.mnemonic, this, this.turnaroundTime, resolve, driveState);
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220MagTapeDrive.prototype.scanBlock = function scanBlock(driveState, wordIndex) {
|
||||
/* Scans one block in a forward direction. Terminates with either the control
|
||||
@@ -1318,6 +1312,7 @@ B220MagTapeDrive.prototype.scanBlock = function scanBlock(driveState, wordIndex)
|
||||
switch (state) {
|
||||
case 1: // initial state: skip over flaw and intra-block words
|
||||
if (w == this.markerGap) {
|
||||
++x;
|
||||
state = 2;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1397,6 +1392,7 @@ B220MagTapeDrive.prototype.scanBlock = function scanBlock(driveState, wordIndex)
|
||||
|
||||
case 7: // step through remaining words in the block until normal EOB
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 8;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1452,6 +1448,7 @@ B220MagTapeDrive.prototype.searchForwardBlock = function searchForwardBlock(driv
|
||||
switch (state) {
|
||||
case 1: // initial state: skip over flaw and intra-block words
|
||||
if (w == this.markerGap) {
|
||||
++x;
|
||||
state = 2;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1553,6 +1550,7 @@ B220MagTapeDrive.prototype.searchBackwardBlock = function searchBackwardBlock(dr
|
||||
switch (state) {
|
||||
case 1: // initial state: skip over flaw and magnetic EOT words
|
||||
if (w == this.markerGap) {
|
||||
--x;
|
||||
state = 2;
|
||||
} else if (w == this.markerFlaw) {
|
||||
--x;
|
||||
@@ -1573,6 +1571,7 @@ B220MagTapeDrive.prototype.searchBackwardBlock = function searchBackwardBlock(dr
|
||||
|
||||
case 3: // search for start of block (first prior inter-block gap word)
|
||||
if (w == this.markerGap) {
|
||||
--x;
|
||||
state = 4;
|
||||
} else if (w < 0) {
|
||||
count = 0;
|
||||
@@ -1650,6 +1649,7 @@ B220MagTapeDrive.prototype.readNextBlock = function readNextBlock(driveState, re
|
||||
switch (state) {
|
||||
case 1: // initial state: skip over flaw and intra-block words
|
||||
if (w == this.markerGap) {
|
||||
++x;
|
||||
state = 2;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1774,6 +1774,7 @@ B220MagTapeDrive.prototype.readNextBlock = function readNextBlock(driveState, re
|
||||
|
||||
case 7: // check for proper end-of-block
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 9;
|
||||
} else {
|
||||
state = 0; // block was longer than preface indicated
|
||||
@@ -1784,6 +1785,7 @@ B220MagTapeDrive.prototype.readNextBlock = function readNextBlock(driveState, re
|
||||
|
||||
case 8: // step through remaining words in the block until normal EOB
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 9;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1801,6 +1803,7 @@ B220MagTapeDrive.prototype.readNextBlock = function readNextBlock(driveState, re
|
||||
|
||||
case 10: // step through remaining words in the block until EOB for error
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 11;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1856,6 +1859,7 @@ B220MagTapeDrive.prototype.overwriteBlock = function overwriteBlock(driveState,
|
||||
switch (state) {
|
||||
case 1: // initial state: skip over flaw and intra-block words
|
||||
if (w == this.markerGap) {
|
||||
++x;
|
||||
state = 2;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1945,6 +1949,7 @@ B220MagTapeDrive.prototype.overwriteBlock = function overwriteBlock(driveState,
|
||||
|
||||
case 6: // step through remaining words in the block until normal EOB
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 7;
|
||||
} else {
|
||||
++x;
|
||||
@@ -1962,6 +1967,7 @@ B220MagTapeDrive.prototype.overwriteBlock = function overwriteBlock(driveState,
|
||||
|
||||
case 8: // step through remaining words in the block until EOB for error
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 9;
|
||||
} else {
|
||||
++x;
|
||||
@@ -2168,6 +2174,7 @@ B220MagTapeDrive.prototype.spaceForwardBlock = function spaceForwardBlock(driveS
|
||||
switch (state) {
|
||||
case 1: // initial state: skip over flaw and intra-block words
|
||||
if (w == this.markerGap) {
|
||||
++x;
|
||||
state = 2;
|
||||
} else {
|
||||
++x;
|
||||
@@ -2184,6 +2191,7 @@ B220MagTapeDrive.prototype.spaceForwardBlock = function spaceForwardBlock(driveS
|
||||
|
||||
case 3: // found preface: search for end of block (next erase-gap word)
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 4;
|
||||
} else {
|
||||
++x;
|
||||
@@ -2238,6 +2246,7 @@ B220MagTapeDrive.prototype.spaceBackwardBlock = function spaceBackwardBlock(driv
|
||||
switch (state) {
|
||||
case 1: // initial state: skip over flaw and magnetic EOT words
|
||||
if (w == this.markerGap) {
|
||||
--x;
|
||||
state = 2;
|
||||
} else if (w == this.markerFlaw) {
|
||||
--x;
|
||||
@@ -2342,6 +2351,7 @@ B220MagTapeDrive.prototype.spaceEOIBlock = function spaceEOIBlock(driveState) {
|
||||
|
||||
case 3: // search for end of block (next erase-gap word)
|
||||
if (w == this.markerEOB) {
|
||||
++x;
|
||||
state = 4;
|
||||
} else {
|
||||
++x;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CACHE MANIFEST
|
||||
# retro-220 emulator 0.03c, 2017-11-17 06:15
|
||||
# retro-220 emulator 0.04, 2017-11-19 15:00
|
||||
CACHE:
|
||||
../emulator/B220Processor.js
|
||||
B220.css
|
||||
|
||||
@@ -58,16 +58,22 @@ B220PaperTapePunch.codeXlate = [ // translate internal B220 code to ANSI
|
||||
// so B220 carriage-return (16) translates to "|". To avoid space-expansion
|
||||
// of tabs (26), they are translated to "~". The 02 "blank" code is "_".
|
||||
// Form-feed (15) translates to "^".
|
||||
" ", "?", "_", ".", "\u00A4", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 00-0F
|
||||
"&", "?", "?", "$", "*", "^", "|", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 10-1F
|
||||
"-", "/", "?", ",", "%", "?", "~", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 20-2F
|
||||
"?", "?", "?", "#", "@", "!", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 30-3F
|
||||
"?", "A", "B", "C", "D", "E", "F", "G", "H", "I", "?", "?", "?", "?", "?", "?", // 40-4F
|
||||
"?", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "?", "?", "?", "?", "?", "?", // 50-5F
|
||||
"?", "?", "S", "T", "U", "V", "W", "X", "Y", "Z", "?", "?", "?", "?", "?", "?", // 60-6F
|
||||
"?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 70-7F
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "?", "?", "?", "?", "?", "?", // 80-8F
|
||||
"?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]; // 90-9F
|
||||
" ", "?", "_", ".", "\u00A4", "?", "?", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 00-0F
|
||||
"&", "?", "?", "$", "*", "^", "|", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 10-1F
|
||||
"-", "/", "?", ",", "%", "?", "~", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 20-2F
|
||||
"?", "?", "?", "#", "@", "\\", "?", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 30-3F
|
||||
"?", "A", "B", "C", "D", "E", "F", "G", "H", "I", "!", "!", "!", "!", "!", "!", // 40-4F
|
||||
"?", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "!", "!", "!", "!", "!", "!", // 50-5F
|
||||
"?", "?", "S", "T", "U", "V", "W", "X", "Y", "Z", "!", "!", "!", "!", "!", "!", // 60-6F
|
||||
"?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 70-7F
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "!", "!", "!", "!", "!", // 80-8F
|
||||
"?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 90-9F
|
||||
"!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", // A0-AF
|
||||
"!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", // B0-BF
|
||||
"!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", // C0-CF
|
||||
"!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", // D0-DF
|
||||
"!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", // E0-EF
|
||||
"!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!", "!"]; // F0-FF
|
||||
|
||||
|
||||
/**************************************/
|
||||
@@ -105,6 +111,7 @@ B220PaperTapePunch.prototype.punchEmptyLine = function punchEmptyLine(text) {
|
||||
}
|
||||
paper.lastChild.nodeValue += "\n"; // newline
|
||||
paper.appendChild(this.doc.createTextNode(line));
|
||||
this.punchEOP.scrollIntoView();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
|
||||
@@ -247,7 +247,7 @@ B220PaperTapeReader.prototype.readerOnload = function readerOnload() {
|
||||
body = this.$$("PaperTapeReader")
|
||||
this.remoteSwitch = new ToggleSwitch(body, null, null, "RemoteSwitch",
|
||||
B220PaperTapeReader.offSwitchImage, B220PaperTapeReader.onSwitchImage);
|
||||
this.remoteSwitch.set(prefs.remote);
|
||||
this.remoteSwitch.set(0); // ignore prefs.remote, always initialize as LOCAL
|
||||
|
||||
this.readyLamp = new ColoredLamp(body, null, null, "ReadyLamp", "blueLamp lampCollar", "blueLit");
|
||||
this.setReaderReady(this.remoteSwitch.state != 0);
|
||||
@@ -360,36 +360,30 @@ B220PaperTapeReader.prototype.readTapeChar = function readTapeChar(receiver) {
|
||||
this.window.focus(); // call attention to the tape reader
|
||||
} else {
|
||||
this.busy = false;
|
||||
do {
|
||||
if (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
|
||||
if (x >= bufLength) { // end of buffer -- send finish
|
||||
this.sendTapeChar(0x20, 0x35, receiver);
|
||||
this.setReaderEmpty();
|
||||
} 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 { // translate character and send its code
|
||||
++x;
|
||||
this.sendTapeChar(c, B220PaperTapeReader.xlate220[c], receiver);
|
||||
break; // out of do loop
|
||||
}
|
||||
this.sendTapeChar(0x20, 0x35, receiver);
|
||||
if (x >= bufLength) {
|
||||
this.setReaderEmpty();
|
||||
}
|
||||
} else if (c == 0x0A) { // line feed -- send EOW
|
||||
++x;
|
||||
this.sendTapeChar(0x20, 0x35, receiver);
|
||||
if (x >= bufLength) {
|
||||
this.setReaderEmpty();
|
||||
}
|
||||
} else { // translate character and send its code
|
||||
++x;
|
||||
this.sendTapeChar(c, B220PaperTapeReader.xlate220[c], receiver);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
this.tapeSupplyBar.value = bufLength-x;
|
||||
this.bufIndex = x;
|
||||
|
||||
@@ -76,7 +76,7 @@ B220SystemConfig.defaultConfig = {
|
||||
|
||||
ConsoleOutput: {
|
||||
units: [
|
||||
{type: "TTYA", unitMask: 0x001, remote: 1, format: 0, zeroSuppress: 0, mapMemory: 0,
|
||||
{type: "TTYA", unitMask: 0x001, remote: 1, format: 0, zeroSuppress: 0, mapMemory: 0, printerSpeed: 0,
|
||||
columns: 72, tabs: "9,17,25,33,41,49,57,65,73,81"},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"},
|
||||
@@ -460,6 +460,7 @@ B220SystemConfig.prototype.saveConfigDialog = function saveConfigDialog() {
|
||||
unit.remote = (unit.remote || 0);
|
||||
unit.zeroSuppress = (unit.zeroSuppress || 0);
|
||||
unit.mapMemory = (unit.mapMemory || 0);
|
||||
unit.printerSpeed = (unit.printerSpeed || 0);
|
||||
e = this.$$(prefix + "Format");
|
||||
unit.format = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value);
|
||||
unit.columns = (unit.columns ? unit.columns : 72);
|
||||
|
||||
Reference in New Issue
Block a user