1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-05-01 22:17:00 +00:00

1. Release emulator version 0.11.

2. Change name of CentralCentrol bit() method to bitTest().
3. Correct length of data sent to printer by IOUnit if I/O descriptor has a zero length.
4. Implement Processor.isP1 property to optimize testing for Processor 1 vs 2.
5. Implement ability to delete the IndexedDB database for the disk subsystem in ColdLoader.
6. Implement "purist" mode in B5500Console to suppress display of emulator's extra annunciators.
7. Correct behavior of Input Request and Ready controls in SPOUnit.
This commit is contained in:
paul.kimpel@digm.com
2013-07-21 23:32:12 +00:00
parent dea0b37e98
commit c1731fc675
8 changed files with 113 additions and 86 deletions

View File

@@ -61,7 +61,7 @@ function B5500CentralControl() {
/**************************************/
/* Global constants */
B5500CentralControl.version = "0.10";
B5500CentralControl.version = "0.11";
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)
@@ -227,7 +227,7 @@ B5500CentralControl.prototype.clear = function clear() {
};
/**************************************/
B5500CentralControl.prototype.bit = function bit(word, bit) {
B5500CentralControl.prototype.bitTest = function bitTest(word, bit) {
/* Extracts and returns the specified bit from the word */
var e = 47-bit; // word lower power exponent
var p; // bottom portion of word power of 2
@@ -677,7 +677,7 @@ B5500CentralControl.prototype.testUnitReady = function testUnitReady(index) {
/* Determines whether the unit index "index" is currently in ready status.
Returns 1 if ready, 0 if not ready */
return (index ? this.bit(this.unitStatusMask, index) : 0);
return (index ? this.bitTest(this.unitStatusMask, index) : 0);
};
/**************************************/
@@ -685,7 +685,7 @@ B5500CentralControl.prototype.testUnitBusy = function testUnitBusy(index) {
/* Determines whether the unit index "index" is currently in use by any other
I/O Unit. Returns 1 if busy, 0 if not busy */
return (index ? this.bit(this.unitBusyMask, index) : 0);
return (index ? this.bitTest(this.unitBusyMask, index) : 0);
};
/**************************************/

View File

@@ -702,10 +702,10 @@ B5500IOUnit.prototype.initiatePrinterIO = function initiatePrinterIO(u) {
} else {
memWords = (this.D23F ? this.DwordCount : 0);
if (memWords > 0) {
chars = memWords*8;
chars = (memWords %= 0x20)*8;
} else {
memWords = 17; // assume a 132-character printer
chars = 132;
memWords = 15; // assume a 120-character printer
chars = 120; // (i.e., a descriptor for a Mod I or II IOU)
}
this.fetchBuffer(1, memWords);
this.Daddress = (addr-1) & 0x7FFF; // printer accesses memory backwards, so final address is initial-1

View File

@@ -113,6 +113,7 @@ B5500Processor.prototype.clear = function clear() {
this.US14X = 0; // STOP OPERATOR switch
this.isP1 = this === this.cc.P1; // True if this is the control processor
this.busy = 0; // Processor is running, not idle or halted
this.controlCycles = 0; // Current control-state cycle count (for UI display)
this.cycleCount = 0; // Cycle count for current syllable
@@ -135,7 +136,7 @@ B5500Processor.prototype.accessError = function accessError() {
} else if (this.accessor.MPED) {
this.I |= 0x01; // set I01F: memory parity error
this.cc.signalInterrupt();
if (this === this.cc.P1 && !this.NCSF) {
if (this.isP1 && !this.NCSF) {
this.busy = 0; // P1 memory parity in control state stops the proc
this.cycleLimit = 0; // exit this.run()
}
@@ -1289,7 +1290,7 @@ B5500Processor.prototype.storeForInterrupt = function storeForInterrupt(forTest)
this.BROF = 0;
this.AROF = 0;
if (forced) {
if (this === this.cc.P1) {
if (this.isP1) {
this.T = 0x89; // inject 0211=ITI into T register
} else {
this.stop(); // idle the processor
@@ -1299,7 +1300,7 @@ B5500Processor.prototype.storeForInterrupt = function storeForInterrupt(forTest)
this.CWMF = 0;
} else if (forTest) {
this.CWMF = 0;
if (this === this.cc.P1) {
if (this.isP1) {
this.loadBviaM(); // B = [M]: load DD for test
this.C = this.B % 0x8000;
this.L = 0;
@@ -4537,7 +4538,7 @@ B5500Processor.prototype.run = function run() {
* SECL: Syllable Execution Complete Level *
***************************************************************/
if ((this === this.cc.P1 ? this.cc.IAR : this.I) && this.NCSF) {
if ((this.isP1 ? this.cc.IAR : this.I) && this.NCSF) {
// there's an interrupt and we're in normal state
this.T = 0x0609; // inject 3011=SFI into T
this.Q &= 0xFFFEFF; // reset Q09F: adder mode for R-relative addressing

View File

@@ -1961,6 +1961,7 @@ window.addEventListener("load", function() {
alert("Disk database opened: " + name + " #" + disk.version);
$$("ColdstartBtn").disabled = false;
$$("FileSelector").disabled = false;
$$("DeleteDBBtn").disabled = false;
// dumpDisk(); // <<<<<<<<<<<<<< DEBUG <<<<<<<<<<<<<<<<<
@@ -1971,6 +1972,36 @@ window.addEventListener("load", function() {
}
/**************************************/
function deleteDiskDatabase(name, version) {
/* Attempts to permanently delete the disk subsystem database for the
specified "name". Clears the browser window if successful */
var req;
if (confirm("This will PERMANENTLY DELETE the emulator's entire disk subsystem.\n" +
"Are you sure you want to do this?")) {
if (confirm("Deletion of the disk subsystem CANNOT BE UNDONE.\n\nAre you really sure?")) {
disk = null; // invalidate the IDB handle
req = window.indexedDB.deleteDatabase(dbName);
req.onerror = function(ev) {
alert("Cannot delete the disk database: " + ev.target.error);
};
req.onblocked = function(ev) {
alert("Database.deleteDatabase is blocked -- cannot continue");
};
req.onsuccess = function(ev) {
alert("retro-B5500 disk subsystem database deleted successfully");
document.open();
document.write("B5500ColdLoader terminated.");
document.close();
};
}
}
}
/**************************************/
function checkBrowser() {
/* Checks whether this browser can support the necessary stuff */
@@ -2002,6 +2033,7 @@ window.addEventListener("load", function() {
initializeDisk();
}
}, false);
$$("DeleteDBBtn").addEventListener("click", deleteDiskDatabase)
$$("LoadBtn").addEventListener("click", loadFromTape);
openDatabase(dbName, dbVersion);
}
@@ -2029,15 +2061,17 @@ TBODY#TapeDirBody {
<body>
<div style="position:relative; width:100%; height:3em">
<div style="position:relative; width:100%; height:4em">
<div style="position:absolute; left:0; top:0; width:auto">
<img src="../webUI/retro-B5500-Logo.png" alt="retro-B5500 Logo" style="float:left">
&nbsp;Disk SubSystem Coldstart Loader
</div>
<div style="text-align:center">
<div style="position:absolute; left:30em; top:0; width:auto">
<input id=ColdstartBtn type=button value="Cold Start" DISABLED>
&nbsp;&nbsp;
<input id=DeleteDBBtn type=button value="Delete Disk Subsystem" DISABLED>
</div>
<div style="position:absolute; top:0; right:0; width:auto">
<div style="position:absolute; top:2em; left:30em; width:auto">
<input id=FileSelector type=file size=60 DISABLED>
</div>

View File

@@ -47,6 +47,7 @@ window.addEventListener("load", function() {
var perLightsMap = new Array(48);
var procDelay;
var procSlack;
var showAnnunciators = false;
var timer;
var timerInterval = 50; // milliseconds
@@ -58,6 +59,14 @@ window.addEventListener("load", function() {
return function() {f.apply(context, arguments)};
}
function BurroughsLogo_Click(ev) {
showAnnunciators = !showAnnunciators;
$$("CentralControl").style.visibility = (showAnnunciators ? "visible" : "hidden");
$$("RetroVersion").style.visibility = (showAnnunciators ? "visible" : "hidden");
$$("RetroLogoImage").style.display = (showAnnunciators ? "inline" : "none");
$$("B5500LogoImage").style.display = (showAnnunciators ? "none" : "inline");
}
function PowerOnBtn_Click(ev) {
$$("PowerOnBtn").className = "whiteButton whiteLit";
$$("AControlBtn").className = "yellowButton yellowLit";
@@ -67,6 +76,7 @@ window.addEventListener("load", function() {
$$("LoadBtn").disabled = false;
$$("HaltBtn").disabled = true;
boundBlinkenlicht();
BurroughsLogo_Click(); // turn on the annunciators
window.focus();
return true;
}
@@ -184,9 +194,12 @@ window.addEventListener("load", function() {
var et;
var pa = cc.PA;
var pb = cc.PB;
var p1 = cc.P1;
var stamp = new Date().getTime();
var stateRate;
timer = setTimeout(boundBlinkenlicht, timerInterval);
if (pa) {
if (!pa.busy) {
if (lastPAControlRate != -1) {
@@ -252,13 +265,6 @@ window.addEventListener("load", function() {
}
pa.controlCycles = pa.normalCycles = 0;
et = pa.procTime;
while (et < 0) {
et += stamp;
}
procDelay.innerHTML = pa.delayDeltaAvg.toFixed(3);
procSlack.innerHTML = (pa.procSlack/et*100).toFixed(1) + "%";
}
}
@@ -330,8 +336,16 @@ window.addEventListener("load", function() {
}
}
displayCentralControl();
timer = setTimeout(boundBlinkenlicht, timerInterval);
et = p1.procTime;
while (et < 0) {
et += stamp;
}
procDelay.innerHTML = p1.delayDeltaAvg.toFixed(3);
procSlack.innerHTML = (p1.procSlack/et*100).toFixed(1) + "%";
if (showAnnunciators) {
displayCentralControl();
}
}
function buildLightMaps() {
@@ -381,11 +395,12 @@ window.addEventListener("load", function() {
$$("RetroVersion").innerHTML = B5500CentralControl.version;
if (!checkBrowser()) {
$$("PowerOnBtn").addEventListener("click", PowerOnBtn_Click);
$$("PowerOffBtn").addEventListener("click", PowerOffBtn_Click);
$$("HaltBtn").addEventListener("click", HaltBtn_Click);
$$("LoadBtn").addEventListener("click", LoadBtn_Click);
$$("LoadSelectBtn").addEventListener("click", LoadSelectBtn_Click);
$$("BurroughsLogo").addEventListener("click", BurroughsLogo_Click, false);
$$("PowerOnBtn").addEventListener("click", PowerOnBtn_Click, false);
$$("PowerOffBtn").addEventListener("click", PowerOffBtn_Click, false);
$$("HaltBtn").addEventListener("click", HaltBtn_Click, false);
$$("LoadBtn").addEventListener("click", LoadBtn_Click, false);
$$("LoadSelectBtn").addEventListener("click", LoadSelectBtn_Click, false);
aControl = $$("AControlBtn");
aNormal = $$("ANormalBtn");
@@ -419,16 +434,18 @@ window.addEventListener("load", function() {
<button id=PowerOffBtn class="blackButton blackLit" DISABLED>POWER OFF</button>
<div id=BurroughsLogo>
<img id=BurroughsLogoImage src="Burroughs-Logo-Neg.jpg" alt="Burroughs logo">
<img id=BurroughsLogoImage src="Burroughs-Logo-Neg.jpg" alt="Burroughs logo"
title="Click to toggle the white annunciator lights">
</div>
<div id=RetroVersion>
<div id=RetroVersion title="retro-B5500 emulator version">
?.??
</div>
<div id=B5500Logo>
<img src="retro-B5500-Logo.png" alt="retro-B5500 logo"><!-- B 5500 -->
<img id=RetroLogoImage src="retro-B5500-Logo.png" alt="retro-B5500 logo">
<span id=B5500LogoImage style="display:none">&nbsp;B&nbsp;5500&nbsp;</span>
</div>
<table id=CentralControl>
<table id=CentralControl style="visibility:hidden">
<colgroup>
<col span=32 class=AnnunciatorCol>
<col>
@@ -439,7 +456,7 @@ window.addEventListener("load", function() {
<td id=AD2F>IOU2 <!-- I/O unit 2 busy -->
<td id=AD3F>IOU3 <!-- I/O unit 3 busy -->
<td id=AD4F>IOU4 <!-- I/O unit 4 busy -->
<td id=CCI03F>TIMR <!-- Time interval interrupt -->
<td id=CCI03F>TIMR <!-- Interval timer interrupt -->
<td id=CCI04F>IOBZ <!-- I/O busy interrupt -->
<td id=CCI05F>KBD <!-- Keyboard request interrupt -->
<td id=CCI06F>PR1F <!-- Printer 1 finished interrupt -->
@@ -455,23 +472,23 @@ window.addEventListener("load", function() {
<td id=CCI16F>DK2F <!-- Disk file #2 read check finished -->
<td colspan=13>
<td id=procSlack>
<td class=busy>PA Slack
<td class=busy title="Percentage of time Processor A is throttling its performance">P1 Slack
<tr id=CCPeripheralRow>
<td id=DCA>DCA <!-- 17 -->
<td id=PPB>PPB <!-- 18 -->
<td id=PRB>PRB <!-- 19 -->
<td id=PRA>PRA <!-- 20 -->
<td id=PPA>PPA <!-- 21 -->
<td id=SPO>SPO <!-- 22 -->
<td id=CRB>CRB <!-- 23 -->
<td id=CRA>CRA <!-- 24 -->
<td id=CPA>CPA <!-- 25 -->
<td id=LPB>LPB <!-- 26 -->
<td id=LPA>LPA <!-- 27 -->
<td id=DKB>DKB <!-- 28 -->
<td id=DKA>DKA <!-- 29 -->
<td id=DRB>DRB <!-- 30 -->
<td id=DRA>DRA <!-- 31 -->
<td id=DRB>DRB <!-- 30 -->
<td id=DKA>DKA <!-- 29 -->
<td id=DKB>DKB <!-- 28 -->
<td id=SPO>SPO <!-- 22 -->
<td id=CPA>CPA <!-- 25 -->
<td id=CRA>CRA <!-- 24 -->
<td id=CRB>CRB <!-- 23 -->
<td id=LPA>LPA <!-- 27 -->
<td id=LPB>LPB <!-- 26 -->
<td id=DCA>DCA <!-- 17 -->
<td id=PRA>PRA <!-- 20 -->
<td id=PRB>PRB <!-- 19 -->
<td id=PPA>PPA <!-- 21 -->
<td id=PPB>PPB <!-- 18 -->
<td id=MTA>MTA <!-- 47 -->
<td id=MTB>MTB <!-- 46 -->
<td id=MTC>MTC <!-- 45 -->
@@ -489,7 +506,7 @@ window.addEventListener("load", function() {
<td id=MTS>MTS <!-- 33 -->
<td id=MTT>MTT <!-- 32 -->
<td id=procDelay>
<td class=busy>PA Delay
<td class=busy title="Average excess throttling delay for Processor A (ms)">P1 Delay
</table>
</div>

View File

@@ -163,7 +163,7 @@ B5500DummyPrinter.prototype.write = function write(finish, buffer, length, mode,
this.timer = setTimeout(this.signal,
60000/this.linesPerMinute + this.initiateStamp - new Date().getTime());
finish(0, 0);
finish(this.errorMask, 0);
this.endOfPaper.scrollIntoView();
};

View File

@@ -18,7 +18,7 @@
<button id=SPOReadyBtn class="yellowButton blackBorder">READY</button>
<button id=SPOPowerBtn class="blackButton blackBorder">POWER</button>
<button id=SPORemoteBtn class="yellowButton blackBorder">REMOTE</button>
<button id=SPOLocalBtn class="yellowButton blackBorder">LOCAL</button>
<button id=SPOLocalBtn class="yellowButton blackBorder yellowLit">LOCAL</button>
<button id=SPOInputRequestBtn class="yellowButton blackBorder">INPUT REQUEST</button>
<button id=SPOEndOfMessageBtn class="yellowButton blackBorder">END OF MESSAGE</button>
<button id=SPOBlank1Btn class="yellowButton blackBorder"></button>

View File

@@ -55,7 +55,6 @@ function B5500SPOUnit(mnemonic, unitIndex, designate, statusChange, signal) {
}
// this.spoState enumerations
B5500SPOUnit.prototype.spoNotReady = 0;
B5500SPOUnit.prototype.spoLocal = 1;
B5500SPOUnit.prototype.spoRemote = 2;
B5500SPOUnit.prototype.spoInput = 3;
@@ -92,7 +91,7 @@ B5500SPOUnit.prototype.clear = function clear() {
this.printCol = 0;
this.nextCharTime = 0;
this.spoState = this.spoNotReady; // Current state of SPO interface
this.spoState = this.spoLocal; // Current state of SPO interface
this.spoLocalRequested = false; // LOCAL button pressed while active
};
@@ -126,27 +125,6 @@ B5500SPOUnit.prototype.removeClass = function removeClass(e, name) {
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
};
/**************************************/
B5500SPOUnit.prototype.setNotReady = function setNotReady() {
/* Sets the status of the SPO to Not Ready */
if (this.spoState == this.spoLocal) {
this.spoState = this.spoNotReady;
this.removeClass(this.$$("SPOReadyBtn"), "yellowLit");
this.statusChange(0);
}
};
/**************************************/
B5500SPOUnit.prototype.setReady = function setReady() {
/* Sets the status of the SPO to Ready */
if (this.spoState == this.spoNotReady) {
this.addClass(this.$$("SPOReadyBtn"), "yellowLit");
this.spoState = this.spoLocal;
}
};
/**************************************/
B5500SPOUnit.prototype.setLocal = function setLocal() {
/* Sets the status of the SPO to Local */
@@ -155,6 +133,7 @@ B5500SPOUnit.prototype.setLocal = function setLocal() {
this.spoState = this.spoLocal;
this.addClass(this.$$("SPOLocalBtn"), "yellowLit");
this.removeClass(this.$$("SPORemoteBtn"), "yellowLit");
this.removeClass(this.$$("SPOInputRequestBtn"), "yellowLit");
this.statusChange(0);
// Set up to echo characters from the keyboard
@@ -276,7 +255,7 @@ B5500SPOUnit.prototype.terminateInput = function terminateInput() {
set the state to Remote, and call finish() for us. Slick, eh? */
if (this.spoState == this.spoInput) {
this.removeClass(this.$$("SPOInputRequestBtn"), "yellowLit");
this.removeClass(this.$$("SPOReadyBtn"), "yellowLit");
this.bufLength = this.bufIndex;
this.nextCharTime = new Date().getTime();
this.outputChar();
@@ -289,7 +268,7 @@ B5500SPOUnit.prototype.cancelInput = function cancelInput() {
but it also sets a parity error so the input message will be rejected */
if (this.spoState = this.spoInput) {
this.removeClass(this.$$("SPOInputRequestBtn"), "yellowLit");
this.removeClass(this.$$("SPOReadyBtn"), "yellowLit");
this.errorMask |= 0x10; // set parity/error-button bit
this.bufLength = this.bufIndex;
this.nextCharTime = new Date().getTime();
@@ -361,6 +340,7 @@ B5500SPOUnit.prototype.keyDown = function keyDown(ev) {
switch (this.spoState) {
case this.spoRemote:
case this.spoOutput:
this.addClass(this.$$("SPOInputRequestBtn"), "yellowLit");
this.signal();
result = false;
break;
@@ -472,18 +452,13 @@ B5500SPOUnit.prototype.spoOnload = function spoOnload() {
that.setRemote();
}, false);
this.$$("SPOPowerBtn").addEventListener("click", function() {
that.window.alert("Don't DO THAT");
}, false);
this.$$("SPOLocalBtn").addEventListener("click", function() {
that.setLocal();
}, false);
this.$$("SPOInputRequestBtn").addEventListener("click", function() {
if (that.spoState == that.spoRemote) {
that.signal();
} else if (that.spoState == that.spoOutput) {
if (that.spoState == that.spoRemote || that.spoState == that.spoOutput) {
that.addClass(that.$$("SPOInputRequestBtn"), "yellowLit");
that.signal();
}
}, false);
@@ -499,9 +474,8 @@ B5500SPOUnit.prototype.spoOnload = function spoOnload() {
for (x=0; x<32; x++) {
this.appendEmptyLine();
}
this.setReady();
this.window.focus();
this.printText("retro-B5500 Emulator Version " + B5500CentralControl.version, function() {
this.window.focus();
that.setRemote();
that.appendEmptyLine();
});
@@ -515,7 +489,8 @@ B5500SPOUnit.prototype.read = function read(finish, buffer, length, mode, contro
switch (this.spoState) {
case this.spoRemote:
this.spoState = this.spoInput;
this.addClass(this.$$("SPOInputRequestBtn"), "yellowLit");
this.addClass(this.$$("SPOReadyBtn"), "yellowLit");
this.removeClass(this.$$("SPOInputRequestBtn"), "yellowLit");
this.buffer = buffer;
this.bufLength = length;
this.bufIndex = 0;