mirror of
https://github.com/pkimpel/retro-220.git
synced 2026-04-13 23:44:23 +00:00
Commit emulator version 1.00.
1. Rework Processor internal timing and throttling mechanism during I/O. 2. Revise Console statistics display, add instruction counter. 3. Correct (again) CFA/CFR instruction when sign is included in field. 4. Correct B-register modification of words during Cardatron and magnetic tape input. 5. Clear Processor alarms on Reset/Transfer. 6. Add links to wiki on index and home pages. 7. Eliminate B220Util CSS class functions in favor of DOM classList methods. 8. Attempt to reproduce "Sundland Beige" color for the panels. 9. Correct formatting of tab stops for B220ConsolePrinter. 10. Reduce Whippet printer speed from 5000 to 1000 cps. 11. Reduce Console update frequency from every 50 to 100 ms; increase lamp glow update factor from 0.25 to 0.75. 12. Allow click of white button below console register lamps in addition to clicking the lamps themselves to toggle the lamp state. 13. Rework the way that white vertical bars are drawn on registers. 14. Allow B220PaperTapeReader to properly send sign-2 alphanumeric words with trailing spaces if the tape image file has been space-trimmed on the right. 15. Clear the paper tape reader view window when loading new tapes. 16. Revise yet again the setCallback() delay deviation adjustment algorithm.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
The Burroughs 220 was a late-1950s, decimal, vacuum-tube, core-memory computer system. Some consider it to be the last of the major vacuum-tube computers.
|
||||
|
||||
The 220 was the follow-on product to the ElectroData/Burroughs Datatron 205. It was initially developed as the ElectroData Datatron 220 but renamed after Burroughs bought ElectroData in 1956. The system was initially released in 1958. It did well with both scientific and commercial applications, but being a vacuum-tube system at the beginning of the transistorized era, was only modestly successful.
|
||||
The 220 was the follow-on product to the ElectroData/Burroughs Datatron 205. It was initially developed as the ElectroData Datatron 220 but renamed after Burroughs acquired ElectroData in 1956. The system was initially released in 1958. It did well with both scientific and commercial applications, but being a vacuum-tube system at the beginning of the transistorized era, was only modestly successful.
|
||||
|
||||
The ElectroData Division of Burroughs went on to create a number of successful systems after the 220, including the B100/200/300 series, the B1700/1800/1900 series, the B2000/3000/4000/V Series, the B5000/5500, and finally the B6000/7000/A Series, which are still produced and sold today as Unisys ClearPath MCP systems.
|
||||
|
||||
@@ -13,7 +13,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/Burroughs-220/ |
|
||||
| Emulator documentation | https://github.com/pkimpel/retro-220/wiki |
|
||||
| Burroughs 205/220 blog | http://datatron.blogspot.com |
|
||||
| Datatron 205 site | http://www.phkimpel.us/ElectroData-205/ |
|
||||
| Documents at bitsavers | http://bitsavers.org/pdf/burroughs/electrodata/220/ |
|
||||
| 220 documents at bitsavers | http://bitsavers.org/pdf/burroughs/electrodata/220/ |
|
||||
| BALGOL compiler listing | http://archive.computerhistory.org/resources/text/Knuth_Don_X4100/PDF_index/k-1-pdf/k-1-u2196-balgol220compiler.pdf |
|
||||
| Datatron 205 site | http://www.phkimpel.us/ElectroData-205/ |
|
||||
|
||||
@@ -84,12 +84,14 @@ function B220Processor(config, devices) {
|
||||
this.IB = new B220Processor.Register(11*4, this, true); // memory Input Buffer
|
||||
|
||||
// Processor throttling control and timing statistics
|
||||
this.asyncTime = 0; // time for processor asynchronous operation during I/O
|
||||
this.execClock = 0; // emulated internal processor clock, ms
|
||||
this.execLimit = 0; // current time slice limit on this.execClock, ms
|
||||
this.instructionCount = 0; // total instructions executed
|
||||
this.opTime = 0; // estimated time for current instruction, ms
|
||||
this.procStart = 0; // Javascript time that the processor started running, ms
|
||||
this.procTime = 0; // total internal running time for processor, ms
|
||||
this.runStamp = 0; // timestamp of last run() slice, ms
|
||||
this.procTimer = 0; // elapsed time that the processor has been running, ms
|
||||
this.procTime = 0; // total emulated running time for processor, ms
|
||||
this.runStamp = 0; // timestamp of start of last time slice, ms
|
||||
this.runTimer = 0; // elapsed run-time timer value, ms
|
||||
this.scheduler = 0; // current setCallback token
|
||||
|
||||
@@ -258,7 +260,7 @@ function B220Processor(config, devices) {
|
||||
* Global Constants *
|
||||
***********************************************************************/
|
||||
|
||||
B220Processor.version = "0.07";
|
||||
B220Processor.version = "1.00";
|
||||
|
||||
B220Processor.tick = 1000/200000; // milliseconds per clock cycle (200KHz)
|
||||
B220Processor.cyclesPerMilli = 1/B220Processor.tick;
|
||||
@@ -716,12 +718,43 @@ B220Processor.prototype.updateLampGlow = function updateLampGlow(beta) {
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.clockIn = function clockIn() {
|
||||
/* Updates the emulated processor clock during asynchronous I/O so that
|
||||
glow averages can be updated based on elapsed time. Also used at the end of
|
||||
and I/O to synchronize the emulated clock with real time */
|
||||
B220Processor.prototype.asyncOff = function asyncOff() {
|
||||
/* Updates the emulated processor clock while operating asynchronously during
|
||||
I/O so that glow averages can be updated based on elapsed time. Also used at
|
||||
the end of and I/O to synchronize the emulated clock with real time */
|
||||
|
||||
this.execClock = performance.now();
|
||||
if (this.asyncTime < 0) {
|
||||
this.asyncTime += performance.now();
|
||||
this.execClock += this.asyncTime;
|
||||
this.procSlack += this.asyncTime; // consider I/O time to be processor slack
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.asyncOn = function asyncOn() {
|
||||
/* Sets this.asyncTime to start asynchronous timing for the processor during I/O */
|
||||
|
||||
if (this.asyncTime >= 0) {
|
||||
this.asyncTime = -performance.now();
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.procOff = function procOff() {
|
||||
/* Stops emulated internal run timing for the processor */
|
||||
|
||||
while (this.procTime < 0) {
|
||||
this.procTime += this.execClock;
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Processor.prototype.procOn = function procOn() {
|
||||
/* Starts emulated internal run timing for the processor */
|
||||
|
||||
while (this.procTime >= 0) {
|
||||
this.procTime -= this.execClock;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2109,7 +2142,8 @@ B220Processor.prototype.compareField = function compareField() {
|
||||
is LOW (UET=1, HIT=0), EQUAL (UET=0, HIT=1), or HIGH (UET=1, HIT=1) with
|
||||
respect to the memory field. Note that the sign digit, if included in the
|
||||
comparison is handled in a very strange fashion -- see the discussion in the
|
||||
220 Operational Characteristics manual for the truly gruesome details */
|
||||
220 Operational Characteristics manual for the truly gruesome details. And
|
||||
no, I didn't get this right the first time, nor the second, nor the third */
|
||||
var adder = 0; // current adder digit
|
||||
var carry = 1; // carry flag defaults to 1, since we're subtracting
|
||||
var compl = 1; // do complement addition by default, since we're subtracting
|
||||
@@ -2161,28 +2195,36 @@ B220Processor.prototype.compareField = function compareField() {
|
||||
// the non-signed digits need to be compared in a signed, algebraic manner,
|
||||
// but the transformed sign digits need to be compared unsigned. Since the
|
||||
// compare is based on a signed subtraction, then if the original sign of
|
||||
// either of the operands is negative, we use the 9s-complement of the
|
||||
// transformed sign digit for that operand, converting the unsigned
|
||||
// compare of the transformed sign digits into a signed one.
|
||||
// either of the operands indicates negative (1, 2, 3), we use the 9s-
|
||||
// complement of the transformed sign digit for that operand, converting
|
||||
// the unsigned compare of the transformed sign digits into a signed one.
|
||||
if (L > s) { // sign digit is included
|
||||
rSign = (rw - rw%0x10000000000)/0x10000000000;
|
||||
dSign = (dw - dw%0x10000000000)/0x10000000000;
|
||||
sign = 1-dSign%2;
|
||||
compl = ((rSign%2)^sign);
|
||||
carry = compl;
|
||||
if (rSign%2) { // complement the transformed sign
|
||||
rSign = 9 - (rSign<8 ? rSign^3 : rSign);
|
||||
} else if (rSign < 8) { // just transform the sign
|
||||
if (rSign < 8) {
|
||||
rSign ^= 3;
|
||||
}
|
||||
|
||||
rw = rw%0x10000000000 + rSign*0x10000000000;
|
||||
if (dSign%2) { // complement the transformed sign
|
||||
dSign = 9 - (dSign<8 ? dSign^3 : dSign);
|
||||
} else if (dSign < 8) {
|
||||
dSign ^= 3; // just transform the sign
|
||||
dSign = (dw - dw%0x10000000000)/0x10000000000;
|
||||
if (dSign < 8) {
|
||||
dSign ^= 3;
|
||||
}
|
||||
|
||||
if (dSign > 2) {
|
||||
sign = 1;
|
||||
} else { // treat as negative
|
||||
sign = 0;
|
||||
dSign = 9-dSign;
|
||||
}
|
||||
|
||||
if (rSign > 2) {
|
||||
compl = sign;
|
||||
} else { // treat as negative
|
||||
compl = 1-sign;
|
||||
rSign = 9-rSign;
|
||||
}
|
||||
|
||||
carry = compl;
|
||||
rw = rw%0x10000000000 + rSign*0x10000000000;
|
||||
dw = dw%0x10000000000 + dSign*0x10000000000;
|
||||
}
|
||||
|
||||
@@ -2698,7 +2740,7 @@ B220Processor.prototype.consoleOutputSign = function consoleOutputSign(printSign
|
||||
var d;
|
||||
var w;
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (this.AST.value) { // if false, we've probably been cleared
|
||||
d = this.bcdAdd(this.CCONTROL, 0x990, 3); // decrement word count
|
||||
this.CCONTROL += d - this.CCONTROL%0x1000;
|
||||
@@ -2719,6 +2761,7 @@ B220Processor.prototype.consoleOutputSign = function consoleOutputSign(printSign
|
||||
this.EWT.set(0);
|
||||
this.PZT.set(d == 2 && !this.HOLDPZTZEROSW);
|
||||
this.PA.set(0x80 + d); // translate numerically
|
||||
this.asyncOn();
|
||||
printSign(this.PA.value, this.boundConsoleOutputChar);
|
||||
}
|
||||
}
|
||||
@@ -2732,14 +2775,16 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar
|
||||
var d;
|
||||
var w;
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (this.AST.value) { // if false, we've probably been cleared
|
||||
if (this.EWT.value) {
|
||||
if (this.CCONTROL%0x1000 < 0x10) {
|
||||
this.asyncOn();
|
||||
printChar(0x35, this.boundConsoleOutputFinished);
|
||||
} else {
|
||||
this.C.inc();
|
||||
this.CADDR = this.C.value%0x10000;
|
||||
this.asyncOn();
|
||||
printChar(0x35, this.boundConsoleOutputSign);
|
||||
}
|
||||
} else if (this.PZT.value) { // Output alphabetically
|
||||
@@ -2753,6 +2798,8 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar
|
||||
if (this.DC.value >= 0x20) {
|
||||
this.EWT.set(1);
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
printChar(d, this.boundConsoleOutputChar);
|
||||
} else { // Output numerically
|
||||
if (this.DPT.value && !this.LEADINGZEROESSW) {
|
||||
@@ -2762,6 +2809,7 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar
|
||||
this.DPT.set(0);
|
||||
this.LT1.set(0); // stop any zero-suppression
|
||||
this.PA.set(0x03); // decimal point code
|
||||
this.asyncOn();
|
||||
printChar(0x03, this.boundConsoleOutputChar);
|
||||
return; // early exit
|
||||
}
|
||||
@@ -2782,6 +2830,8 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar
|
||||
if (this.DC.value >= 0x20) {
|
||||
this.EWT.set(1);
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
printChar(d, this.boundConsoleOutputChar);
|
||||
}
|
||||
}
|
||||
@@ -2791,7 +2841,7 @@ B220Processor.prototype.consoleOutputChar = function consoleOutputChar(printChar
|
||||
B220Processor.prototype.consoleOutputFinished = function consoleOutputFinished() {
|
||||
/* Handles the final cycle of console output */
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (this.AST.value) { // if false, we've probably been cleared
|
||||
this.EWT.set(0);
|
||||
this.ioComplete(true);
|
||||
@@ -2803,7 +2853,8 @@ B220Processor.prototype.consoleInputFinishWord = function consoleInputFinishWord
|
||||
/* 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 */
|
||||
of another word. Note that this routine does not do asyncOff -- that is handled
|
||||
by the caller */
|
||||
var d;
|
||||
var w;
|
||||
|
||||
@@ -2813,7 +2864,10 @@ B220Processor.prototype.consoleInputFinishWord = function consoleInputFinishWord
|
||||
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
|
||||
}
|
||||
|
||||
if (this.COP == 0x05) { // read inverse: permute the sign digit
|
||||
if (this.COP != 0x05) { // read normal: sign digit in normal position
|
||||
w = this.D.value%0x10000000000;
|
||||
d = (this.D.value - w)/0x10000000000;
|
||||
} else { // read inverse: permute the sign digit
|
||||
d = this.D.value%0x10;
|
||||
w = (this.D.value - d)/0x10;
|
||||
this.D.set(w + d*0x10000000000);
|
||||
@@ -2822,9 +2876,6 @@ B220Processor.prototype.consoleInputFinishWord = function consoleInputFinishWord
|
||||
this.ioComplete(true);
|
||||
return; // >>> ALARM ERROR EXIT <<<
|
||||
}
|
||||
} else { // sign digit in normal position
|
||||
w = this.D.value%0x10000000000;
|
||||
d = (this.D.value - w)/0x10000000000;
|
||||
}
|
||||
|
||||
if (this.rDigit & d & 0x08) { // B-modify word before storing
|
||||
@@ -2848,6 +2899,7 @@ B220Processor.prototype.consoleInputFinishWord = function consoleInputFinishWord
|
||||
this.ioComplete(true);
|
||||
} else { // initiate input of another word
|
||||
this.D.set(0);
|
||||
this.asyncOn();
|
||||
if (this.COP == 0x05) {
|
||||
d = this.console.inputUnitSelect(this.selectedUnit, this.boundConsoleInputInitiateInverse);
|
||||
} else {
|
||||
@@ -2869,7 +2921,7 @@ B220Processor.prototype.consoleInputInitiateNormal = function consoleInputInitia
|
||||
should be translated numerically or alphanumerically */
|
||||
var code = result.code;
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (this.AST.value) { // if false, we've probably been cleared
|
||||
this.E.set(this.CADDR);
|
||||
this.C.inc();
|
||||
@@ -2886,15 +2938,18 @@ B220Processor.prototype.consoleInputInitiateNormal = function consoleInputInitia
|
||||
case 0x82: // sign=2, set alpha translation
|
||||
this.PZT.set(!this.HOLDPZTZEROSW);
|
||||
this.D.set(2);
|
||||
this.asyncOn();
|
||||
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);
|
||||
this.asyncOn();
|
||||
result.readChar(this.boundConsoleInputReceiveChar);
|
||||
} else if (code == 0) { // we'll take a space as a zero
|
||||
this.D.set(0);
|
||||
this.asyncOn();
|
||||
result.readChar(this.boundConsoleInputReceiveChar);
|
||||
} else { // sign is non-numeric -- invalid
|
||||
this.D.set(0);
|
||||
@@ -2913,7 +2968,7 @@ B220Processor.prototype.consoleInputInitiateInverse = function consoleInputIniti
|
||||
rotates the sign digit into the D register, and sets PZT for numeric translation */
|
||||
var code = result.code;
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (this.AST.value) { // if false, we've probably been cleared
|
||||
this.E.set(this.CADDR);
|
||||
this.C.inc();
|
||||
@@ -2931,9 +2986,11 @@ B220Processor.prototype.consoleInputInitiateInverse = function consoleInputIniti
|
||||
this.PZT.set(0);
|
||||
if ((code & 0xF0) == 0x80) {// it's a numeric code -- okay
|
||||
this.D.set(code%0x10);
|
||||
this.asyncOn();
|
||||
result.readChar(this.boundConsoleInputReceiveChar);
|
||||
} else if (code == 0) { // we'll take a space as a zero
|
||||
this.D.set(0);
|
||||
this.asyncOn();
|
||||
result.readChar(this.boundConsoleInputReceiveChar);
|
||||
} else { // digit is non-numeric -- invalid
|
||||
this.D.set(0);
|
||||
@@ -2956,7 +3013,7 @@ B220Processor.prototype.consoleInputReceiveChar = function consoleInputReceiveCh
|
||||
var sign; // register sign digit
|
||||
var word; // register word less sign
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (this.AST.value) { // if false, we've probably been cleared
|
||||
switch (code) {
|
||||
case 0x17: // invalid character/parity error
|
||||
@@ -2969,13 +3026,16 @@ B220Processor.prototype.consoleInputReceiveChar = function consoleInputReceiveCh
|
||||
default: // anything else, accumulate digits in word
|
||||
if (this.PZT.value) { // alphanumeric translation
|
||||
this.D.set((this.D.value % 0x1000000000)*0x100 + code);
|
||||
this.asyncOn();
|
||||
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);
|
||||
this.asyncOn();
|
||||
result.readChar(this.boundConsoleInputReceiveChar);
|
||||
} else if (code == 0) { // we'll take a space as a zero
|
||||
this.D.set((this.D.value % 0x10000000000)*0x10);
|
||||
this.asyncOn();
|
||||
result.readChar(this.boundConsoleInputReceiveChar);
|
||||
} else { // code is non-numeric -- invalid
|
||||
this.setPaperTapeCheck(1);
|
||||
@@ -2997,7 +3057,7 @@ B220Processor.prototype.cardatronOutputWord = function cardatronOutputWord() {
|
||||
Cardatron Control Unit. Returns a negative number to stop transfer */
|
||||
var word;
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (!this.AST.value) { // we've probably been cleared
|
||||
word = -1;
|
||||
} else if (this.MET.value) { // previous memory access error
|
||||
@@ -3013,6 +3073,7 @@ B220Processor.prototype.cardatronOutputWord = function cardatronOutputWord() {
|
||||
this.execClock += 0.117; // time for full-word transfer
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
return word;
|
||||
};
|
||||
|
||||
@@ -3036,7 +3097,7 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
var returnCode = 0; // default is to continue receiving
|
||||
var sign; // D-register sign digit
|
||||
|
||||
this.clockIn();
|
||||
this.asyncOff();
|
||||
if (!this.AST.value) { // we've probably been cleared
|
||||
returnCode = -1;
|
||||
} else if (word < 0) {
|
||||
@@ -3046,6 +3107,7 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
returnCode = -1;
|
||||
} else if (this.MET.value) {
|
||||
// Memory error has occurred: just ignore further data from Cardatron
|
||||
this.asyncOn();
|
||||
} else {
|
||||
// Full word accumulated -- process it and initialize for the next word
|
||||
this.D.set(word);
|
||||
@@ -3064,6 +3126,8 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
if (!this.MET.value) {
|
||||
this.E.dec(); // decrement memory address for next word
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
break;
|
||||
|
||||
case 6: // sign is 6, 7: execute control word
|
||||
@@ -3074,6 +3138,8 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
if (!this.MET.value) {
|
||||
this.E.dec(); // decrement memory address for next word
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
} else { // input control words are executed
|
||||
this.IB.set(this.D.value); // move word to IB for use by fetch()
|
||||
this.ioComplete(false); // terminate I/O but do not restart Processor yet
|
||||
@@ -3088,7 +3154,7 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
if (!(this.rDigit & 0x08)) { // no B-register modification
|
||||
this.IB.set(this.D.value);
|
||||
} else { // add B to low-order four digits of word
|
||||
word = word - word%0x100000 + this.bcdAdd(word, this.B.value, 4);
|
||||
word = word - word%0x10000 + this.bcdAdd(word, this.B.value, 4);
|
||||
this.C10.set(0); // reset carry toggle
|
||||
this.IB.set((sign%2)*0x10000000000 + word);
|
||||
}
|
||||
@@ -3096,6 +3162,8 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
if (!this.MET.value) {
|
||||
this.E.dec(); // decrement memory address for next word
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
break;
|
||||
} // switch sign
|
||||
|
||||
@@ -3113,10 +3181,10 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
|
||||
B220Processor.prototype.magTapeComplete = function magTapeComplete(control, word) {
|
||||
/* Call-back routine to signal completion of a magnetic tape operation.
|
||||
If this.AST is false, does nothing, as we have probably either been cleared
|
||||
or the Reset/Transfer switch has been activated. Otherwsie, if "control" is
|
||||
or the Reset/Transfer switch has been activated. Otherwise, if "control" is
|
||||
true, the contents of "word" are processed as a tape control word and an
|
||||
appropriate branch is set up. Unconditionally terminates the tape I/O
|
||||
instruction */
|
||||
instruction. asyncOff() will be done by ioComplete() */
|
||||
var aaaa = 0; // address where C & P will be stored
|
||||
var bbbb = 0; // address to load into P
|
||||
|
||||
@@ -3153,11 +3221,11 @@ B220Processor.prototype.magTapeSendWord = function magTapeSendWord(initialFetch)
|
||||
occurs, and the I/O must be aborted. Returns the BCD memory word otherwise */
|
||||
var result; // return value
|
||||
|
||||
this.asyncOff();
|
||||
if (!this.AST.value) {
|
||||
result = -1; // we've probably been cleared
|
||||
} else {
|
||||
if (initialFetch) {
|
||||
this.clockIn();
|
||||
this.CCONTROL = this.CADDR; // copy C address into control digits
|
||||
}
|
||||
|
||||
@@ -3170,10 +3238,10 @@ B220Processor.prototype.magTapeSendWord = function magTapeSendWord(initialFetch)
|
||||
} else {
|
||||
result = this.IB.value;
|
||||
this.D.set(result);
|
||||
this.execClock += 0.480; // time to transfer one word to tape
|
||||
}
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -3188,11 +3256,11 @@ B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initial
|
||||
var result = 0; // return value
|
||||
var sign; // sign digit
|
||||
|
||||
this.asyncOff();
|
||||
if (!this.AST.value) {
|
||||
result = -1; // we've probably been cleared
|
||||
} else {
|
||||
if (initialStore) {
|
||||
this.clockIn();
|
||||
this.CCONTROL = this.CADDR; // copy C address into control digits
|
||||
}
|
||||
|
||||
@@ -3204,7 +3272,7 @@ B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initial
|
||||
sign = (word - word%0x10000000000)/0x10000000000;
|
||||
if (sign & 0x08) { // this word is to be B-adjusted
|
||||
word = (sign&0x07)*0x10000000000 + word%0x10000000000 -
|
||||
word%0x100000 + this.bcdAdd(word, this.B.value, 4);
|
||||
word%0x10000 + this.bcdAdd(word, this.B.value, 4);
|
||||
this.C10.set(0); // reset carry toggle
|
||||
}
|
||||
}
|
||||
@@ -3213,11 +3281,10 @@ B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initial
|
||||
this.writeMemory();
|
||||
if (this.MET.value) { // invalid address
|
||||
result = -1;
|
||||
} else {
|
||||
this.execClock += 0.480; // time to transfer one word to tape
|
||||
}
|
||||
}
|
||||
|
||||
this.asyncOn();
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -3301,6 +3368,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
this.COP = (w%0x1000000 - w%0x10000)/0x10000; // C register operation code
|
||||
this.CADDR = w%0x10000; // C register operand address
|
||||
this.opTime = 0; // clear the current instruction timer
|
||||
++this.instructionCount;
|
||||
|
||||
if (this.OFT.value && this.HCT.value && this.COP != 0x31) {
|
||||
this.setStop(); // if overflow and SOH and instruction is not BOF, stop
|
||||
@@ -3318,7 +3386,6 @@ B220Processor.prototype.execute = function execute() {
|
||||
break;
|
||||
|
||||
case 0x01: //--------------------- NOP No operation
|
||||
// do nothing
|
||||
this.opTime = 0.010;
|
||||
this.operationComplete();
|
||||
break;
|
||||
@@ -3414,6 +3481,7 @@ B220Processor.prototype.execute = function execute() {
|
||||
break;
|
||||
|
||||
case 0x08: //--------------------- KAD Keyboard add
|
||||
this.opTime = 0.005;
|
||||
this.D.set(0);
|
||||
this.setStop();
|
||||
this.operationComplete();
|
||||
@@ -3588,8 +3656,8 @@ B220Processor.prototype.execute = function execute() {
|
||||
break;
|
||||
|
||||
case 0x30: //--------------------- BUN Branch, unconditionally
|
||||
this.P.set(this.CADDR);
|
||||
this.opTime = 0.035;
|
||||
this.P.set(this.CADDR);
|
||||
this.operationComplete();
|
||||
break;
|
||||
|
||||
@@ -4211,10 +4279,8 @@ B220Processor.prototype.ioComplete = function ioComplete(restart) {
|
||||
resume automatic operation */
|
||||
|
||||
this.AST.set(0);
|
||||
this.clockIn();
|
||||
while (this.procTime < 0) {
|
||||
this.procTime += this.execClock;
|
||||
}
|
||||
this.asyncOff();
|
||||
this.procOff();
|
||||
|
||||
this.operationComplete();
|
||||
if (restart && this.RUT.value) {
|
||||
@@ -4227,6 +4293,7 @@ B220Processor.prototype.ioInitiate = function ioInitiate() {
|
||||
/* Initiates asynchronous mode of the processor for I/O */
|
||||
|
||||
this.AST.set(1);
|
||||
this.asyncOn();
|
||||
this.updateLampGlow(0); // update the console lamps
|
||||
this.execLimit = 0; // kill the run() loop
|
||||
};
|
||||
@@ -4305,7 +4372,7 @@ B220Processor.prototype.schedule = function schedule() {
|
||||
If the processor remains active, this routine will reschedule itself after
|
||||
an appropriate delay, thereby throttling the performance and allowing other
|
||||
modules to share the single Javascript execution thread */
|
||||
var delayTime; // delay from/until next run() for this processor, ms
|
||||
var delayTime = 0; // delay from/until next run() for this processor, ms
|
||||
var stamp = performance.now(); // ending time for the delay and the run() call, ms
|
||||
|
||||
this.scheduler = 0;
|
||||
@@ -4315,7 +4382,7 @@ B220Processor.prototype.schedule = function schedule() {
|
||||
delayTime = stamp - this.delayLastStamp;
|
||||
this.procSlack += delayTime;
|
||||
|
||||
// Compute the exponential weighted average of scheduling delay.
|
||||
// Compute the exponential weighted average of scheduling delay deviation.
|
||||
this.delayDeltaAvg = (delayTime - this.delayRequested)*B220Processor.delayAlpha +
|
||||
this.delayDeltaAvg*B220Processor.delayAlpha1;
|
||||
this.procSlackAvg = delayTime*B220Processor.slackAlpha +
|
||||
@@ -4323,9 +4390,8 @@ B220Processor.prototype.schedule = function schedule() {
|
||||
}
|
||||
|
||||
// Execute the time slice.
|
||||
this.procTime -= this.execClock; // prepare to accumulate internal processor time
|
||||
this.runStamp = stamp; // starting clock time for time slice
|
||||
|
||||
this.runStamp = stamp; // starting clock time for time slice
|
||||
this.procOn(); // prepare to accumulate internal processor time
|
||||
this.run();
|
||||
|
||||
stamp = performance.now();
|
||||
@@ -4333,15 +4399,16 @@ B220Processor.prototype.schedule = function schedule() {
|
||||
this.procRunAvg*B220Processor.slackAlpha1;
|
||||
|
||||
// Determine what to do next.
|
||||
this.runStamp = stamp; // DEBUG: for DiagMonitor use only.
|
||||
if (!this.RUT.value) {
|
||||
// Processor is stopped, just inhibit delay averaging on next call and exit.
|
||||
this.delayLastStamp = 0;
|
||||
this.procTime += this.execClock; // accumulate internal processor time for the slice
|
||||
this.procOff(); // accumulate internal processor time for the slice
|
||||
} else if (this.AST.value) {
|
||||
// Processor is idle during I/O, but still accumulating clocks.
|
||||
// Processor is idle during I/O, but still accumulating clocks, so no procOff().
|
||||
this.delayLastStamp = 0;
|
||||
} else {
|
||||
this.procTime += this.execClock; // accumulate internal processor time for the slice
|
||||
this.procOff(); // accumulate internal processor time for the slice
|
||||
|
||||
// The processor is still running, so schedule next time slice after a
|
||||
// throttling delay. delayTime is the number of milliseconds the
|
||||
@@ -4355,7 +4422,7 @@ B220Processor.prototype.schedule = function schedule() {
|
||||
delayTime = this.execClock - stamp;
|
||||
this.delayRequested = delayTime;
|
||||
this.delayLastStamp = stamp;
|
||||
this.scheduler = setCallback(this.mnemonic, this, delayTime, this.schedule);
|
||||
this.scheduler = setCallback(this.mnemonic, this, delayTime, schedule);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4370,12 +4437,17 @@ B220Processor.prototype.start = function start() {
|
||||
!this.TAT.value && !this.CRT.value &&
|
||||
!this.PAT.value && !this.HAT.value &&
|
||||
!this.systemNotReady.value && !this.computerNotReady.value) {
|
||||
this.procStart = stamp;
|
||||
this.execClock = stamp;
|
||||
this.asyncTime = 0;
|
||||
this.delayLastStamp = 0;
|
||||
this.delayRequested = 0;
|
||||
this.RUT.set(1);
|
||||
|
||||
// Start the processor timer
|
||||
while (this.procTimer >= 0) {
|
||||
this.procTimer -= stamp;
|
||||
}
|
||||
|
||||
// Start the run timer
|
||||
while (this.runTimer >= 0) {
|
||||
this.runTimer -= stamp;
|
||||
@@ -4398,14 +4470,19 @@ B220Processor.prototype.stop = function stop() {
|
||||
this.AST.set(0);
|
||||
|
||||
// Stop the timers
|
||||
this.clockIn();
|
||||
while (this.procTime < 0) {
|
||||
this.procTime += this.execClock;
|
||||
}
|
||||
this.asyncOff();
|
||||
this.procOff();
|
||||
|
||||
// Stop the run timer
|
||||
while (this.runTimer < 0) {
|
||||
this.runTimer += stamp;
|
||||
}
|
||||
|
||||
// Stop the processor timer
|
||||
while (this.procTimer < 0) {
|
||||
this.procTimer += stamp;
|
||||
}
|
||||
|
||||
this.updateLampGlow(1); // freeze state in the lamps
|
||||
if (this.scheduler) {
|
||||
clearCallback(this.scheduler);
|
||||
@@ -4485,6 +4562,7 @@ B220Processor.prototype.resetRunTimer = function resetRunTimer() {
|
||||
/* Resets the elapsed run-time timer to zero */
|
||||
|
||||
if (this.poweredOn) {
|
||||
this.instructionCount = 0;
|
||||
if (this.runTimer < 0) { // it's running, adjust its bias
|
||||
this.runTimer = -performance.now();
|
||||
} else { // it's stopped, just zero it
|
||||
@@ -4500,6 +4578,14 @@ B220Processor.prototype.resetTransfer = function resetTransfer() {
|
||||
when running */
|
||||
|
||||
if (this.poweredOn) {
|
||||
this.digitCheckAlarm.set(0);
|
||||
this.ALT.set(0);
|
||||
this.MET.set(0);
|
||||
this.TAT.set(0);
|
||||
this.CRT.set(0);
|
||||
this.PAT.set(0);
|
||||
this.HAT.set(0);
|
||||
|
||||
this.E.set(0x0000);
|
||||
this.readMemory();
|
||||
this.IB.set(this.IB.value - this.IB.value % 0x100000000 +
|
||||
@@ -4536,8 +4622,9 @@ B220Processor.prototype.powerUp = function powerUp() {
|
||||
if (!this.poweredOn) {
|
||||
this.clear();
|
||||
this.poweredOn = 1;
|
||||
this.procTime = this.runTimer = 0;
|
||||
this.procSlack = this.procSlackAvg = this.procRunAvg = 0;
|
||||
this.procTimer = this.runTimer = this.instructionCount = 0;
|
||||
this.procTime = this.procSlack = 0;
|
||||
this.procSlackAvg = this.procRunAvg = 0;
|
||||
this.delayDeltaAvg = this.delayRequested = 0;
|
||||
|
||||
this.console = this.devices.ControlConsole;
|
||||
|
||||
@@ -29,11 +29,15 @@
|
||||
<ul>
|
||||
<li><a href="./webUI/B220.html">220 Emulator Home Page</a>
|
||||
<br>The home page from which you can start the emulator and open the control panels.
|
||||
Please see the <a href="https://github.com/pkimpel/retro-220/wiki/GettingStarted">Getting Started</a> and <a href="https://github.com/pkimpel/retro-220/wiki/ConfiguringTheEmulator">Configuring the Emulator</a> wiki pages for information on setting up and running the emulator.
|
||||
|
||||
<!--
|
||||
<li><a href="./webSite/HelpMenu.html">Help & Getting Started</a>
|
||||
<br>A menu of information resources to assist you in setting up and operating the emulator.
|
||||
-->
|
||||
-->
|
||||
|
||||
<li><a href="https://github.com/pkimpel/retro-220/wiki">Project Wiki</a>
|
||||
<br>A set of help pages to assist you in setting up and operating the emulator.
|
||||
|
||||
<li><a href="https://github.com/pkimpel/retro-220/">Open Source Project</a>
|
||||
<br>Source code, documentation, and other developer resources for the retro-220 emulator project at GitHub.
|
||||
@@ -65,7 +69,7 @@
|
||||
Copyright (c) 2017, Paul Kimpel • Licensed under the <a href="LICENSE.txt">MIT License</a>
|
||||
</div>
|
||||
<div id=lastModDiv>Revised
|
||||
2017-11-19
|
||||
2018-07-16
|
||||
</div>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -66,11 +66,16 @@
|
||||
<td id=StatusMsg>
|
||||
<td class=rj><a href="http://datatron.blogspot.com/" target="_blank">
|
||||
Burroughs 205 & 220 Blog</a>
|
||||
<tr>
|
||||
<td><a href="https://github.com/pkimpel/retro-220/wiki" target="_blank">
|
||||
Project Wiki</a>
|
||||
<td class=center>
|
||||
<td class=rj>
|
||||
</table>
|
||||
|
||||
<div id=CenteredBody>
|
||||
<img id=B220Image src="./resources/B220-Site.jpg"
|
||||
alt="Burroughs 220 System, ca. 1960">
|
||||
alt="Burroughs 220 System, Michigan National Bank, ca. 1960">
|
||||
<br>
|
||||
<button id=StartUpBtn>
|
||||
Start the Emulator
|
||||
|
||||
@@ -121,9 +121,8 @@ window.addEventListener("load", function() {
|
||||
if (!window.JSON) {missing += ", JSON"}
|
||||
if (!window.localStorage) {missing += ", LocalStorage"}
|
||||
if (!window.indexedDB) {missing += ", IndexedDB"}
|
||||
if (!window.postMessage) {missing += ", window.postMessage"}
|
||||
if (!(window.performance && "now" in performance)) {missing += ", performance.now"}
|
||||
if (!window.Promise) {missing += ", Promise"}
|
||||
if (!(window.performance && "now" in performance)) {missing += ", performance.now"}
|
||||
|
||||
if (missing.length == 0) {
|
||||
return true;
|
||||
@@ -147,7 +146,7 @@ window.addEventListener("load", function() {
|
||||
document.getElementById("ConfigureBtn").disabled = false;
|
||||
document.getElementById("ConfigureBtn").addEventListener("click", configureSystem, false);
|
||||
|
||||
document.getElementById("StatusMsg").textContent = "The Application Cache feature has been deimplemented";
|
||||
clearStatusMsg(30);
|
||||
//document.getElementById("StatusMsg").textContent = "The Application Cache feature has been deimplemented";
|
||||
//clearStatusMsg(30);
|
||||
}
|
||||
}, false);
|
||||
|
||||
@@ -79,7 +79,7 @@ function B220CardatronInput(mnemonic, unitIndex, config) {
|
||||
/**************************************/
|
||||
|
||||
B220CardatronInput.prototype.eolRex = /([^\n\r\f]*)((:?\r[\n\f]?)|\n|\f)?/g;
|
||||
B220CardatronInput.prototype.cardsPerMinute = 240; // IBM Type 087/089 collator
|
||||
B220CardatronInput.prototype.cardsPerMinute = 240; // 240=IBM Type 087/089 collator, 100=Type 523 Summary Punch
|
||||
B220CardatronInput.prototype.eodBias = -0x900000000000; // signals end-of-data to Processor
|
||||
|
||||
B220CardatronInput.trackSize = 319; // digits
|
||||
@@ -184,12 +184,12 @@ B220CardatronInput.prototype.setReaderReady = function setReaderReady(ready) {
|
||||
|
||||
this.$$("CIFileSelector").disabled = ready;
|
||||
if (ready && !this.ready) {
|
||||
B220Util.addClass(this.$$("CIStartBtn"), "greenLit")
|
||||
B220Util.removeClass(this.$$("CIStopBtn"), "redLit");
|
||||
this.$$("CIStartBtn").classList.add("greenLit")
|
||||
this.$$("CIStopBtn").classList.remove("redLit");
|
||||
this.ready = true;
|
||||
} else if (this.ready && !ready) {
|
||||
B220Util.removeClass(this.$$("CIStartBtn"), "greenLit")
|
||||
B220Util.addClass(this.$$("CIStopBtn"), "redLit");
|
||||
this.$$("CIStartBtn").classList.remove("greenLit")
|
||||
this.$$("CIStopBtn").classList.add("redLit");
|
||||
this.ready = false;
|
||||
}
|
||||
};
|
||||
@@ -444,7 +444,7 @@ B220CardatronInput.prototype.determineFormatBand = function determineFormatBand(
|
||||
case "7":
|
||||
format = 7;
|
||||
break;
|
||||
case "`": // 1-8 punch
|
||||
case "\`": // 1-8 punch
|
||||
format = 1;
|
||||
this.noReload = true;
|
||||
this.setFormatLockout(true);
|
||||
@@ -464,7 +464,7 @@ B220CardatronInput.prototype.determineFormatBand = function determineFormatBand(
|
||||
this.noReload = true;
|
||||
this.setFormatLockout(true);
|
||||
break;
|
||||
case "'": // 5-8 punch
|
||||
case "\'": // 5-8 punch
|
||||
case "|": // translates to a 5-numeric digit
|
||||
format = 5;
|
||||
this.noReload = true;
|
||||
|
||||
@@ -87,8 +87,7 @@
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
left: 384px;
|
||||
right: 0;
|
||||
width: calc(100% - 346px);
|
||||
width: calc(100% - 394px);
|
||||
height: 18px;
|
||||
border: 1px solid white}
|
||||
|
||||
|
||||
@@ -209,12 +209,12 @@ B220CardatronOutput.prototype.setDeviceReady = function setDeviceReady(ready) {
|
||||
|
||||
this.runoutSupplyCount = 0;
|
||||
if (ready && !this.ready) {
|
||||
B220Util.addClass(this.$$("COStartBtn"), "greenLit")
|
||||
B220Util.removeClass(this.$$("COStopBtn"), "redLit");
|
||||
this.$$("COStartBtn").classList.add("greenLit")
|
||||
this.$$("COStopBtn").classList.remove("redLit");
|
||||
this.ready = true;
|
||||
} else if (!ready && this.ready) {
|
||||
B220Util.removeClass(this.$$("COStartBtn"), "greenLit")
|
||||
B220Util.addClass(this.$$("COStopBtn"), "redLit");
|
||||
this.$$("COStartBtn").classList.remove("greenLit")
|
||||
this.$$("COStopBtn").classList.add("redLit");
|
||||
this.ready = false;
|
||||
}
|
||||
};
|
||||
@@ -224,7 +224,7 @@ B220CardatronOutput.prototype.runoutSupply = function runoutSupply(ev) {
|
||||
/* Handles an event to clear the supply from the printer/punch */
|
||||
|
||||
this.runoutSupplyCount = 0;
|
||||
B220Util.removeClass(this.$$("COEndOfSupplyBtn"), "redLit");
|
||||
this.$$("COEndOfSupplyBtn").classList.remove("redLit");
|
||||
this.supplyMeter.value = this.supplyLeft = this.maxSupplyLines;
|
||||
this.groupLinesLeft = 0;
|
||||
while (this.supply.firstChild) {
|
||||
@@ -251,7 +251,7 @@ B220CardatronOutput.prototype.copySupply = function copySupply(ev) {
|
||||
barGroup = barGroup.nextSibling;
|
||||
}
|
||||
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Snapshot",
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", "",
|
||||
"scrollbars,resizable,width=500,height=500",
|
||||
this, function(ev) {
|
||||
var doc = ev.target;
|
||||
@@ -333,10 +333,10 @@ B220CardatronOutput.prototype.printLine = function printLine(text, spaceBefore)
|
||||
|
||||
this.appendLine(text || "\xA0");
|
||||
if (this.supplyLeft > 0) {
|
||||
this.supplyMeter.value = this.supplyLeft -= 1;
|
||||
this.supplyMeter.value = (this.supplyLeft -= 1);
|
||||
} else {
|
||||
this.setDeviceReady(false);
|
||||
B220Util.addClass(this.$$("COEndOfSupplyBtn"), "redLit");
|
||||
this.$$("COEndOfSupplyBtn").classList.add("redLit");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -430,12 +430,12 @@ B220CardatronOutput.prototype.initiateWrite = function initiateWrite() {
|
||||
}
|
||||
|
||||
// Convert to ASCII line image and determine carriage control
|
||||
line = String.fromCharCode.apply(null, this.lineBuffer.subarray(lx, this.lineWidth+lx));
|
||||
line = String.fromCharCode.apply(null, this.lineBuffer.subarray(lx, this.lineWidth+lx))
|
||||
.replace(this.rtrimRex, '');
|
||||
if (this.useAlgolGlyphs) {
|
||||
line = B220Util.xlateASCIIToAlgol(line.replace(this.rtrimRex, ''));
|
||||
} else {
|
||||
line = line.replace(this.rtrimRex, '');
|
||||
line = B220Util.xlateASCIIToAlgol(line);
|
||||
}
|
||||
|
||||
switch (this.cDigit) {
|
||||
case 1: // Relay 1 (eject page after printing)
|
||||
case 9: // same as 1
|
||||
@@ -544,10 +544,14 @@ B220CardatronOutput.prototype.COStopBtn_onClick = function COStopBtn_onClick(ev)
|
||||
|
||||
/**************************************/
|
||||
B220CardatronOutput.prototype.CORunoutSupplyBtn_onClick = function CORunoutSupplyBtn_onClick(ev) {
|
||||
/* Handle the click event for the Skip To Heading button */
|
||||
/* Handle the click event for the Skip To Heading or Runout Supply button */
|
||||
|
||||
if (!this.ready) {
|
||||
this.printLine("", -1);
|
||||
if (this.atTopOfForm) {
|
||||
this.appendLine("\xA0"); // force start of a new greenbar group
|
||||
}
|
||||
|
||||
this.skipToChannel();
|
||||
this.endOfSupply.scrollIntoView();
|
||||
if (++this.runoutSupplyCount >= 3) {
|
||||
if (this.window.confirm("Do you want to clear the output from the device?")) {
|
||||
@@ -569,7 +573,7 @@ B220CardatronOutput.prototype.COEndOfSupplyBtn_onClick = function COEndOfSupplyB
|
||||
|
||||
if (this.supplyLeft <= 0 && !this.ready) {
|
||||
this.runoutSupplyCount = 0;
|
||||
B220Util.removeClass(this.$$("COEndOfSupplyBtn"), "redLit");
|
||||
this.$$("COEndOfSupplyBtn").classList.remove("redLit");
|
||||
this.setDeviceReady(true);
|
||||
}
|
||||
};
|
||||
@@ -651,8 +655,8 @@ B220CardatronOutput.prototype.COSetZSBtn_onClick = function COSetZSBtn_onClick(e
|
||||
zsCol = tron.parseZeroSuppressList(text, win);
|
||||
if (zsCol !== null) {
|
||||
tron.zsCol = zsCol;
|
||||
B220Util.removeClass(tron.$$("COSetZSBtn"), (zsCol.length > 0 ? "blackButton1" : "greenButton1"));
|
||||
B220Util.addClass(tron.$$("COSetZSBtn"), (zsCol.length > 0 ? "greenButton1" : "blackButton1"));
|
||||
tron.$$("COSetZSBtn").classList.remove(zsCol.length > 0 ? "blackButton1" : "greenButton1");
|
||||
tron.$$("COSetZSBtn").classList.add(zsCol.length > 0 ? "greenButton1" : "blackButton1");
|
||||
|
||||
// Store the new list in the system configuration object
|
||||
text = zsCol.join(",");
|
||||
@@ -758,8 +762,8 @@ B220CardatronOutput.prototype.deviceOnLoad = function deviceOnLoad(ev) {
|
||||
if (zsCol !== null) {
|
||||
this.zsCol = zsCol;
|
||||
if (zsCol.length > 0) {
|
||||
B220Util.removeClass(this.$$("COSetZSBtn"), (zsCol.length > 0 ? "blackButton1" : "greenButton1"));
|
||||
B220Util.addClass(this.$$("COSetZSBtn"), (zsCol.length > 0 ? "greenButton1" : "blackButton1"));
|
||||
this.$$("COSetZSBtn").classList.remove(zsCol.length > 0 ? "blackButton1" : "greenButton1");
|
||||
this.$$("COSetZSBtn").classList.add(zsCol.length > 0 ? "greenButton1" : "blackButton1");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,6 @@ DIV.neonLamp {
|
||||
height: 16px;
|
||||
font-size: 4px;
|
||||
border-radius: 50%;
|
||||
/* border: 2px solid #999; */
|
||||
background-image: radial-gradient(circle, #999, #333)}
|
||||
DIV.neonLit1 {
|
||||
background-image: radial-gradient(circle, #A85, #444)}
|
||||
@@ -308,7 +307,7 @@ DIV.blackControlKnobBottomCaption {
|
||||
|
||||
DIV.panelSurface {
|
||||
position: absolute;
|
||||
background-color: #D8C5BC; /* was #E4DDCD; putty #EDEAE8; */
|
||||
background-color: #EADAD1; /* was #D8C5BC; #E4DDCD; putty #EDEAE8; */
|
||||
color: black}
|
||||
|
||||
DIV.panelRegister {
|
||||
@@ -374,8 +373,8 @@ DIV.panelTopCaption {
|
||||
top: 0.75em;
|
||||
left: 4px;
|
||||
right: 4px;
|
||||
border-top: 2px solid #D8C5BC;
|
||||
color: #D8C5BC}
|
||||
border-top: 2px solid #EADAD1;
|
||||
color: #EADAD1}
|
||||
|
||||
SPAN.panelTopCaptionSpan {
|
||||
position: relative;
|
||||
@@ -383,7 +382,7 @@ SPAN.panelTopCaptionSpan {
|
||||
font-size: 7px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
color: #D8C5BC;
|
||||
color: #EADAD1;
|
||||
background-color: #333}
|
||||
|
||||
DIV.panelRegCaption {
|
||||
@@ -505,7 +504,7 @@ BUTTON.plainButton {
|
||||
width: auto;
|
||||
height: 24px;
|
||||
padding: 2px;
|
||||
color: #D8C5BC;
|
||||
color: #EADAD1;
|
||||
background-color: #999;
|
||||
box-shadow: 3px 3px 2px #999;
|
||||
border: 1px solid #DDD;
|
||||
@@ -515,10 +514,10 @@ BUTTON.panelLabel {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
height: 18px;
|
||||
color: #D8C5BC;
|
||||
color: #EADAD1;
|
||||
background-color: #333;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D8C5BC;
|
||||
border: 1px solid #EADAD1;
|
||||
line-height: 5px;
|
||||
font-size: 5px;
|
||||
font-weight: normal}
|
||||
|
||||
@@ -45,6 +45,7 @@ function B220ConsolePrinter(mnemonic, unitIndex, config) {
|
||||
|
||||
// Create the printer window and onload event
|
||||
this.doc = null;
|
||||
this.window = null;
|
||||
this.paper = null;
|
||||
this.printerEOP = null;
|
||||
this.printerLine = 0;
|
||||
@@ -61,8 +62,8 @@ B220ConsolePrinter.onSwitchImage = "./resources/ToggleUp.png";
|
||||
|
||||
B220ConsolePrinter.ttySpeed = 10; // TTY printer speed, char/sec
|
||||
B220ConsolePrinter.ttyNewLine = 200; // TTY carriage-return delay, ms
|
||||
B220ConsolePrinter.whippetSpeed = 5000; // Whippet printer speed, char/sec
|
||||
B220ConsolePrinter.whippetNewLine = 200;// Whippet carriage-return delay, ms
|
||||
B220ConsolePrinter.whippetSpeed = 1000; // Whippet printer speed, char/sec
|
||||
B220ConsolePrinter.whippetNewLine = 75; // Whippet carriage-return delay, ms
|
||||
B220ConsolePrinter.formFeedPeriod = 500;// form-feed average delay, ms
|
||||
|
||||
B220ConsolePrinter.pageSize = 66; // lines/page for form-feed
|
||||
@@ -166,8 +167,8 @@ B220ConsolePrinter.prototype.printChar = function printChar(code) {
|
||||
/**************************************/
|
||||
B220ConsolePrinter.prototype.printTab = function printTab() {
|
||||
/* Simulates tabulation by outputting an appropriate number of spaces */
|
||||
var tabCol; // tabulation column
|
||||
var x; // scratch index
|
||||
var tabCol = this.columns+1; // tabulation column (defaults to line overflow)
|
||||
var x = 0; // scratch index
|
||||
|
||||
for (x=0; x<this.tabStop.length; ++x) {
|
||||
if (this.tabStop[x] > this.printerCol) {
|
||||
@@ -210,7 +211,7 @@ B220ConsolePrinter.prototype.copyPaper = function copyPaper(ev) {
|
||||
var text = this.paper.textContent;
|
||||
var title = "B220 " + this.mnemonic + " Text Snapshot";
|
||||
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Snapshot",
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", "",
|
||||
"scrollbars,resizable,width=500,height=500",
|
||||
this, function(ev) {
|
||||
var doc = ev.target;
|
||||
@@ -314,7 +315,7 @@ B220ConsolePrinter.prototype.text_OnChange = function text_OnChange(ev) {
|
||||
/* Handler for text onchange events */
|
||||
var prefs = this.config.getNode("ConsoleOutput.units", this.unitIndex);
|
||||
var text = ev.target.value;
|
||||
var v;
|
||||
var v = null;
|
||||
|
||||
switch (ev.target.id) {
|
||||
case "Columns":
|
||||
@@ -329,7 +330,7 @@ B220ConsolePrinter.prototype.text_OnChange = function text_OnChange(ev) {
|
||||
v = this.parseTabStops(prefs.tabs || "", this.window);
|
||||
if (v !== null) {
|
||||
this.tabStop = v;
|
||||
ev.target.value = text = v.join(",");
|
||||
ev.target.value = text = this.formatTabStops(v);
|
||||
prefs.tabs = text;
|
||||
}
|
||||
break;
|
||||
@@ -341,7 +342,21 @@ B220ConsolePrinter.prototype.text_OnChange = function text_OnChange(ev) {
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ConsolePrinter.prototype.parseTabStops = function parsetabStops(text, alertWin) {
|
||||
B220ConsolePrinter.prototype.formatTabStops = function formatTabStops(tabStops) {
|
||||
/* Formats the array "tabStops" of 0-relative tab stop positions as a comma-
|
||||
delimited string of 1-relative numbers */
|
||||
var s = (tabStops[0]+1).toString();
|
||||
var x = 0;
|
||||
|
||||
for (x=1; x<tabStops.length; ++x) {
|
||||
s += "," + (tabStops[x]+1).toString();
|
||||
}
|
||||
|
||||
return s;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ConsolePrinter.prototype.parseTabStops = function parseTabStops(text, alertWin) {
|
||||
/* Parses a comma-delimited list of 1-relative tab stops. If the list is parsed
|
||||
successfully, returns an array of 0-relative tab stop positions; otherwise
|
||||
returns null. An alert is displayed on the window for the first parsing or
|
||||
@@ -386,7 +401,7 @@ B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad(ev) {
|
||||
var id;
|
||||
var mask;
|
||||
var prefs = this.config.getNode("ConsoleOutput.units", this.unitIndex);
|
||||
var tabStop;
|
||||
var tabStop = null;
|
||||
var x;
|
||||
|
||||
this.doc = ev.target;
|
||||
@@ -442,7 +457,7 @@ B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad(ev) {
|
||||
tabStop = this.parseTabStops(prefs.tabs || "", this.window);
|
||||
if (tabStop !== null) {
|
||||
this.tabStop = tabStop;
|
||||
this.$$("TabStops").value = tabStop.join(",");
|
||||
this.$$("TabStops").value = this.formatTabStops(tabStop);
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
@@ -90,22 +90,28 @@
|
||||
|
||||
#ProcDelta {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
width: 48px;
|
||||
text-align: right;
|
||||
left: 120px;
|
||||
bottom: 12px}
|
||||
left: 132px;
|
||||
bottom: 16px}
|
||||
#ProcSlack {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
text-align: right;
|
||||
left: 190px;
|
||||
bottom: 12px}
|
||||
left: 180px;
|
||||
bottom: 16px}
|
||||
#ProcRun {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
width: 48px;
|
||||
text-align: right;
|
||||
left: 260px;
|
||||
bottom: 12px}
|
||||
left: 244px;
|
||||
bottom: 16px}
|
||||
#ICount {
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
text-align: right;
|
||||
left: 292px;
|
||||
bottom: 16px}
|
||||
|
||||
#PanelSurface {
|
||||
height: 100%;
|
||||
|
||||
@@ -151,8 +151,9 @@
|
||||
<button id=RightPanelBtn class=plainButton title="Some day there may be a Right Panel, too">Right Panel</button>
|
||||
|
||||
<div id=ProcDelta title="Average Processor delay delta (ms)"></div>
|
||||
<div id=ProcSlack title="Average Processor slack time (ms)"></div>
|
||||
<div id=ProcSlack title="Average % Processor slack time"></div>
|
||||
<div id=ProcRun title="Average Processor run time (ms)"></div>
|
||||
<div id=ICount title="Total instructions executed"></div>
|
||||
|
||||
<div id=VersionDiv class=caption>
|
||||
retro-220 <span id=EmulatorVersion>?.??</span>
|
||||
|
||||
@@ -103,13 +103,13 @@ function B220ControlConsole(p, systemShutdown) {
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.displayRefreshPeriod = 50; // milliseconds
|
||||
B220ControlConsole.displayRefreshPeriod = 100; // milliseconds
|
||||
B220ControlConsole.offSwitchImage = "./resources/ToggleDown.png";
|
||||
B220ControlConsole.onSwitchImage = "./resources/ToggleUp.png";
|
||||
B220ControlConsole.offOrganSwitchImage = "./resources/Organ-Switch-Up.png"
|
||||
B220ControlConsole.onOrganSwitchImage = "./resources/Organ-Switch-Down.png"
|
||||
|
||||
B220ControlConsole.codeXlate = [ // translate internal B220 code to ANSI
|
||||
B220ControlConsole.codeXlate = [ // translate internal 220 code to ANSI
|
||||
" ", "_", " ", ".", "\u00A4", "_", "_", "_", "_", "_", "!", "!", "!", "!", "!", "!", // 00-0F
|
||||
"&", "_", "_", "$", "*", "^", "~", "_", "_", "_", "!", "!", "!", "!", "!", "!", // 10-1F
|
||||
"-", "/", "_", ",", "%", "_", "|", "_", "_", "_", "!", "!", "!", "!", "!", "!", // 20-2F
|
||||
@@ -392,7 +392,7 @@ B220ControlConsole.prototype.meatballMemdump = function meatballMemdump() {
|
||||
}
|
||||
|
||||
// Outer block of meatBallMemdump
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-MEMDUMP",
|
||||
B220Util.openPopup(window, "./B220FramePaper.html", "",
|
||||
"location=no,scrollbars=yes,resizable,width=800,height=600",
|
||||
this, memdumpSetup);
|
||||
};
|
||||
@@ -470,7 +470,7 @@ B220ControlConsole.prototype.updatePanel = function updatePanel() {
|
||||
text = (timer/1000 + 10000).toFixed(1);
|
||||
this.intervalTimer.textContent = text.substring(text.length-6);
|
||||
|
||||
p.updateLampGlow(p.AST.value ? 0.25 : 0);
|
||||
p.updateLampGlow(p.AST.value ? 0.75 : 0);
|
||||
eLevel = (p.RUT.value ? p.EXT.glow : p.EXT.value);
|
||||
|
||||
// Primary Registers
|
||||
@@ -506,9 +506,16 @@ B220ControlConsole.prototype.updatePanel = function updatePanel() {
|
||||
this.equalLamp.set(p.compareEqualLamp.glow);
|
||||
this.highLamp.set(p.compareHighLamp.glow);
|
||||
|
||||
this.$$("ProcDelta").textContent = p.delayDeltaAvg.toFixed(2) + " D";
|
||||
this.$$("ProcSlack").textContent = p.procSlackAvg.toFixed(2) + " S";
|
||||
this.$$("ProcRun").textContent = p.procRunAvg.toFixed(2) + " R";
|
||||
// Compute the timing statistics
|
||||
timer = this.p.procTimer;
|
||||
while (timer <= 0) {
|
||||
timer += stamp;
|
||||
}
|
||||
|
||||
this.$$("ProcDelta").textContent = p.delayDeltaAvg.toFixed(2) + "=D";
|
||||
this.$$("ProcSlack").textContent = (p.procSlack/timer*100).toFixed(2) + "%S";
|
||||
this.$$("ProcRun").textContent = p.procRunAvg.toFixed(2) + "=R";
|
||||
this.$$("ICount").textContent = B220Util.toFixedWithCommas(p.instructionCount) + "=I";
|
||||
/********** DEBUG **********
|
||||
this.displayCallbackState();
|
||||
***************************/
|
||||
@@ -526,47 +533,43 @@ B220ControlConsole.prototype.lamp_Click = function lamp_Click(ev) {
|
||||
var reg; // register prefix from id
|
||||
|
||||
if (p.poweredOn) {
|
||||
if (ix < 0) {
|
||||
return;
|
||||
} else if (ix > 0) {
|
||||
if (ix > 0) {
|
||||
reg = id.substring(0, ix);
|
||||
bit = parseInt(id.substring(ix+1), 10);
|
||||
if (isNaN(bit)) {
|
||||
return;
|
||||
if (!isNaN(bit)) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
switch (reg) {
|
||||
case "A":
|
||||
p.A.flipBit(bit);
|
||||
break;
|
||||
case "B":
|
||||
p.B.flipBit(bit);
|
||||
break;
|
||||
case "C":
|
||||
p.C.flipBit(bit);
|
||||
break;
|
||||
case "D":
|
||||
p.D.flipBit(bit);
|
||||
break;
|
||||
case "E":
|
||||
p.E.flipBit(bit);
|
||||
break;
|
||||
case "P":
|
||||
p.P.flipBit(bit);
|
||||
break;
|
||||
case "R":
|
||||
p.R.flipBit(bit);
|
||||
break;
|
||||
case "S":
|
||||
p.S.flipBit(bit);
|
||||
break;
|
||||
} // switch reg
|
||||
}
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case "A":
|
||||
p.A.flipBit(bit);
|
||||
break;
|
||||
case "B":
|
||||
p.B.flipBit(bit);
|
||||
break;
|
||||
case "C":
|
||||
p.C.flipBit(bit);
|
||||
break;
|
||||
case "D":
|
||||
p.D.flipBit(bit);
|
||||
break;
|
||||
case "E":
|
||||
p.E.flipBit(bit);
|
||||
break;
|
||||
case "P":
|
||||
p.P.flipBit(bit);
|
||||
break;
|
||||
case "R":
|
||||
p.R.flipBit(bit);
|
||||
break;
|
||||
case "S":
|
||||
p.S.flipBit(bit);
|
||||
break;
|
||||
} // switch reg
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -608,7 +611,6 @@ B220ControlConsole.prototype.switch_Click = function switch_Click(ev) {
|
||||
break;
|
||||
case "StepSwitch":
|
||||
this.stepSwitch.flip();
|
||||
//this.keyboard.keyboardEnable(0);
|
||||
p.step();
|
||||
break;
|
||||
case "ClearSwitch":
|
||||
@@ -776,9 +778,17 @@ B220ControlConsole.prototype.switch_Click = function switch_Click(ev) {
|
||||
p.tracing = !p.tracing;
|
||||
this.$$("LeftPanelBtn").focus(); // release any selection by the click
|
||||
if (p.tracing) {
|
||||
B220Util.addClass(ev.target, "tracing");
|
||||
ev.target.classList.add("tracing");
|
||||
} else {
|
||||
B220Util.removeClass(ev.target, "tracing");
|
||||
ev.target.classList.remove("tracing");
|
||||
}
|
||||
break;
|
||||
|
||||
case "Blank2LampLabel": // initialize to boot from cards (undocumented)
|
||||
if (!p.RUT.value) {
|
||||
p.clear();
|
||||
p.C.set(0x1000600000); // CRD unit 1
|
||||
p.setCycle(1);
|
||||
}
|
||||
break;
|
||||
} // switch ev.target.id
|
||||
@@ -792,11 +802,11 @@ B220ControlConsole.prototype.switch_Click = function switch_Click(ev) {
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad(ev) {
|
||||
/* Initializes the Supervisory Panel window and user interface */
|
||||
var body;
|
||||
var barStyles = {backgroundColor: "white"};
|
||||
var body = null;
|
||||
var p = this.p; // local copy of processor object
|
||||
var panel;
|
||||
var panel = null;
|
||||
var prefs = this.config.getNode("ControlConsole");
|
||||
var x;
|
||||
|
||||
this.doc = ev.target;
|
||||
this.window = this.doc.defaultView;
|
||||
@@ -815,10 +825,14 @@ B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad(ev) {
|
||||
this.regP = new PanelRegister(this.$$("PRegPanel"), 4*4, 4, "P_", "P");
|
||||
this.regS = new PanelRegister(this.$$("SRegPanel"), 4*4, 4, "S_", "S");
|
||||
|
||||
this.regA.drawBox(6, 2, 4, "2px solid white", "2px solid white");
|
||||
this.regC.drawBox(5, 2, 4, "2px solid white", "2px solid white");
|
||||
this.regD.drawBox(6, 2, 4, "2px solid white", "2px solid white");
|
||||
this.regR.drawBox(6, 2, 4, "2px solid white", "2px solid white");
|
||||
this.regA.drawBar(6, 4, barStyles);
|
||||
this.regA.drawBar(8, 4, barStyles);
|
||||
this.regC.drawBar(5, 4, barStyles);
|
||||
this.regC.drawBar(7, 4, barStyles);
|
||||
this.regD.drawBar(6, 4, barStyles);
|
||||
this.regD.drawBar(8, 4, barStyles);
|
||||
this.regR.drawBar(6, 4, barStyles);
|
||||
this.regR.drawBar(8, 4, barStyles);
|
||||
|
||||
// Status Panels
|
||||
|
||||
@@ -998,6 +1012,7 @@ B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad(ev) {
|
||||
|
||||
this.$$("BurroughsMeatball").addEventListener("click", this.boundMeatballMemdump, false);
|
||||
this.$$("B220Logo").addEventListener("dblclick", this.boundSwitch_Click);
|
||||
this.$$("Blank2LampLabel").addEventListener("click", this.boundSwitch_Click);
|
||||
this.$$("IntervalTimerResetBtn").addEventListener("click", this.boundResetTimer, false);
|
||||
this.$$("PowerOffBtn").addEventListener("dblclick", this.boundPowerBtn_Click, false);
|
||||
|
||||
|
||||
@@ -34,9 +34,11 @@ window.addEventListener("load", function(ev) {
|
||||
var p = null; // the Processor object
|
||||
var delayDeltaNode = document.getElementById("DelayDeltaAvg").firstChild;
|
||||
var execClockNode = document.getElementById("ExecClock").firstChild;
|
||||
var lastDelayNode = document.getElementById("Delay").firstChild;
|
||||
var procRunNode = document.getElementById("ProcRunAvg").firstChild;
|
||||
var procSlackNode = document.getElementById("ProcSlackAvg").firstChild;
|
||||
var procTimeNode = document.getElementById("ProcTime").firstChild;
|
||||
var stampDeltaNode = document.getElementById("StampDelta").firstChild;
|
||||
var timeStampNode = document.getElementById("TimeStamp").firstChild;
|
||||
|
||||
function clockIn(stamp, val) {
|
||||
@@ -53,7 +55,7 @@ window.addEventListener("load", function(ev) {
|
||||
function refreshStats() {
|
||||
/* Obtains the current "delayDev" has from the SetCallback mechanism and
|
||||
formats the data to DiagBody */
|
||||
var cat;
|
||||
var cat = "";
|
||||
var cell;
|
||||
var textNode;
|
||||
var delayDev;
|
||||
@@ -66,10 +68,12 @@ window.addEventListener("load", function(ev) {
|
||||
p = window.global.B220Processor.instance;
|
||||
} else {
|
||||
timeStampNode.nodeValue = p.runStamp.toFixed(2);
|
||||
execClockNode.nodeValue = clockIn(stamp, p.execClock).toFixed(2);
|
||||
execClockNode.nodeValue = p.execClock.toFixed(2);
|
||||
stampDeltaNode.nodeValue = (p.execClock-p.runStamp).toFixed(2);
|
||||
lastDelayNode.nodeValue = p.delayRequested.toFixed(2);
|
||||
procTimeNode.nodeValue = clockIn(stamp, p.procTime).toFixed(2);
|
||||
delayDeltaNode.nodeValue = p.delayDeltaAvg.toFixed(2);
|
||||
procSlackNode.nodeValue = p.procSlackAvg.toFixed(4);
|
||||
procSlackNode.nodeValue = p.procSlackAvg.toFixed(2);
|
||||
procRunNode.nodeValue = p.procRunAvg.toFixed(4);
|
||||
}
|
||||
|
||||
@@ -121,6 +125,8 @@ window.addEventListener("load", function(ev) {
|
||||
<tbody id=DiagBody>
|
||||
<tr><td id=TimeStamp class=rj> <td>Time Stamp
|
||||
<tr><td id=ExecClock class=rj> <td>Exec Clock
|
||||
<tr><td id=StampDelta class=rj> <td>Stamp Delta
|
||||
<tr><td id=Delay class=rj> <td>Last delay
|
||||
<tr><td id=ProcTime class=rj> <td>Proc Time
|
||||
<tr><td id=DelayDeltaAvg class=rj> <td>Delay Delta Avg
|
||||
<tr><td id=ProcSlackAvg class=rj> <td>Proc Slack Avg
|
||||
|
||||
@@ -274,12 +274,12 @@ B220MagTapeDrive.prototype.setAtBOT = function setAtBOT(atBOT) {
|
||||
if (atBOT ^ this.atBOT) {
|
||||
this.atBOT = atBOT;
|
||||
if (!atBOT) {
|
||||
B220Util.removeClass(this.$$("MTAtBOTLight"), "annunciatorLit");
|
||||
this.$$("MTAtBOTLight").classList.remove("annunciatorLit");
|
||||
} else {
|
||||
this.imgIndex = 0;
|
||||
this.tapeInches = 0;
|
||||
this.reelAngle = 0;
|
||||
B220Util.addClass(this.$$("MTAtBOTLight"), "annunciatorLit");
|
||||
this.$$("MTAtBOTLight").classList.add("annunciatorLit");
|
||||
this.reelBar.value = this.maxTapeInches;
|
||||
this.reelIcon.style.transform = "none";
|
||||
}
|
||||
@@ -303,9 +303,9 @@ B220MagTapeDrive.prototype.setAtEOT = function setAtEOT(atEOT) {
|
||||
if (atEOT ^ this.atEOT) {
|
||||
this.atEOT = atEOT;
|
||||
if (!atEOT) {
|
||||
B220Util.removeClass(this.$$("MTAtEOTLight"), "annunciatorLit");
|
||||
this.$$("MTAtEOTLight").classList.remove("annunciatorLit");
|
||||
} else {
|
||||
B220Util.addClass(this.$$("MTAtEOTLight"), "annunciatorLit");
|
||||
this.$$("MTAtEOTLight").classList.add("annunciatorLit");
|
||||
this.reelBar.value = 0;
|
||||
}
|
||||
}
|
||||
@@ -379,7 +379,7 @@ B220MagTapeDrive.prototype.setTapeUnloaded = function setTapeUnloaded() {
|
||||
this.reelIcon.style.visibility = "hidden";
|
||||
this.$$("MTFileName").value = "";
|
||||
this.$$("MTLaneNrLight").style.visibility = "hidden";
|
||||
B220Util.addClass(this.$$("MTUnloadedLight"), "annunciatorLit");
|
||||
this.$$("MTUnloadedLight").classList.add("annunciatorLit");
|
||||
if (this.timer) {
|
||||
clearCallback(this.timer);
|
||||
this.timer = 0;
|
||||
@@ -400,7 +400,7 @@ B220MagTapeDrive.prototype.tapeRewind = function tapeRewind(laneNr, lockout) {
|
||||
function rewindFinish() {
|
||||
this.timer = 0;
|
||||
this.tapeState = this.tapeLocal;
|
||||
B220Util.removeClass(this.$$("MTRewindingLight"), "annunciatorLit");
|
||||
this.$$("MTRewindingLight").classList.remove("annunciatorLit");
|
||||
this.rewindLock = (lockout ? true : false);
|
||||
this.rwlLamp.set(this.rewindLock ? 1 : 0);
|
||||
this.setTapeReady(!this.rewindLock);
|
||||
@@ -441,7 +441,7 @@ B220MagTapeDrive.prototype.tapeRewind = function tapeRewind(laneNr, lockout) {
|
||||
this.busy = true;
|
||||
this.tapeState = this.tapeRewinding;
|
||||
this.setAtEOT(false);
|
||||
B220Util.addClass(this.$$("MTRewindingLight"), "annunciatorLit");
|
||||
this.$$("MTRewindingLight").classList.add("annunciatorLit");
|
||||
this.timer = setCallback(this.mnemonic, this, 1000, rewindStart);
|
||||
}
|
||||
});
|
||||
@@ -581,7 +581,7 @@ B220MagTapeDrive.prototype.loadTape = function loadTape() {
|
||||
mt.$$("MTLaneNrLight").style.visibility = "visible";
|
||||
mt.setTapeReady(true);
|
||||
mt.reelIcon.style.visibility = "visible";
|
||||
B220Util.removeClass(mt.$$("MTUnloadedLight"), "annunciatorLit");
|
||||
mt.$$("MTUnloadedLight").classList.remove("annunciatorLit");
|
||||
}
|
||||
|
||||
function writeBlockStart(length) {
|
||||
@@ -1088,7 +1088,7 @@ B220MagTapeDrive.prototype.unloadTape = function unloadTape() {
|
||||
}
|
||||
|
||||
// Outer block of unloadTape
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Unload",
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", "",
|
||||
"location=no,scrollbars=yes,resizable,width=800,height=600",
|
||||
this, unloadSetup);
|
||||
};
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
</div>
|
||||
|
||||
<div id=MTLoadNotes>
|
||||
To load a blank tape, simply click <b>OK</b>; otherwise
|
||||
select a tape-image file before clicking <b>OK</b>.
|
||||
To load a blank tape, select the type from the <b>Format</b> list and
|
||||
click <b>OK</b>; otherwise select a tape-image file before clicking
|
||||
<b>OK</b>.
|
||||
</div>
|
||||
|
||||
<div id=MTLoadButtonGroup>
|
||||
|
||||
@@ -818,6 +818,29 @@ PanelRegister.prototype.panelHeight = function panelHeight(rows) {
|
||||
return (rows-1)*PanelRegister.vSpacing + PanelRegister.vOffset*2 + PanelRegister.lampDiameter;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.drawBar = function drawBar(col, rows, styles) {
|
||||
/* Creates a bar along the left border of a group of lamps in a register.
|
||||
styles is a JS object with name/value pairs to set additional styles for
|
||||
the bar's <div> element */
|
||||
var bar = document.createElement("div");
|
||||
var e = "";
|
||||
|
||||
bar.style.position = "absolute";
|
||||
bar.style.left = (this.xCoord(col) - (PanelRegister.hSpacing-PanelRegister.lampDiameter)/2 + 1).toString() + "px";
|
||||
bar.style.width = "2px";
|
||||
bar.style.top = this.yCoord(1).toString() + "px";
|
||||
bar.style.height = (this.yCoord(rows+1) - this.yCoord(1)).toString() + "px";
|
||||
if (styles) {
|
||||
for (e in styles) {
|
||||
bar.style[e] = styles[e];
|
||||
}
|
||||
}
|
||||
|
||||
this.element.appendChild(bar);
|
||||
return bar;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.drawBox = function drawBox(col, lamps, rows, leftStyle, rightStyle) {
|
||||
/* Creates a box centered around a specified group of lamps in a register.
|
||||
|
||||
@@ -157,7 +157,7 @@ B220PaperTapePunch.prototype.punchCopyTape = function punchCopyTape(ev) {
|
||||
var text = this.punchTape.textContent;
|
||||
var title = "B220 " + this.mnemonic + " Text Snapshot";
|
||||
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Snapshot",
|
||||
B220Util.openPopup(this.window, "./B220FramePaper.html", "",
|
||||
"scrollbars,resizable,width=500,height=500",
|
||||
this, function(ev) {
|
||||
var doc = ev.target;
|
||||
|
||||
@@ -35,8 +35,10 @@ function B220PaperTapeReader(mnemonic, unitIndex, config) {
|
||||
this.boundReadTapeChar = B220PaperTapeReader.prototype.readTapeChar.bind(this);
|
||||
|
||||
this.readResult = { // object passed back to Processor for each read
|
||||
code: 0,
|
||||
readChar: this.boundReadTapeChar
|
||||
code: 0, // 220 char code sent to processor
|
||||
signDigit: 0, // copy of first digit read for word
|
||||
frameCount: 0, // count of tape frames read for word
|
||||
readChar: this.boundReadTapeChar // callback function for next char
|
||||
};
|
||||
|
||||
this.clear();
|
||||
@@ -154,6 +156,7 @@ B220PaperTapeReader.prototype.fileSelector_onChange = function fileSelector_onCh
|
||||
}
|
||||
}
|
||||
|
||||
this.tapeView.value = "";
|
||||
for (x=f.length-1; x>=0; x--) {
|
||||
tape = new FileReader();
|
||||
tape.onload = fileLoader_onLoad;
|
||||
@@ -302,6 +305,9 @@ B220PaperTapeReader.prototype.initiateInput = function initiateInput(successor)
|
||||
the processor and gets the ball rolling */
|
||||
var stamp = performance.now();
|
||||
|
||||
this.readResult.code = 0;
|
||||
this.readResult.signDigit = 0;
|
||||
this.readResult.frameCount = 0;
|
||||
if (stamp-this.nextCharTime < B220PaperTapeReader.idleTime) {
|
||||
this.readTapeChar(successor);
|
||||
} else {
|
||||
@@ -320,6 +326,11 @@ B220PaperTapeReader.prototype.sendTapeChar = function sendTapeChar(c, code, rece
|
||||
var text = this.tapeView.value;
|
||||
|
||||
this.readResult.code = code;
|
||||
++this.readResult.frameCount;
|
||||
if (this.readResult.frameCount == 1) {
|
||||
this.readResult.signDigit = code;
|
||||
}
|
||||
|
||||
if (this.nextCharTime < stamp) {
|
||||
delay = 0;
|
||||
this.nextCharTime = stamp + this.charPeriod;
|
||||
@@ -339,6 +350,29 @@ B220PaperTapeReader.prototype.sendTapeChar = function sendTapeChar(c, code, rece
|
||||
this.tapeView.setSelectionRange(length-1, length);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220PaperTapeReader.prototype.conditionalSendEOW = function conditionalSendEOW(receiver) {
|
||||
/* Checks for the special case of sending an alphanumeric word (sign=2) with
|
||||
less than five alpha characters. Since text editors may trim trailing blanks
|
||||
from the end of lines, alpha words with trailing blanks may be trimmed in the
|
||||
tape image file. If the sign digit was 2 and fewer than six characters (sign
|
||||
plus five alpha codes) have been sent to the processor, sends a space code to
|
||||
pad the alpha word and returns false. Otherwise, sends an End-of-Word code and
|
||||
returns true */
|
||||
var code = 0x35; // EOW code
|
||||
var result = true;
|
||||
|
||||
if (this.readResult.signDigit == 0x82) { // sign digit was a "2"
|
||||
if (this.readResult.frameCount < 6) {
|
||||
code = 0x00; // space code
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.sendTapeChar(0x20, code, receiver);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220PaperTapeReader.prototype.readTapeChar = function readTapeChar(receiver) {
|
||||
/* Reads one character frame from the paper-tape buffer and passes it to the
|
||||
@@ -352,7 +386,7 @@ B220PaperTapeReader.prototype.readTapeChar = function readTapeChar(receiver) {
|
||||
loaded, the fileSelector_onChange event will set ready, notice the hanging
|
||||
read (this.busy=true) and restart the read */
|
||||
var bufLength = this.bufLength; // current buffer length
|
||||
var c; // current character ANSI code
|
||||
var c = 0; // current character ANSI code
|
||||
var x = this.bufIndex; // current buffer index
|
||||
|
||||
if (!this.ready) {
|
||||
@@ -362,23 +396,26 @@ B220PaperTapeReader.prototype.readTapeChar = function readTapeChar(receiver) {
|
||||
} else {
|
||||
this.busy = false;
|
||||
if (x >= bufLength) { // end of buffer -- send finish
|
||||
this.sendTapeChar(0x20, 0x35, receiver);
|
||||
this.setReaderEmpty();
|
||||
if (this.conditionalSendEOW(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();
|
||||
if (this.conditionalSendEOW(receiver)) {
|
||||
if (++x < bufLength && this.buffer.charCodeAt(x) == 0x0A) {
|
||||
++x;
|
||||
}
|
||||
if (x >= bufLength) {
|
||||
this.setReaderEmpty();
|
||||
}
|
||||
}
|
||||
} else if (c == 0x0A) { // line feed -- send EOW
|
||||
++x;
|
||||
this.sendTapeChar(0x20, 0x35, receiver);
|
||||
if (x >= bufLength) {
|
||||
this.setReaderEmpty();
|
||||
if (this.conditionalSendEOW(receiver)) {
|
||||
++x;
|
||||
if (x >= bufLength) {
|
||||
this.setReaderEmpty();
|
||||
}
|
||||
}
|
||||
} else { // translate character and send its code
|
||||
++x;
|
||||
@@ -386,8 +423,8 @@ B220PaperTapeReader.prototype.readTapeChar = function readTapeChar(receiver) {
|
||||
}
|
||||
}
|
||||
|
||||
this.tapeSupplyBar.value = bufLength-x;
|
||||
this.bufIndex = x;
|
||||
this.tapeSupplyBar.value = bufLength-x;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -80,12 +80,13 @@
|
||||
* retro-205 project.
|
||||
* 2017-10-16 P.Kimpel
|
||||
* Replace window.postMessage yield mechanism with one based on Promise().
|
||||
* 2018-07-05 P.Kimpel
|
||||
* Simplify delay and deviation adjustment algorithm.
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
(function (global) {
|
||||
/* Define a closure for the setCallback() mechanism */
|
||||
var alpha = 0.25; // decay factor for delay deviation adjustment
|
||||
var delayDev = {NUL: 0}; // hash of delay time deviations by category
|
||||
var minTimeout = 4; // minimum setTimeout() threshold, milliseconds
|
||||
var lastTokenNr = 0; // last setCallback token return value
|
||||
@@ -145,11 +146,10 @@
|
||||
to "fcn". If the delay is less than "minTimeout", a setImmediate-like mechanism
|
||||
based on DOM Promise() will be used; otherwise the environment's standard
|
||||
setTimeout mechanism will be used */
|
||||
var adj = 0; // adjustment to delay and delayDev[]
|
||||
var categoryName = (category || "NUL").toString();
|
||||
var delay = callbackDelay || 0; // actual delay to be generated
|
||||
var delayBias; // current amount of delay deviation
|
||||
var thisCallback; // call-back object to be used
|
||||
var delayBias = 0; // current amount of delay deviation
|
||||
var thisCallback = null; // call-back object to be used
|
||||
var token = ++lastTokenNr; // call-back token number
|
||||
var tokenName = token.toString(); // call-back token ID
|
||||
|
||||
@@ -161,7 +161,14 @@
|
||||
pool[poolLength] = null;
|
||||
}
|
||||
|
||||
// Fill in the call-back object and tank it in pendingCallbacks.
|
||||
thisCallback.startStamp = perf.now();
|
||||
thisCallback.category = categoryName;
|
||||
thisCallback.delay = delay;
|
||||
thisCallback.context = context || this;
|
||||
thisCallback.fcn = fcn;
|
||||
thisCallback.arg = arg;
|
||||
pendingCallbacks[tokenName] = thisCallback;
|
||||
|
||||
// Adjust the requested delay based on the current delay deviation
|
||||
// for this category.
|
||||
@@ -171,42 +178,19 @@
|
||||
} else {
|
||||
if (delayBias > 0) {
|
||||
// We are delaying too much and should try to delay less.
|
||||
if (delay < 0) {
|
||||
adj = 0; // don't make delay any more negative
|
||||
} else {
|
||||
adj = -Math.min(delay, delayBias, minTimeout)*alpha;
|
||||
if (delay > 0) { // don't make a negative delay any more so
|
||||
delay -= Math.min(delay, delayBias, minTimeout);
|
||||
}
|
||||
} else { // delayBias < 0
|
||||
} else { // delayBias <= 0
|
||||
// We are delaying too little and should try to delay more.
|
||||
if (delay < 0) {
|
||||
if (delay - minTimeout < delayBias) {
|
||||
adj = -delayBias;
|
||||
} else {
|
||||
adj = minTimeout - delay;
|
||||
}
|
||||
delay -= Math.max(delay, delayBias);
|
||||
} else {
|
||||
if (delay > minTimeout) {
|
||||
adj = 0;
|
||||
} else if (delay - minTimeout < delayBias) {
|
||||
adj = -delayBias;
|
||||
} else {
|
||||
adj = minTimeout - delay;
|
||||
}
|
||||
delay += Math.min(-delayBias, minTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
delay += adj;
|
||||
delayDev[categoryName] += adj;
|
||||
}
|
||||
|
||||
// Fill in the call-back object and tank it in pendingCallbacks.
|
||||
thisCallback.category = categoryName;
|
||||
thisCallback.delay = delay;
|
||||
thisCallback.context = context || this;
|
||||
thisCallback.fcn = fcn;
|
||||
thisCallback.arg = arg;
|
||||
pendingCallbacks[tokenName] = thisCallback;
|
||||
|
||||
// Decide whether to do a time wait or just a yield.
|
||||
if (delay > minTimeout) {
|
||||
thisCallback.cancelToken = global.setTimeout(activateCallback, delay, token);
|
||||
|
||||
@@ -49,24 +49,18 @@ B220Util.$$ = function $$(e) {
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.hasClass = function hasClass(e, name) {
|
||||
/* returns true if element "e" has class "name" in its class list */
|
||||
B220Util.toFixedWithCommas = function toFixedWithCommas(v) {
|
||||
/* Formats the value "v" as an integer with commas separating thousands */
|
||||
var s = v.toFixed();
|
||||
var t = "";
|
||||
var x = s.length;
|
||||
|
||||
return e.classList.contains(name);
|
||||
};
|
||||
while (x > 3) {
|
||||
t = "," + s.substring(x-3, x) + t;
|
||||
x -= 3;
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B220Util.addClass = function addClass(e, name) {
|
||||
/* Adds a class "name" to the element "e"s class list */
|
||||
|
||||
e.classList.add(name);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.removeClass = function removeClass(e, name) {
|
||||
/* Removes the class "name" from the element "e"s class list */
|
||||
|
||||
e.classList.remove(name);
|
||||
return s.substring(0, x) + t;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -164,7 +158,7 @@ B220Util.xlateDOMTreeText = function xlateDOMTreeText(n, xlate) {
|
||||
/**************************************/
|
||||
B220Util.openPopup = function openPopup(parent, url, windowName, options, context, onload) {
|
||||
/* Schedules the opening of a pop-up window so that browsers such as Apple
|
||||
Safari (11.0+) will not block the opens if they occur too close together.
|
||||
Safari (11.0+) will not block the opens if they occur too close together.
|
||||
Parameters:
|
||||
parent: parent window for the pop-up
|
||||
url: url of window context, passed to window.open()
|
||||
@@ -222,7 +216,7 @@ B220Util.dequeuePopup = function dequeuePopup() {
|
||||
}
|
||||
|
||||
loader2 = function(ev) { // remove the load event listeners after loading
|
||||
win.removeEventListener("load", loader2, false);
|
||||
win.removeEventListener("load", loader2, false);
|
||||
if (loader1) {
|
||||
win.removeEventListener("load", loader1, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user