1
0
mirror of https://github.com/pkimpel/retro-220.git synced 2026-03-27 02:14:45 +00:00

Commit 220 emulator version 0.3c:

1. Rework magnetic tape drive implementation to use Promises; refactor and consolidate drive operation routines.
2. Implement remaining magnetic tape operations: MOW, MOR, MRD, MRR, MTS, MFS, MTC, MFC.
3. Implement better error status reporting in mag tape control MISC register.
4. Implement memory and Processor-state dump by clicking the Burroughs "meatball" logo.
5. Implement preliminary run-time statistics on Console.
6. Use Function.bind() to bind context in Processor and mag tape scripts.
This commit is contained in:
Paul Kimpel
2017-11-17 06:29:31 -08:00
parent 4c63d98515
commit 654af4f683
11 changed files with 2475 additions and 1794 deletions

View File

@@ -229,22 +229,22 @@ function B220Processor(config, devices) {
this.rightPanelOpen = false;
// Context-bound routines
this.boundUpdateLampGlow = B220Processor.bindMethod(this, B220Processor.prototype.updateLampGlow);
this.boundConsoleOutputSign = B220Processor.prototype.consoleOutputSign.bind(this);
this.boundConsoleOutputChar = B220Processor.prototype.consoleOutputChar.bind(this);
this.boundConsoleOutputFinished = B220Processor.prototype.consoleOutputFinished.bind(this);
this.boundConsoleInputReceiveChar = B220Processor.prototype.consoleInputReceiveChar.bind(this);
this.boundConsoleInputInitiateNormal = B220Processor.prototype.consoleInputInitiateNormal.bind(this);
this.boundConsoleInputInitiateInverse = B220Processor.prototype.consoleInputInitiateInverse.bind(this);
this.boundConsoleOutputSign = B220Processor.bindMethod(this, B220Processor.prototype.consoleOutputSign);
this.boundConsoleOutputChar = B220Processor.bindMethod(this, B220Processor.prototype.consoleOutputChar);
this.boundConsoleOutputFinished = B220Processor.bindMethod(this, B220Processor.prototype.consoleOutputFinished);
this.boundConsoleInputReceiveChar = B220Processor.bindMethod(this, B220Processor.prototype.consoleInputReceiveChar);
this.boundConsoleInputInitiateNormal = B220Processor.bindMethod(this, B220Processor.prototype.consoleInputInitiateNormal);
this.boundConsoleInputInitiateInverse = B220Processor.bindMethod(this, B220Processor.prototype.consoleInputInitiateInverse);
this.boundCardatronOutputWord= B220Processor.prototype.cardatronOutputWord.bind(this);
this.boundCardatronOutputFinished = B220Processor.prototype.cardatronOutputFinished.bind(this);
this.boundCardatronReceiveWord = B220Processor.prototype.cardatronReceiveWord.bind(this);
this.boundCardatronOutputWord= B220Processor.bindMethod(this, B220Processor.prototype.cardatronOutputWord);
this.boundCardatronOutputFinished = B220Processor.bindMethod(this, B220Processor.prototype.cardatronOutputFinished);
this.boundCardatronReceiveWord = B220Processor.bindMethod(this, B220Processor.prototype.cardatronReceiveWord);
this.boundMagTapeComplete = B220Processor.prototype.magTapeComplete.bind(this);
this.boundMagTapeReceiveWord = B220Processor.prototype.magTapeReceiveWord.bind(this);
this.boundMagTapeSendWord = B220Processor.prototype.magTapeSendWord.bind(this);
this.boundMagTapeComplete = B220Processor.bindMethod(this, B220Processor.prototype.magTapeComplete);
this.boundMagTapeReceiveWord = B220Processor.bindMethod(this, B220Processor.prototype.magTapeReceiveWord);
this.boundMagTapeSendWord = B220Processor.bindMethod(this, B220Processor.prototype.magTapeSendWord);
this.boundIoComplete = B220Processor.prototype.ioComplete.bind(this);
this.clear(); // Create and initialize the processor state
@@ -256,13 +256,13 @@ function B220Processor(config, devices) {
* Global Constants *
***********************************************************************/
B220Processor.version = "0.03b";
B220Processor.version = "0.03c";
B220Processor.tick = 1000/200000; // milliseconds per clock cycle (200KHz)
B220Processor.cyclesPerMilli = 1/B220Processor.tick;
// clock cycles per millisecond (200 => 200KHz)
B220Processor.timeSlice = 10; // maximum processor time slice, ms
B220Processor.delayAlpha = 0.001; // decay factor for exponential weighted average delay
B220Processor.delayAlpha = 0.0001; // decay factor for exponential weighted average delay
B220Processor.delayAlpha1 = 1-B220Processor.delayAlpha;
B220Processor.slackAlpha = 0.0001; // decay factor for exponential weighted average slack
B220Processor.slackAlpha1 = 1-B220Processor.slackAlpha;
@@ -322,15 +322,6 @@ B220Processor.emptyFunction = function emptyFunction() {
return;
};
/**************************************/
B220Processor.bindMethod = function bindMethod(context, f) {
/* Returns a new function that binds the function "f" to the object "context".
Note that this is a static constructor property function, NOT an instance
method of the CC object */
return function bindMethodAnon() {return f.apply(context, arguments)};
};
/**************************************/
B220Processor.bcdBinary = function bcdBinary(v) {
/* Converts the BCD value "v" to a binary number and returns it. If the
@@ -2834,21 +2825,19 @@ B220Processor.prototype.cardatronReceiveWord = function cardatronReceiveWord(wor
***********************************************************************/
/**************************************/
B220Processor.prototype.magTapeComplete = function magTapeComplete(alarm, control, word) {
B220Processor.prototype.magTapeComplete = function magTapeComplete(control, word) {
/* Call-back routine to signal completion of a magnetic tape operation. If
"alarm" is true, the Magnetic Tape Alarm will be set. If "control" is true,
the contents of "word" are processed as a tape control word and an appropriate
branch is set up. Unconditionally terminates the tape I/O instruction */
"control" is true, the contents of "word" are processed as a tape control
word and an appropriate branch is set up. Unconditionally terminates the
tape I/O instruction */
var aaaa;
var bbbb;
if (alarm) {
this.setMagneticTapeCheck(true);
} else if (control) {
if (control) {
this.D.set(word);
bbbb = word%0x10000;
aaaa = ((word - bbbb)/0x10000)%0x10000;
if ((word - word%0x10000000000)%2) { // if sign bit is 1,
if (word%0x20000000000 >= 0x10000000000) { // if sign bit is 1,
bbbb = this.bcdAdd(bbbb, this.B.value, 4); // B-adjust the low-order 4 digits
}
@@ -2862,13 +2851,13 @@ B220Processor.prototype.magTapeComplete = function magTapeComplete(alarm, contro
}
}
this.ioComplete(true);
Promise.resolve(true).then(this.boundIoComplete);
};
/**************************************/
B220Processor.prototype.magTapeSendWord = function magTapeSendWord(initial) {
B220Processor.prototype.magTapeSendWord = function magTapeSendWord(initialFetch) {
/* Sends the next of data from memory to the tape control unit, starting at
the current operand address in the C register. "initial" is true if this
the current operand address in the C register. "initialFetch" is true if this
call is the first to fetch words for a block. This causes the routine to
save the current operand address in the control digits of C. Returns
binary -1 if the processor has been cleared or a memory address error
@@ -2878,7 +2867,7 @@ B220Processor.prototype.magTapeSendWord = function magTapeSendWord(initial) {
if (!this.AST.value) {
result = -1; // we've probably been cleared
} else {
if (initial) {
if (initialFetch) {
this.clockIn();
this.CCONTROL = this.CADDR; // copy C address into control digits
}
@@ -2900,9 +2889,9 @@ B220Processor.prototype.magTapeSendWord = function magTapeSendWord(initial) {
};
/**************************************/
B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initial, word) {
B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initialStore, word) {
/* Stores the next of data from the tape control unit to memory, starting at
the current operand address in the C register. "initial" is true if this
the current operand address in the C register. "initialStore" is true if this
call is the first to store words for a block. This causes the routine to
save the current operand address in the control digits of C. Returns
binary -1 if the processor has been cleared or a memory address error
@@ -2913,7 +2902,7 @@ B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initial
if (!this.AST.value) {
result = -1; // we've probably been cleared
} else {
if (initial) {
if (initialStore) {
this.clockIn();
this.CCONTROL = this.CADDR; // copy C address into control digits
}
@@ -2923,7 +2912,7 @@ B220Processor.prototype.magTapeReceiveWord = function magTapeReceiveWord(initial
this.C.set((this.CCONTROL*0x100 + this.COP)*0x10000 + this.CADDR);
this.D.set(word);
if (this.vDigit & 0x08) { // B-adjustment of words is enabled
sign = (word - word%0x10000000000);
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);
@@ -3601,22 +3590,33 @@ B220Processor.prototype.execute = function execute() {
this.vDigit = this.CCONTROL%0x10;
this.ioInitiate();
if (this.vDigit & 0x08) { // MRW/MDA: rewind, with or without lockout
this.magTape.rewind(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendWord);
this.magTape.rewind(this.D.value);
} else if (this.vDigit & 0x04) { // MLS: lane select
this.magTape.laneSelect(this.D.value, this.boundMagTapeComplete, this.boundMagTapeSendWord);
this.magTape.laneSelect(this.D.value);
} else { // MTS/MFS: search or field search
if (this.D.value%0x80000000000 < 0x40000000000) { // full-word search
this.magTape.search(this.D.value, this.boundMagTapeComplete, 0, this.boundMagTapeSendWord);
} else { // partial-word search based on sL in B
this.magTape.search(this.D.value, this.boundMagTapeComplete, this.B.value, this.boundMagTapeSendWord);
if (this.D.value%0x80000000000 < 0x40000000000) { // sign 4-bit = 0: full-word search
this.magTape.search(this.D.value, 0);
} else { // partial-word search based on sL00 in B
this.magTape.search(this.D.value, this.B.value);
}
}
}
break;
case 0x51: //--------------------- MTC/MFC Magnetic tape scan/field scan
this.setProgramCheck(1);
this.operationComplete();
this.opTime = 0.160;
if (!this.magTape) {
this.setMagneticTapeCheck(true); // no tape control
this.operationComplete();
} else {
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
this.ioInitiate();
if (this.D.value%0x80000000000 < 0x40000000000) { // sign 4-bit = 0: full-word search
this.magTape.scan(this.D.value, 0);
} else { // partial-word search based on sL00 in B
this.magTape.scan(this.D.value, this.B.value);
}
}
break;
case 0x52: //--------------------- MRD Magnetic tape read
@@ -3626,9 +3626,9 @@ B220Processor.prototype.execute = function execute() {
this.operationComplete();
} else {
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
this.vDigit = this.CCONTROL%0x10;
this.vDigit = this.CCONTROL%0x10; // controlword and B-mod bits
this.ioInitiate();
this.magTape.read(this.D.value, this.boundMagTapeComplete, false, this.boundMagTapeReceiveWord);
this.magTape.read(this.D.value, false);
}
break;
@@ -3639,9 +3639,9 @@ B220Processor.prototype.execute = function execute() {
this.operationComplete();
} else {
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
this.vDigit = this.CCONTROL%0x10;
this.vDigit = this.CCONTROL%0x10; // controlword and B-mod bits
this.ioInitiate();
this.magTape.read(this.D.value, this.boundMagTapeComplete, true, this.boundMagTapeReceiveWord);
this.magTape.read(this.D.value, true);
}
break;
@@ -3653,7 +3653,7 @@ B220Processor.prototype.execute = function execute() {
} else {
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
this.ioInitiate();
this.magTape.initialWrite(this.D.value, this.boundMagTapeComplete, false, this.boundMagTapeSendWord);
this.magTape.initialWrite(this.D.value, false);
}
break;
@@ -3665,7 +3665,7 @@ B220Processor.prototype.execute = function execute() {
} else {
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
this.ioInitiate();
this.magTape.initialWrite(this.D.value, this.boundMagTapeComplete, true, this.boundMagTapeSendWord);
this.magTape.initialWrite(this.D.value, true);
}
break;
@@ -3677,7 +3677,7 @@ B220Processor.prototype.execute = function execute() {
} else {
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
this.ioInitiate();
this.magTape.overwrite(this.D.value, this.boundMagTapeComplete, false, this.boundMagTapeSendWord);
this.magTape.overwrite(this.D.value, false);
}
break;
@@ -3689,7 +3689,7 @@ B220Processor.prototype.execute = function execute() {
} else {
this.selectedUnit = (this.CCONTROL >>> 12)%0x10;
this.ioInitiate();
this.magTape.overwrite(this.D.value, this.boundMagTapeComplete, true, this.boundMagTapeSendWord);
this.magTape.overwrite(this.D.value, true);
}
break;
@@ -3703,13 +3703,13 @@ B220Processor.prototype.execute = function execute() {
this.ioInitiate();
switch (this.CCONTROL%0x10) {
case 1: // MPB: position tape backward
this.magTape.positionBackward(this.D.value, this.boundMagTapeComplete);
this.magTape.positionBackward(this.D.value);
break;
case 2: // MPE: position tape at end
this.magTape.positionAtEnd(this.D.value, this.boundMagTapeComplete);
this.magTape.positionAtEnd(this.D.value);
break;
default: // MPF: position tape forward
this.magTape.positionForward(this.D.value, this.boundMagTapeComplete);
this.magTape.positionForward(this.D.value);
break;
} // switch on operation variant
}
@@ -3723,7 +3723,7 @@ B220Processor.prototype.execute = function execute() {
} else {
opTime = 0.14;
if (this.CCONTROL%0x10 == 1) { // MIE
if (this.magTape.testUnitAtMagneticEOT(this.D.value)) {
if (this.magTape.testUnitAtEOT(this.D.value)) {
this.P.set(this.CADDR);
this.opTime += 0.020;
}
@@ -4257,19 +4257,20 @@ B220Processor.prototype.loadDefaultProgram = function loadDefaultProgram() {
this.MM[ 2] = 0x1000540000; // MIW 0,1,10,100
this.MM[ 3] = 0x1750540100; // MIW 100,1,7,50
this.MM[ 4] = 0x1500550079; // MIR 79,1,5,00
this.MM[ 5] = 0x1101542000; // MIW 2000,1,1,1 // write control block
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] = 0x1101012000; // MOW 2000,1,1,1 // TEMP: changed to a NOP
//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 a control block
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
@@ -4283,6 +4284,7 @@ B220Processor.prototype.loadDefaultProgram = function loadDefaultProgram() {
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

View File

@@ -66,16 +66,22 @@ B220ConsolePrinter.maxScrollLines = 15000;
// Maximum amount of paper scrollback
B220ConsolePrinter.codeXlate = [ // translate internal B220 code to ANSI
" ", "?", " ", ".", "\u00A4", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 00-0F
"&", "?", "?", "$", "*", "\f", "\n", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 10-1F
"-", "/", "?", ",", "%", "?", "\t", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 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
"&", "?", "?", "$", "*", "\f", "\n", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 10-1F
"-", "/", "?", ",", "%", "?", "\t", "?", "?", "?", "!", "!", "!", "!", "!", "!", // 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
/**************************************/

View File

@@ -34,8 +34,8 @@
font-weight: bold}
#IntervalTimerResetCaption {
bottom: 21px;
left: calc(50% - 206px);
bottom: 20px;
width: 120px;
text-align: right}
#IntervalTimerResetBtn {
@@ -69,7 +69,7 @@
bottom: 12px}
#PowerOffCaption {
left: calc(50% + 92px);
bottom: 21px}
bottom: 20px}
#VersionDiv {
right: 150px;
@@ -85,6 +85,25 @@
right: 12px;
bottom: 12px}
#ProcDelta {
position: absolute;
width: 64px;
text-align: right;
left: 120px;
bottom: 12px}
#ProcSlack {
position: absolute;
width: 64px;
text-align: right;
left: 190px;
bottom: 12px}
#ProcRun {
position: absolute;
width: 64px;
text-align: right;
left: 260px;
bottom: 12px}
#PanelSurface {
height: 100%;
width: 100%}

View File

@@ -148,17 +148,16 @@
<button id=LeftPanelBtn class=plainButton title="Some day there may be a Left Panel">Left Panel</button>
<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=ProcRun title="Average Processor run time (ms)"></div>
<div id=VersionDiv class=caption>
retro-220 <span id=EmulatorVersion>?.??</span>
</div>
</div>
<div id=Diagnostics>
<br>
Proc Delta: <input id=ProcDelta class="rj" type=text size=10>
&nbsp;&nbsp;
Latency: <input id=LastLatency class="rj" type=text size=10>
<table id=CallbackTable>
<thead>
<tr>

View File

@@ -17,7 +17,7 @@ function B220ControlConsole(p, systemShutdown) {
/* Constructor for the ControlConsole object */
var h = 600;
var w = 1064;
var mnemonic = "ControlConsole";
var mnemonic = "Console";
var inputConfig = p.config.getNode("ConsoleInput");
var outputConfig = p.config.getNode("ConsoleOutput");
var u;
@@ -30,12 +30,12 @@ function B220ControlConsole(p, systemShutdown) {
this.keyboard = new B220ConsoleKeyboard(p);
this.boundLamp_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.lamp_Click);
this.boundPowerBtn_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.powerBtn_Click);
this.boundSwitch_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.switch_Click);
this.boundStartBtn_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.startBtn_Click);
this.boundResetTimer = B220Util.bindMethod(this, B220ControlConsole.prototype.resetTimer);
this.boundUpdatePanel = B220Util.bindMethod(this, B220ControlConsole.prototype.updatePanel);
this.boundMeatballMemdump = B220ControlConsole.prototype.meatballMemdump.bind(this);
this.boundLamp_Click = B220ControlConsole.prototype.lamp_Click.bind(this);
this.boundPowerBtn_Click = B220ControlConsole.prototype.powerBtn_Click.bind(this);
this.boundSwitch_Click = B220ControlConsole.prototype.switch_Click.bind(this);
this.boundResetTimer = B220ControlConsole.prototype.resetTimer.bind(this);
this.boundUpdatePanel = B220ControlConsole.prototype.updatePanel.bind(this);
// Configure the console input unit objects. These are paper-tape readers.
this.inputUnit = [
@@ -109,6 +109,24 @@ 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
" ", "_", " ", ".", "\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
/**************************************/
B220ControlConsole.prototype.$$ = function $$(e) {
return this.doc.getElementById(e);
@@ -150,6 +168,234 @@ B220ControlConsole.prototype.beforeUnload = function beforeUnload(ev) {
return msg;
};
/**************************************/
B220ControlConsole.prototype.meatballMemdump = function meatballMemdump() {
/* Opens a temporary window and formats the current processor and memory
state to it */
var doc = null; // loader window.document
var p = this.p; // local copy of Processor object
var paper = null; // <pre> element to receive dump lines
var trimRightRex = /[\s\uFEFF\xA0]+$/;
var win = this.window.open("./B220FramePaper.html", this.mnemonic + "-MEMDUMP",
"location=no,scrollbars=yes,resizable,width=800,height=600");
var xlate = B220ControlConsole.codeXlate; // local copy
function formatWord(w) {
/* Formats a 220 numeric word as "S DDDDDDDDDD" and returns it */
var s = padBCD(w, 11);
return s.substring(0, 1) + " " + s.substring(1);
}
function padBCD(value, digits) {
/* Formats "value" as a BCD number of "digits" length, left-padding with
zeroes as necessary */
var text = value.toString(16);
if (value < 0) {
return text;
} else {
return padLeft(text, digits, "0");
}
}
function padLeft(text, minLength, c) {
/* Pads "text" on the left to a total length of "minLength" with "c" */
var s = text.toString();
var len = s.length;
var pad = c || " ";
while (len++ < minLength) {
s = pad + s;
}
return s;
}
function trimRight(text) {
/* Returns the string with all terminating whitespace removed from "text" */
return text.replace(trimRightRex, '');
}
function wordToANSI(value) {
/* Converts the "value" as a 220 word to a five-character string and returns it */
var c; // current character
var s = ""; // working string value
var w = value; // working word value
var x; // character counter
for (x=0; x<5; ++x) {
c = w % 256;
w = (w-c)/256;
s = xlate[c] + s;
}
return s;
}
function writer(text) {
/* Outputs one line of text to the dump window */
paper.appendChild(doc.createTextNode(trimRight(text) + "\n"));
}
function dumpProcessorState() {
/* Dumps the register state for the Processor */
var s = "";
var x = 0;
writer("");
writer("Processor:");
writer("");
writer("A: " + formatWord(p.A.value) + " R: " + formatWord(p.R.value) +
" D: " + formatWord(p.D.value));
writer("");
s = padBCD(p.C.value, 10);
s = s.substring(0, 4) + " " + s.substring(4, 6) + " " + s.substring(6);
writer("B: " + padBCD(p.B.value, 4) + " P: " + padBCD(p.P.value, 4) + " C: " + s +
" E: " + padBCD(p.E.value, 4) + " S: " + padBCD(p.S.value, 4));
writer("");
s = "Program Switches:";
for (x=1; x<=10; ++x) {
if (p["PC" + x%10 + "SW"]) {
s += " " + x%10;
} else {
s += " .";
}
}
if (p.SONSW) {s += " S-ON"}
if (p.SUNITSSW) {s += " S-UNITS"}
if (p.STOCSW) {s += " S-TO-C"}
if (p.STOPSW) {s += " S-TO-P"}
writer(s);
s = "Flip-Flops:";
if (p.digitCheckAlarm.value) {s += " DCK"}
if (p.ALT.value) {s += " ALT"}
if (p.AST.value) {s += " AST"}
if (p.CCT.value) {s += " CCT"}
if (p.CRT.value) {s += " CRT"}
if (p.DPT.value) {s += " DPT"}
if (p.EWT.value) {s += " EWT"}
if (p.EXT.value) {s += " EXT"}
if (p.HAT.value) {s += " HAT"}
if (p.HCT.value) {s += " HCT"}
if (p.HIT.value) {s += " HIT"}
if (p.MAT.value) {s += " MAT"}
if (p.MET.value) {s += " MET"}
if (p.MNT.value) {s += " MNT"}
if (p.OFT.value) {s += " OFT"}
if (p.PAT.value) {s += " PAT"}
if (p.PRT.value) {s += " PRT"}
if (p.PZT.value) {s += " PZT"}
if (p.RPT.value) {s += " RPT"}
if (p.RUT.value) {s += " RUT"}
if (p.SST.value) {s += " SST"}
if (p.TAT.value) {s += " TAT"}
if (p.UET.value) {s += " UET"}
writer(s);
s = " ";
if (p.systemNotReady.value) {s += " SNR"}
if (p.computerNotReady.value) {s += " CNR"}
if (p.compareLowLamp.value) {s += " LOW"}
if (p.compareEqualLamp.value) {s += " EQUAL"}
if (p.compareLowLamp.value) {s += " HIGH"}
if (p.C10.value) {s += " C10"}
if (p.DST.value) {s += " DST"}
if (p.LT1.value) {s += " LT1"}
if (p.LT2.value) {s += " LT2"}
if (p.LT3.value) {s += " LT3"}
if (p.SCI.value) {s += " SCI"}
if (p.SGT.value) {s += " SGT"}
if (p.SUT.value) {s += " SUT"}
if (p.TBT.value) {s += " TBT"}
if (p.TCT.value) {s += " TCT"}
if (p.TPT.value) {s += " TPT"}
if (p.TWT.value) {s += " TWT"}
writer(s);
}
function memdumpDriver() {
/* Driver for formatting the memory and Processor state dump */
var addr = 0;
var dupCount = 0;
var lastLine = "";
var line = "";
var top = p.memorySize-1; // max memory address
var x = 0; // image data index
function dumpDupes() {
/* Outputs the duplicate-line message, if any */
if (dupCount > 0) {
writer(".... ..... DUP FOR " + dupCount + " LINE" + (dupCount>1 ? "S" : "") +
" THRU " + padLeft(addr-1, 4, "0") + " .....");
dupCount = 0;
}
}
while (paper.firstChild) { // delete any existing <pre> content
paper.removeChild(paper.firstChild);
}
writer("retro-220 Processor State and Memory Dump : " + new Date().toString());
dumpProcessorState();
// Dump all of memory
writer("");
writer("Memory: ");
writer("");
addr = 0;
while (addr <= top) {
// Format the next five words
line = "";
for (x=0; x<5; ++x) {
line += " " + formatWord(p.MM[addr+x]);
} // for x
// Check for duplicate lines; write a non-duplicate
if (line == lastLine) {
++dupCount;
} else {
dumpDupes();
lastLine = line;
line = padLeft(addr, 4, "0") + line + " ";
for (x=0; x<5; ++x) {
line += wordToANSI(p.MM[addr+x]);
} // for x
writer(line);
}
addr += 5;
} // for addr
dumpDupes();
writer("");
writer("End dump, memory size: " + (top+1).toString() + " words");
}
function memdumpSetup() {
/* Loads a status message into the "paper" rendering area, then calls
dumpDriver after a short wait to allow the message to appear */
win.removeEventListener("load", memdumpSetup, false);
doc = win.document;
doc.title = "retro-220 Console: Meatball Memdump";
paper = doc.getElementById("Paper");
writer("Rendering the dump... please wait...");
setTimeout(memdumpDriver, 50);
}
// Outer block of meatBallMemdump
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
win.focus();
win.addEventListener("load", memdumpSetup, false);
};
/**************************************/
B220ControlConsole.prototype.displayCallbackState = function displayCallbackState() {
/* Builds a table of outstanding callback state */
@@ -259,9 +505,10 @@ 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";
/********** DEBUG **********
this.$$("ProcDelta").value = p.procSlackAvg.toFixed(2);
this.$$("LastLatency").value = p.delayDeltaAvg.toFixed(2);
this.displayCallbackState();
***************************/
};
@@ -737,6 +984,7 @@ B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad() {
this.resetTransferSwitch.addEventListener("click", this.boundSwitch_Click);
this.tcuClearSwitch.addEventListener("click", this.boundSwitch_Click);
this.$$("BurroughsMeatball").addEventListener("click", this.boundMeatballMemdump);
this.$$("IntervalTimerResetBtn").addEventListener("click", this.boundResetTimer);
this.$$("PowerOffBtn").addEventListener("click", this.boundPowerBtn_Click);

File diff suppressed because it is too large Load Diff

View File

@@ -197,6 +197,13 @@ SELECT {
right: 16px}
#MTUnloadedLight {
top: 36px;
right: 8px;
width: 64px}
#MTLaneNrLight {
color: black;
font-weight: bold;
top: 60px;
right: 8px;
width: 64px}

View File

@@ -87,6 +87,7 @@
<img id=MTReel src="./resources/MagTapeReel.jpg">
<div id=MTUnloadedLight class=annunciator>UNLOADED</div>
<div id=MTLaneNrLight class=annunciator>LANE 0</div>
<div id=MTAtBOTLight class=annunciator>AT BOT</div>
<div id=MTAtEOTLight class=annunciator>AT EOT</div>
<div id=MTRewindingLight class=annunciator>REWINDING</div>

File diff suppressed because it is too large Load Diff

View File

@@ -49,7 +49,7 @@
<option value="100">100-word blocks
</select>
&nbsp;&nbsp;
<input id=MTLoadWriteEnableCheck type=checkbox value="1">
<input id=MTLoadWriteEnableCheck type=checkbox value="1" checked>
<label for=MTLoadWriteEnableCheck>Write Enabled</label>
</div>

View File

@@ -1,5 +1,5 @@
CACHE MANIFEST
# retro-220 emulator 0.03b, 2017-11-02 12:30
# retro-220 emulator 0.03c, 2017-11-17 06:15
CACHE:
../emulator/B220Processor.js
B220.css