1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-04-25 20:01:52 +00:00

Release emulator version 0.18:

1. Implement system state dump in B5500Console and B5500SyllableDebugger.
2. Correct reporting of extended tape drive status in Mod-III result descriptors.
3. Further fixes for tape drive status oscillation at BOT.
4. Correct Processor TRN syllable (was not clearing zone bits).
5. Correct Processor TRW syllable Invalid Address fault when source string ended at address @77777.
6. Remove extraneous parameter in cc.fieldIsolate call for Processor ISO syllable (thanks to Peter Grootswagers).
7. Implement Power Off and Dump buttons in SyllableDebugger.
This commit is contained in:
paul.kimpel@digm.com
2013-12-30 19:24:01 +00:00
parent 2dadec8b8b
commit c15fdc89c9
6 changed files with 543 additions and 74 deletions

View File

@@ -61,7 +61,7 @@ function B5500CentralControl(global) {
/**************************************/
/* Global constants */
B5500CentralControl.version = "0.17";
B5500CentralControl.version = "0.18";
B5500CentralControl.memReadCycles = 2; // assume 2 µs memory read cycle time (the other option was 3 µs)
B5500CentralControl.memWriteCycles = 4; // assume 4 µs memory write cycle time (the other option was 6 µs)
@@ -891,6 +891,150 @@ B5500CentralControl.prototype.runTest = function runTest(runAddr) {
this.P1.start();
};
B5500CentralControl.prototype.dumpSystemState = function dumpSystemState(caption, writer) {
/* Generates a dump of the processor states and all of memory
"caption is an identifying string that is output in the heading line.
"writer" is a function that is called to output lines of text to the outside
world. It takes two parameters:
"phase" is a numeric code indicating the type of line being output:
0 = initialization and heading line
1 = processor 1 state
2 = processor 2 state
32 = core memory
-1 = end of dump (text parameter not valid)
"text" is the line of text to be output.
*/
var addr;
var bic;
var dupCount = 0;
var lastLine = "";
var line;
var lineAddr;
var mod;
var x;
var accessor = { // Memory access control block
requestorID: "C", // Memory requestor ID
addr: 0, // Memory address
word: 0, // 48-bit data word
MAIL: 0, // Truthy if attempt to access @000-@777 in normal state
MPED: 0, // Truthy if memory parity error
MAED: 0 // Truthy if memory address/inhibit error
};
var BICtoANSI = [
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "#", "@", "?", ":", ">", "}",
"+", "A", "B", "C", "D", "E", "F", "G",
"H", "I", ".", "[", "&", "(", "<", "~",
"|", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "$", "*", "-", ")", ";", "{",
" ", "/", "S", "T", "U", "V", "W", "X",
"Y", "Z", ",", "%", "!", "=", "]", "\""];
function padLeft(text, minLength, char) {
/* Pads "text" on the left to a total length of "minLength" with "char" */
var s = text.toString();
var len = s.length;
var pad = char || " ";
while (len++ < minLength) {
s = pad + s;
}
return s;
}
function padOctal(value, octades) {
/* Formats "value" as an octal number of "octades" length, left-padding with
zeroes as necessary */
var text = value.toString(8);
if (value >= 0) {
return padLeft(text, octades, "0");
} else {
return text;
}
}
function convertWordtoANSI(value) {
/* Converts the "value" as a B5500 word to an eight 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<8; x++) {
c = w % 64;
w = (w-c)/64;
s = BICtoANSI[c] + s;
}
return s;
}
function dumpProcessorState(px, nr) {
/* Dumps the register state for the specified processor */
writer(nr, "Processor P" + nr + " = " + px.mnemonic + ":");
writer(nr, "NCSF=" + px.NCSF + " CWMF=" + px.CWMF + " MSFF=" + px.MSFF + " SALF=" + px.SALF +
" VARF=" + px.VARF);
writer(nr, "C=" + padOctal(px.C, 5) + " L=" + px.L + " P=" + padOctal(px.P, 16) + " PROF=" + px.TROF +
" T=" + padOctal(px.T, 4) + " TROF=" + px.TROF);
writer(nr, "I=" + padLeft(px.I.toString(2), 8, "0") + " E=" + padLeft(px.E.toString(2), 6, "0") +
" Q=" + padLeft(px.Q.toString(2), 9, "0") + " [bit masks]");
writer(nr, "M=" + padOctal(px.M, 5) + " G=" + px.G + " H=" + px.H);
writer(nr, "S=" + padOctal(px.S, 5) + " K=" + px.K + " V=" + px.V);
writer(nr, "F=" + padOctal(px.F, 5) + " R=" + padOctal(px.R, 3));
writer(nr, "X= " + padOctal(px.X, 13) + " Y=" + padOctal(px.Y, 2) + " Z=" + padOctal(px.Z, 2) +
" N=" + px.N);
writer(nr, "A=" + padOctal(px.A, 16) + " AROF=" + px.AROF);
writer(nr, "B=" + padOctal(px.B, 16) + " BROF=" + px.BROF);
}
writer(0, "B5500 State Dump by " + (caption || "(unknown)") + " : " + new Date().toString());
// Dump the processor states
dumpProcessorState(this.P1, 1);
if (this.P2) {
dumpProcessorState(this.P2, 2);
}
// Dump all of memory
for (mod=0; mod<0x8000; mod+=0x1000) {
for (addr=0; addr<0x1000; addr+=4) {
lineAddr = mod+addr;
line = " ";
bic = " ";
for (x=0; x<4; x++) {
accessor.addr = lineAddr+x;
this.fetch(accessor);
if (accessor.MPED) {
line += " << PARITY >> ";
bic += "????????";
} else if (accessor.MAED) {
line += " << INV ADDR >> ";
bic += "????????";
} else {
line += " " + padOctal(accessor.word, 16);
bic += convertWordtoANSI(accessor.word);
}
} // for x
if (line == lastLine && lineAddr < 0x7FFC) {
dupCount++;
} else {
if (dupCount > 0) {
writer(32, "..... ................ for " + dupCount*4 + " words");
dupCount = 0;
}
writer(32, padOctal(lineAddr, 5) + line + bic);
lastLine = line;
}
} // for addr
} // for mod
writer(-1, null);
};
/**************************************/
B5500CentralControl.prototype.configureSystem = function configureSystem() {
/* Establishes the hardware module configuration from the

View File

@@ -70,7 +70,9 @@ function B5500IOUnit(ioUnitID, cc) {
this.boundFinishGeneric = this.makeFinish(this.finishGeneric);
this.boundFinishGenericRead = this.makeFinish(this.finishGenericRead);
this.boundFinishSPORead = this.makeFinish(this.finishSPORead);
this.boundFinishTapeIO = this.makeFinish(this.finishTapeIO);
this.boundFinishTapeRead = this.makeFinish(this.finishTapeRead);
this.boundFinishTapeWrite = this.makeFinish(this.finishTapeWrite);
this.initiateStamp = 0; // Timestamp of last I/O initiation on this unit
@@ -960,11 +962,41 @@ B5500IOUnit.prototype.finishSPORead = function finishSPORead(errorMask, length)
};
/**************************************/
B5500IOUnit.prototype.finishTapeRead = function finishDiskRead(errorMask, length) {
B5500IOUnit.prototype.finishTapeIO = function finishTapeIO(errorMask, count) {
/* For Mod III I/O Units, extra status bits can be reported in the word-count
field. The driver will report these in the higher-order bits of errorMask.
mask & 0x040000 => tape at EOT (becomes D14F)
mask & 0x080000 => tape at BOT (becomes D13F)
mask & 0x100000 => blank tape (becomes D12F)
mask & 0x200000 => reserved for relocated D29F memory parity bit (becomes D11F)
The original memory parity bit in D29F is relocated to D11F, and both
D02F and D29F are set unconditionally.
In addition, the count of characters in a paritally-filled final word is
reported in the low-order three bits of the word count field.
For a forward read, this is the number of characters in the last partial word.
For a backward read, this is 7 minus the number of characters */
var partialCount = (errorMask % 0x040000) >>> 15;
if (errorMask & 0x1C0008) {
partialCount += ((errorMask % 0x200000) >>> 18) * 0x08 +
(errorMask & 0x08) * 0x08; // relocate the memory parity bit
this.D02F = 1; // mark as a Mod III RD
errorMask |= 0x08; // set the original mem parity bit (D29) unconditionally
}
this.DwordCount = partialCount;
this.finishGeneric(errorMask, count);
//console.log(this.mnemonic + " finishTapeIO: " + errorMask.toString(8) + " for " + count.toString() +
// ", D=" + this.D.toString(8));
};
/**************************************/
B5500IOUnit.prototype.finishTapeRead = function finishTapeRead(errorMask, length) {
/* Handles I/O finish for a tape drive read operation */
var count;
var memWords = (length+7) >>> 3;
var partialCount = (errorMask % 0x040000) >>> 15;
if (this.D23F && memWords > this.DwordCount) {
memWords = this.DwordCount;
@@ -984,29 +1016,19 @@ B5500IOUnit.prototype.finishTapeRead = function finishDiskRead(errorMask, length
}
}
// For Mod III I/O Units, extra status bits can be reported in the word-count
// field. The driver will report these in the higher-order bits of errorMask.
// mask & 0x040000 => tape at EOT (becomes D14F)
// mask & 0x080000 => tape at BOT (becomes D13F)
// mask & 0x100000 => blank tape (becomes D12F)
// mask & 0x200000 => reserved for relocated D29F memory parity bit (becomes D11F)
// The original memory parity bit in D29F is relocated to D11F, and both
// D02F and D29F are set unconditionally.
this.finishTapeIO(errorMask, count);
};
// In addition, the count of characters in a paritally-filled final word is
// reported in the low-order three bits of the word count field. For a forward
// read, this is the number of characters in the last partial word. For a back-
// ward read, this is 7 minus the number of characters.
/**************************************/
B5500IOUnit.prototype.finishTapeWrite = function finishTapeWrite(errorMask, length) {
/* Handles I/O finish for a tape drive write operation */
if ((errorMask & 0x3C0000) || this.D29F) {
this.DwordCount = partialCount +
((errorMask % 0x400000) >>> 18) * 0x08 +
this.D29F * 0x40; // relocate the memory parity bit
this.D02F = 1; // mark as a Mod III RD
errorMask |= 0x08; // set the original mem parity bit unconditionally
}
/*** Temporary stub until tape write is implemented ***/
this.finishGeneric(errorMask, count);
this.finishTapeIO(errorMask, length);
//console.log(this.mnemonic + " finishTapeWr: " + errorMask.toString(8) + " for " + length.toString() +
// ", D=" + this.D.toString(8));
};
/**************************************/
@@ -1021,17 +1043,17 @@ B5500IOUnit.prototype.initiateTapeIO = function initiateTapeIO(u) {
this.D30F = 1; // (MAINTENANCE I/Os NOT YET IMPLEMENTED)
this.finish();
} else if (this.D23F && this.DwordCount == 0) { // forward or backward space
u.space(this.boundFinishGeneric, 0, this.D22F);
u.space(this.boundFinishTapeIO, 0, this.D22F);
} else { // some sort of actual read
memWords = (this.D23F ? this.DwordCount : this.buffer.length);
u.read(this.boundFinishTapeRead, this.buffer, memWords*8, this.D21F, this.D22F);
}
} else { // tape write operation
if (this.D23F && this.DwordCount == 0) {// interrogate drive status
u.writeInterrogate(this.boundFinishGeneric, 0);
u.writeInterrogate(this.boundFinishTapeIO, 0);
} else if (this.D18F) { // memory inhibit
if (this.D22F) { // backward write => rewind
u.rewind(this.boundFinishGeneric);
u.rewind(this.boundFinishTapeIO);
} else {
this.D30F = 1; // (ERASE NOT YET IMPLEMENTED)
this.finish();

View File

@@ -1031,8 +1031,9 @@ B5500Processor.prototype.streamCharacterToDest = function streamCharacterToDest(
/**************************************/
B5500Processor.prototype.streamNumericToDest = function streamNumericToDest(count, zones) {
/* Transfers character transfers from source to destination for the TRS syllable.
"count" is the number of source characters to transfer */
/* Transfers from source to destination for the TRN and TRZ syllables. "count"
is the number of source characters to transfer. If transferring numerics and the
low-order character has a negative sign (BA=10), sets MSFF=1 */
var aBit; // A register bit nr
var aw; // current A register word
var bBit; // B register bit nr
@@ -1062,11 +1063,8 @@ B5500Processor.prototype.streamNumericToDest = function streamNumericToDest(coun
c = this.cc.fieldIsolate(aw, aBit, 6);
if (zones) { // transfer only the zone portion of the char
bw = this.cc.fieldInsert(bw, bBit, 2, c >>> 4);
} else { // transfer only the numeric portion of the char
bw = this.cc.fieldInsert(bw, bBit+2, 4, c);
if (count == 1 && (c & 0x30) == 0x20) {
this.MSFF = 1; // neg. sign
}
} else { // transfer the numeric portion with a zero zone
bw = this.cc.fieldInsert(bw, bBit, 6, (c & 0x0F));
}
count--;
if (bBit < 42) {
@@ -1102,6 +1100,9 @@ B5500Processor.prototype.streamNumericToDest = function streamNumericToDest(coun
} while (count);
this.B = bw;
this.Y = c; // for display purposes only
if (!zones && (c & 0x30) == 0x20) {
this.MSFF = 1; // last char had a negative sign
}
}
};
@@ -3087,9 +3088,14 @@ B5500Processor.prototype.run = function run() {
this.storeAviaS(); // [S] = A
this.S++;
this.M++;
this.loadAviaM(); // A = [M]
} while (--variant);
if (--variant) {
this.loadAviaM(); // A = [M]
} else {
break;
}
} while (true);
}
this.AROF = 0;
break;
case 0x06: // XX06: SED=Set destination address
@@ -3629,7 +3635,7 @@ B5500Processor.prototype.run = function run() {
break;
case 0x3D: // XX75: TRN=Transfer source numerics
this.MSFF = 0; // initialize true-false FF
this.MSFF = 0; // initialize for negative sign test
this.streamNumericToDest(variant, false);
break;
@@ -4484,7 +4490,7 @@ B5500Processor.prototype.run = function run() {
this.A = cc.fieldIsolate(this.A, t1, t2);
} else { // handle wrap-around in the source value
this.A = cc.fieldInsert(
cc.fieldIsolate(this.A, 0, t2-48+t1, t1+t2-48), 48-t2, 48-t1,
cc.fieldIsolate(this.A, 0, t2-48+t1), 48-t2, 48-t1,
cc.fieldIsolate(this.A, t1, 48-t1));
}
// approximate the shift cycle counts

View File

@@ -84,6 +84,7 @@ window.addEventListener("load", function() {
$$("LoadSelectBtn").disabled = false;
$$("LoadBtn").disabled = false;
$$("HaltBtn").disabled = true;
$$("MemoryCheckBtn").disabled = false;
window.focus();
if (showAnnunciators) {
$$("CentralControl").style.visibility = "visible";
@@ -108,6 +109,7 @@ window.addEventListener("load", function() {
$$("LoadSelectBtn").disabled = true;
$$("LoadBtn").disabled = true;
$$("HaltBtn").disabled = true;
$$("MemoryCheckBtn").disabled = true;
if (timer) {
clearTimeout(timer);
timer = null;
@@ -165,6 +167,85 @@ window.addEventListener("load", function() {
}
}
function dumpState(caption) {
/* Generates a dump of the processor states and all of memory */
var doc;
var lastPhase = -2;
var win = window.open("", "", "resizable,scrollbars,status");
var x;
var htmlMatch = /[<>&"]/g; // regular expression for escaping HTML text
function escapeHTML(text) {
/* Returns "text" as escaped HTML */
function htmlFilter(char) {
/* Used to escape HTML-sensitive characters in a string */
switch (char) {
case "&":
return "&amp;";
case "<":
return "&lt;";
case ">":
return "&gt;";
case "\"":
return "&quot;";
default:
return char;
}
}
return text.replace(htmlMatch, htmlFilter);
}
function writer(phase, text) {
/* Call-back function for cc.dumpSystemState */
switch (phase) {
case 0:
lastPhase = phase;
doc.writeln(escapeHTML(text));
break;
case 1:
case 2:
if (phase == lastPhase) {
doc.writeln(escapeHTML(text));
} else {
lastPhase = phase;
doc.writeln();
doc.writeln(escapeHTML(text));
doc.writeln();
}
break;
case 32:
if (phase != lastPhase) {
lastPhase = phase;
doc.writeln();
}
doc.writeln();
doc.writeln(escapeHTML(text));
break;
case -1:
break;
} // switch
}
doc = win.document;
doc.open();
doc.writeln("<html><head><title>B5500 Console State Dump</title>");
doc.writeln("</head><body>");
doc.write("<pre>");
cc.dumpSystemState(caption, writer);
doc.writeln("</pre></body></html>")
doc.close();
win.focus();
}
function displayCallbacks() {
/* Builds a table of outstanding callbacks */
var cb;
@@ -479,6 +560,10 @@ window.addEventListener("load", function() {
$$("RetroVersion").innerHTML = B5500CentralControl.version;
if (!checkBrowser()) {
$$("BurroughsLogo").addEventListener("click", BurroughsLogo_Click, false);
$$("B5500Logo").addEventListener("click", function(ev) {
alert("Dynamic configuration management is not yet implemented");
});
$$("PowerOnBtn").addEventListener("click", PowerOnBtn_Click, false);
$$("PowerOffBtn").addEventListener("click", PowerOffBtn_Click, false);
$$("HaltBtn").addEventListener("click", HaltBtn_Click, false);
@@ -490,6 +575,9 @@ window.addEventListener("load", function() {
B5500SystemConfiguration.PB ^= true;
$$("RetroVersion").style.color = (B5500SystemConfiguration.PB ? "yellow" : "white");
});
$$("MemoryCheckBtn").addEventListener("click", function(ev) {
dumpState("Memory Check Button");
});
aControl = $$("AControlBtn");
aNormal = $$("ANormalBtn");
@@ -510,7 +598,7 @@ window.addEventListener("load", function() {
<button id=HaltBtn class="redButton" DISABLED>HALT</button>
<button id=NotReadyBtn class=whiteButton>NOT READY</button>
<button id=MemoryCheckBtn class=redButton>MEMORY CHECK</button>
<button id=MemoryCheckBtn class=redButton DISABLED>MEMORY CHECK</button>
<button id=LoadBtn class="blackButton blackLit" DISABLED>LOAD</button>
<button id=LoadSelectBtn class="yellowButton" DISABLED>CARD LOAD SELECT</button>

View File

@@ -274,10 +274,6 @@ B5500MagTapeDrive.prototype.setTapeRemote = function setTapeRemote(ready) {
this.statusChange(0);
this.removeClass(this.$$("MTRemoteBtn"), "yellowLit");
this.addClass(this.$$("MTLocalBtn"), "yellowLit");
if (this.timer) {
clearCallback(this.timer);
this.timer = null;
}
}
}
};
@@ -319,7 +315,7 @@ B5500MagTapeDrive.prototype.tapeRewind = function tapeRewind(makeReady) {
this.timer = null;
this.busy = false;
this.removeClass(this.$$("MTRewindingLight"), "whiteLit");
if (makeReady) {
if (makeReady && this.tapeState == this.tapeRemote) {
this.ready = true;
this.statusChange(1);
}
@@ -515,7 +511,7 @@ B5500MagTapeDrive.prototype.bcdSpaceBackward = function bcdSpaceBackward(checkEO
if (imgIndex <= 0) {
this.setAtBOT(true);
this.errorMask |= 0x100010; // set blank-tape and parity bits
this.errorMask |= 0x100000; // set blank-tape bit
} else {
if (this.atEOT) {
this.setAtEOT(false);
@@ -652,7 +648,7 @@ B5500MagTapeDrive.prototype.bcdReadBackward = function bcdReadBackward(oddParity
if (imgIndex <= 0) {
this.setAtBOT(true);
this.errorMask |= 0x100010; // set blank-tape and parity bits
this.errorMask |= 0x100000; // set blank-tape bit
} else {
if (this.atEOT) {
this.setAtEOT(false);
@@ -930,9 +926,10 @@ B5500MagTapeDrive.prototype.writeInterrogate = function writeInterrogate(finish,
} else if (!this.ready) {
finish(0x04, 0); // report unit not ready
} else {
this.buildErrorMask(0, true);
if (!this.writeRing) {
this.errorMask |= 0x50; // RD bits 26 & 28 => no write ring
if (this.writeRing) {
this.buildErrorMask(0, true);
} else {
this.errorMask |= 0x50; // RD bits 26 & 28 => no write ring, don't return Mod III bits
}
finish(this.errorMask, 0);
}

View File

@@ -40,6 +40,8 @@ var running = false; // true if in run mode
var runSilently = false; // true if system state is not to be refreshed after each step
var stopAddress = 0; // run-until-address stop point
var htmlMatch = /[<>&"]/g; // regular expression for escaping HTML text
var accessor = { // Memory access control block
requestorID: "A", // Memory requestor ID
addr: 0, // Memory address
@@ -265,6 +267,52 @@ function setText(id, text) {
}
}
function escapeHTML(text) {
/* Returns "text" as escaped HTML */
function htmlFilter(char) {
/* Used to escape HTML-sensitive characters in a string */
switch (char) {
case "&":
return "&amp;";
case "<":
return "&lt;";
case ">":
return "&gt;";
case "\"":
return "&quot;";
default:
return char;
}
}
return text.replace(htmlMatch, htmlFilter);
}
function padLeft(text, minLength, char) {
/* Pads "text" on the left to a total length of "minLength" with "char" */
var s = text.toString();
var len = s.length;
var pad = char || " ";
while (len++ < minLength) {
s = pad + s;
}
return s;
}
function padOctal(value, octades) {
/* Formats "value" as an octal number of "octades" length, left-padding with
zeroes as necessary */
var text = value.toString(8);
if (value >= 0) {
return padLeft(text, octades, "0");
} else {
return text;
}
}
function parseToOctal(e) {
/* Obtains the .value from the element "e", parses it, and returns the
result as a B5500 numeric word. If the element text contains any of "-+eE."
@@ -320,20 +368,6 @@ function parseToOctal(e) {
return v;
}
function padOctal(value, octades) {
/* Formats "value" as an octal number of "octades" length, left-padding with
zeroes as necessary */
var text = value.toString(8);
var len = text.length;
if (value >= 0) {
while (len++ < octades) {
text = "0" + text;
}
}
return text;
}
function decodeSyllable(syllable, mode, level, msff) {
/* Decodes the B5500 operator "syllable" and returns a string formatted with the
mnemonic description of that syllable.
@@ -660,6 +694,171 @@ function displaySystemState() {
//window.focus();
}
function dumpState__OLD(caption) {
/* Generates a dump of the processor states and all of memory */
var addr;
var bic;
var doc;
var dupCount = 0;
var lastLine = "";
var line;
var lineAddr;
var mod;
var win = window.open("", "", "resizable,scrollbars,status");
var x;
function convertWordtoANSI(value) {
/* Converts the "value" as a B5500 word to an eight 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<8; x++) {
c = w % 64;
w = (w-c)/64;
s = BICtoANSI[c] + s;
}
return s;
}
function dumpProcessorState(px) {
/* Dumps the register state for the specified processor */
var procNr = (px === cc.P1 ? "1" : "2");
doc.writeln();
doc.writeln("Processor P" + procNr + " = " + px.mnemonic + ":");
doc.writeln();
doc.writeln("NCSF=" + px.NCSF + " CWMF=" + px.CWMF + " MSFF=" + px.MSFF + " SALF=" + px.SALF +
" VARF=" + px.VARF);
doc.writeln("C=" + padOctal(px.C, 5) + " L=" + px.L + " P=" + padOctal(px.P, 16) + " PROF=" + px.TROF +
" T=" + padOctal(px.T, 4) + " TROF=" + px.TROF);
doc.writeln("I=" + padLeft(px.I.toString(2), 8, "0") + " E=" + padLeft(px.E.toString(2), 6, "0") +
" Q=" + padLeft(px.Q.toString(2), 12, "0") + " [bit masks]");
doc.writeln("M=" + padOctal(px.M, 5) + " G=" + px.G + " H=" + px.H);
doc.writeln("S=" + padOctal(px.S, 5) + " K=" + px.K + " V=" + px.V);
doc.writeln("F=" + padOctal(px.F, 5) + " R=" + padOctal(px.R, 3));
doc.writeln();
doc.writeln("X= " + padOctal(px.X, 13) + " Y=" + padOctal(px.Y, 2) + " Z=" + padOctal(px.Z, 2) +
" N=" + px.N);
doc.writeln("A=" + padOctal(px.A, 16) + " AROF=" + px.AROF);
doc.writeln("B=" + padOctal(px.B, 16) + " BROF=" + px.BROF);
}
doc = win.document;
doc.open();
doc.writeln("<html><head><title>B5500 Syllable Debugger State Dump</title>");
doc.writeln("</head><body>");
doc.writeln("<pre>Dump by " + escapeHTML(caption || "(unknown)") + " : " + new Date().toString());
dumpProcessorState(cc.P1);
if (cc.P2) {
dumpProcessorState(cc.P2);
}
doc.writeln();
for (mod=0; mod<0x8000; mod+=0x1000) {
for (addr=0; addr<0x1000; addr+=4) {
lineAddr = mod+addr;
line = bic = "";
for (x=0; x<4; x++) {
accessor.addr = lineAddr+x;
cc.fetch(accessor);
if (accessor.MAIL) {
line += escapeHTML(" << ADDR INH >> ");
bic += "????????";
} else if (accessor.MPED) {
line += escapeHTML(" << PARITY >> ");
bic += "????????";
} else if (accessor.MAED) {
line += escapeHTML(" << INV ADDR >> ");
bic += "????????";
} else {
line += " " + padOctal(accessor.word, 16);
bic += convertWordtoANSI(accessor.word);
}
} // for x
if (line == lastLine && lineAddr < 0x7FFC) {
dupCount++;
} else {
if (dupCount > 0) {
doc.writeln();
doc.writeln("..... ................ for " + dupCount*4 + " words");
dupCount = 0;
}
doc.writeln();
doc.write(padOctal(lineAddr, 5));
doc.write(" ");
doc.write(line);
doc.write(" ");
doc.writeln(escapeHTML(bic));
lastLine = line;
}
} // for addr
} // for mod
doc.writeln("</pre></body></html>")
doc.close();
win.focus();
}
function dumpState(caption) {
/* Generates a dump of the processor states and all of memory */
var doc;
var lastPhase = -2;
var win = window.open("", "", "resizable,scrollbars,status");
var x;
function writer(phase, text) {
/* Call-back function for cc.dumpSystemState */
switch (phase) {
case 0:
lastPhase = phase;
doc.writeln(escapeHTML(text));
break;
case 1:
case 2:
if (phase == lastPhase) {
doc.writeln(escapeHTML(text));
} else {
lastPhase = phase;
doc.writeln();
doc.writeln(escapeHTML(text));
doc.writeln();
}
break;
case 32:
if (phase != lastPhase) {
lastPhase = phase;
doc.writeln();
}
doc.writeln();
doc.writeln(escapeHTML(text));
break;
case -1:
break;
} // switch
}
doc = win.document;
doc.open();
doc.writeln("<html><head><title>B5500 Syllable Debugger State Dump</title>");
doc.writeln("</head><body>");
doc.write("<pre>");
cc.dumpSystemState(caption, writer);
doc.writeln("</pre></body></html>")
doc.close();
win.focus();
}
function establishSilence(beQuiet) {
/* Maintains synchronization between the global "runSilently" flag, the
RunSilently checkbox, and cc.inhCCI03F */
@@ -762,19 +961,14 @@ function runIt(ev) {
alert("P1.S out of range");
stopAddress = 0;
}
/***************************
if (px.C < 0x40) {
// There is an interrupt
switch (px.C) {
case 0x31: // P1 invalid address
case 0x32: // P1 stack overflow
case 0x3C: // P1 integer overflow
alert("Unexpected Processor Interrupt occurred");
stopAddress = 0;
break;
}
/********************
if (stopAddress == 0x31 && (px.I & 0x02)) { // There is an Invalid Address interrupt
dumpState("Invalid Address");
stopAddress = 0;
}
***************************/
********************/
if (--count <= 0) {
count = runningCycles;
break; // exit loop to pick up events
@@ -971,6 +1165,18 @@ function selectProcessor_onChange(ev) {
}
}
function powerOff_onClick(ev) {
/* Power off the system in response to the Power Off button */
cc.powerOff();
}
function dump_onClick(ev) {
/* Dumps the system state to a new window */
dumpState("User Requested");
}
function checkBrowser() {
/* Checks whether this browser can support the necessary stuff */
var missing = "";
@@ -1147,6 +1353,8 @@ function initialize() {
$$("FileSelector").addEventListener("change", fileSelector_onChange, false);
$$("HardwareLoad").addEventListener("click", hardwareLoad_onClick, false);
$$("SelectProcessor").addEventListener("change", selectProcessor_onChange, false);
$$("PowerOff").addEventListener("click", powerOff_onClick, false);
$$("Dump").addEventListener("click", dump_onClick, false);
$$("GoBtn").addEventListener("click", goIt, false);
$$("StepBtn").addEventListener("click", stepIt, false);
$$("RunBtn").addEventListener("click", runIt, false);
@@ -1203,6 +1411,10 @@ window.onload = function() {
<option value=1 selected>Show P1
<option value=2>Show P2
</select>
&nbsp;&nbsp;
<input id=PowerOff type=button value="Power Off">
&nbsp;&nbsp;
<input id=Dump type=button value="Dump">
</p>
<table id=RegisterBank1 class="normal border">