1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-05-02 06:26:23 +00:00

Commit retro-b5500 release 1.06:

1. Redesign and simplify delay and time deviation adjustment algorithm
in global SetCallback function; reinstate alpha parameter to control
adjustment decay rate.
2. Correct memory stores during tape drive backward read.
3. Compare tape image file extensions in case-insensitive manner.
4. Detect dropouts (no flux change) in magnetic tape images.
5. Suppress printed SPO greeting after power-on.
6. Disable (for now) the ConsolePanel lamp test.
7. Update stacker progress meter and stacker-full annunciator when
emptying a stacker.
8. Supply (benign) terminating semicolons in ConsolePanel method
declarations.
9. Optimize extraction of MSCW address during Character Mode exit.
10. Miscellaneous minor additions and enhancements to scripts in tools/
directory.
This commit is contained in:
Paul Kimpel
2020-01-03 20:50:28 -08:00
parent 196175cd39
commit 1f82a16aaf
19 changed files with 1102 additions and 103 deletions

View File

@@ -97,6 +97,16 @@ B5500CardPunch.prototype.copyStacker = function copyStacker(ev) {
});
this.emptyStacker(stacker);
if (stacker == this.stacker1) {
this.stacker1Count = 0;
this.$$("CPStacker1Bar").value = 0;
this.$$("CPStacker1Full").classList.remove("annunciatorLit");
} else if (stacker == this.stacker2) {
this.stacker2Count = 0;
this.$$("CPStacker2Bar").value = 0;
this.$$("CPStacker2Full").classList.remove("annunciatorLit");
}
ev.preventDefault();
ev.stopPropagation();
};

View File

@@ -34,6 +34,7 @@ function B5500ConsolePanel(global, autoPowerUp, shutDown) {
this.cc; // B5500CentralControl object
this.ccLatches = [0, 0, 0]; // I/O- & interrupt-reporting latches
this.ccLightsMap = new Array(6); // Misc annunciator DOM objects
this.enableLampTest = false; // Perform lamp test at power-on
this.global = global; // Global window object
this.intLightsMap = new Array(48); // Interrupt annunciator DOM objects
this.lastInterruptMask = 0; // Prior mask of interrupt annunciator lights
@@ -67,7 +68,7 @@ B5500ConsolePanel.annOffColor = "#333"; // annunciator lamp off color
/**************************************/
B5500ConsolePanel.prototype.$$ = function $$(id) {
return this.doc.getElementById(id);
}
};
/**************************************/
B5500ConsolePanel.prototype.setAnnunciators = function setAnnunciators(showEm) {
@@ -78,7 +79,7 @@ B5500ConsolePanel.prototype.setAnnunciators = function setAnnunciators(showEm) {
this.$$("RetroLogoImage").style.display = (showEm ? "inline" : "none");
this.$$("B5500LogoImage").style.display = (showEm ? "none" : "inline");
this.$$("ConfigLabel").style.display = (showEm ? "inline" : "none");
}
};
/**************************************/
B5500ConsolePanel.prototype.evaluateNotReady = function evaluateNotReady(config) {
@@ -87,7 +88,7 @@ B5500ConsolePanel.prototype.evaluateNotReady = function evaluateNotReady(config)
var lampClass = "whiteButton";
switch (false) {
case config.PA.enabled || config.PA.enabled:
case config.PA.enabled || config.PB.enabled:
case (config.PA.enabled && !config.PB1L) || (config.PB.enabled && config.PB1L):
case config.IO1.enabled || config.IO2.enabled || config.IO3.enabled || config.IO4.enabled:
case config.memMod[0].enabled:
@@ -97,7 +98,7 @@ B5500ConsolePanel.prototype.evaluateNotReady = function evaluateNotReady(config)
}
this.$$("NotReadyBtn").className = lampClass;
}
};
/**************************************/
B5500ConsolePanel.prototype.focusConsole = function focusConsole() {
@@ -105,7 +106,7 @@ B5500ConsolePanel.prototype.focusConsole = function focusConsole() {
this.window.focus();
this.$$("LoadBtn").focus();
}
};
/**************************************/
B5500ConsolePanel.prototype.BurroughsLogo_Click = function BurroughsLogo_Click(ev) {
@@ -113,7 +114,7 @@ B5500ConsolePanel.prototype.BurroughsLogo_Click = function BurroughsLogo_Click(e
this.showAnnunciators = !this.showAnnunciators;
this.setAnnunciators(this.showAnnunciators);
}
};
/**************************************/
B5500ConsolePanel.prototype.B5500Logo_Click = function B5500Logo_Click(ev) {
@@ -127,7 +128,7 @@ B5500ConsolePanel.prototype.B5500Logo_Click = function B5500Logo_Click(ev) {
this.$$("ConfigLabel").style.display = "none";
sysConfig.openConfigUI();
}
}
};
/**************************************/
B5500ConsolePanel.prototype.PowerOnBtn_Click = function PowerOnBtn_Click(ev) {
@@ -159,7 +160,7 @@ B5500ConsolePanel.prototype.PowerOnBtn_Click = function PowerOnBtn_Click(ev) {
that.$$("PowerOnBtn").className = "greenButton greenLit";
that.$$("SysConfigName").textContent = config.configName;
that.$$("StorageName").textContent = config.units.DKA.storageName;
if (that.showAnnunciators) {
if (that.enableLampTest && that.showAnnunciators) {
that.lampTest(applyPower.bind(that), config);
} else {
applyPower(config);
@@ -169,7 +170,7 @@ B5500ConsolePanel.prototype.PowerOnBtn_Click = function PowerOnBtn_Click(ev) {
sysConfig.getSystemConfig(null, youMayPowerOnWhenReady_Gridley); // get current system config
return true;
}
};
/**************************************/
B5500ConsolePanel.prototype.PowerOffBtn_Click = function PowerOffBtn_Click(ev) {
@@ -198,7 +199,7 @@ B5500ConsolePanel.prototype.PowerOffBtn_Click = function PowerOffBtn_Click(ev) {
this.timer = 0;
}
return true;
}
};
/**************************************/
B5500ConsolePanel.prototype.HaltBtn_Click = function HaltBtn_Click(ev) {
@@ -213,7 +214,7 @@ B5500ConsolePanel.prototype.HaltBtn_Click = function HaltBtn_Click(ev) {
clearInterval(this.timer);
this.timer = 0;
}
}
};
/**************************************/
B5500ConsolePanel.prototype.LoadBtn_Click = function LoadBtn_Click(ev) {
@@ -250,7 +251,7 @@ B5500ConsolePanel.prototype.LoadBtn_Click = function LoadBtn_Click(ev) {
this.window.alert("cc.load() result = " + result);
break;
}
}
};
/**************************************/
B5500ConsolePanel.prototype.LoadSelectBtn_Click = function LoadSelectBtn_Click(ev) {
@@ -263,7 +264,7 @@ B5500ConsolePanel.prototype.LoadSelectBtn_Click = function LoadSelectBtn_Click(e
this.cc.cardLoadSelect = 1;
this.$$("LoadSelectBtn").className = "yellowButton yellowLit";
}
}
};
/**************************************/
B5500ConsolePanel.prototype.dumpState = function dumpState(caption) {
@@ -354,7 +355,7 @@ B5500ConsolePanel.prototype.dumpState = function dumpState(caption) {
B5500Util.openPopup(this.window, "./B5500FramePaper.html", "",
"location=no,resizable,scrollbars,status",
this, dumpStateOnLoad);
}
};
/**************************************/
B5500ConsolePanel.prototype.dumpTape = function dumpTape(caption) {
@@ -430,7 +431,7 @@ B5500ConsolePanel.prototype.dumpTape = function dumpTape(caption) {
B5500Util.openPopup(this.window, "./B5500FramePaper.html", "",
"location=no,resizable,scrollbars,status",
this, dumpTapeOnLoad);
}
};
/**************************************/
B5500ConsolePanel.prototype.displayCallbackState = function displayCallbackState() {
@@ -487,7 +488,7 @@ B5500ConsolePanel.prototype.displayCallbackState = function displayCallbackState
body.id = oldBody.id;
oldBody.parentNode.replaceChild(body, oldBody);
}
};
/**************************************/
B5500ConsolePanel.prototype.displayCentralControl = function displayCentralControl() {
@@ -550,7 +551,7 @@ B5500ConsolePanel.prototype.displayCentralControl = function displayCentralContr
unitBusyChange >>>= 1;
x--;
}
}
};
/**************************************/
B5500ConsolePanel.prototype.dasBlinkenlichten = function dasBlinkenlichten() {
@@ -706,7 +707,7 @@ B5500ConsolePanel.prototype.dasBlinkenlichten = function dasBlinkenlichten() {
this.displayCentralControl();
}
//this.displayCallbackState();
}
};
/**************************************/
B5500ConsolePanel.prototype.buildLightMaps = function buildLightMaps() {
@@ -730,7 +731,7 @@ B5500ConsolePanel.prototype.buildLightMaps = function buildLightMaps() {
spec = B5500CentralControl.unitSpecs[mnem];
this.perLightsMap[spec.unitIndex] = this.$$(mnem);
}
}
};
/**************************************/
B5500ConsolePanel.prototype.lampTest = function lampTest(callback, callbackParam) {
@@ -780,7 +781,7 @@ B5500ConsolePanel.prototype.lampTest = function lampTest(callback, callbackParam
this.$$("CentralControl").style.display = "block"; // overrides if !this.cc.poweredUp
switchEm(1);
setCallback(null, this, 2000, switchEm, 0);
}
};
/**************************************/
B5500ConsolePanel.prototype.beforeUnload = function beforeUnload(ev) {
@@ -819,7 +820,7 @@ B5500ConsolePanel.prototype.clearStatusLabel = function clearStatusLabel(inSecon
this.$$("StatusLabel").textContent = "";
this.statusLabelTimer = 0;
});
}
};
/**************************************/
B5500ConsolePanel.prototype.consoleOnload = function consoleOnload(ev) {

View File

@@ -376,7 +376,7 @@ B5500MagTapeDrive.prototype.loadTape = function loadTape() {
file = ev.target.files[0];
fileName = file.name;
x = fileName.lastIndexOf(".");
fileExt = (x > 0 ? fileName.substring(x) : "");
fileExt = (x > 0 ? fileName.substring(x) : "").toLowerCase();
writeRingCheck.checked = false;
tapeLengthSelect.disabled = true;
@@ -977,8 +977,8 @@ B5500MagTapeDrive.prototype.bcdReadForward = function bcdReadForward(oddParity)
var buffer = this.buffer; // IOUnit buffer
var bufLength = this.bufLength // IOUnit buffer length
var bufIndex = 0; // current IOUnit buffer offset
var c; // current character (tape image frame)
var cx; // current character translated to ASCII
var c = 0; // current character (tape image frame)
var cx = 0; // current character translated to ASCII
var image = this.image; // tape image
var imgLength = this.imgLength; // tape image length
var imgIndex = this.imgIndex; // current tape image offset
@@ -998,6 +998,10 @@ B5500MagTapeDrive.prototype.bcdReadForward = function bcdReadForward(oddParity)
c &= 0x7F; // zap the start-of-block bit
do {
if (c == 0x00) {
if (bufIndex > 0) {
this.errorMask |= 0x10; // dropout detected: no flux change
}
if (++blankCount > this.maxBlankFrames) {
this.errorMask |= 0x100000; // blank tape timeout
break; // kill the read loop
@@ -1057,8 +1061,8 @@ B5500MagTapeDrive.prototype.bcdReadBackward = function bcdReadBackward(oddParity
var buffer = this.buffer; // IOUnit buffer
var bufLength = this.bufLength // IOUnit buffer length
var bufIndex = 0; // current IOUnit buffer offset
var c; // current character (tape image frame)
var cx; // current character translated to ASCII
var c = 0; // current character (tape image frame)
var cx = 0; // current character translated to ASCII
var image = this.image; // tape image
var imgLength = this.imgLength; // tape image length
var imgIndex = this.imgIndex; // current tape image offset
@@ -1081,13 +1085,17 @@ B5500MagTapeDrive.prototype.bcdReadBackward = function bcdReadBackward(oddParity
} else {
do {
if (c == 0x00) {
if (bufIndex > 0) {
this.errorMask |= 0x10; // dropout detected: no flux change
}
if (++blankCount > this.maxBlankFrames) {
this.errorMask |= 0x100000; // blank tape timeout
break; // kill the read loop
} else if (imgIndex > 0) {
c = image[--imgIndex]; // get next char frame
} else {
break; // at end of tape, kill the read loop
break; // at beginning of tape, kill the read loop
}
} else {
blankCount = 0;
@@ -1137,6 +1145,7 @@ B5500MagTapeDrive.prototype.bcdWrite = function bcdWrite(oddParity) {
var buffer = this.buffer; // IOUnit buffer
var bufLength = this.bufLength // IOUnit buffer length
var bufIndex = 0; // current IOUnit buffer offset
var c = 0; // current tape character code
var image = this.image; // tape image
var imgLength = this.imgLength; // tape image length
var imgIndex = this.imgIndex; // current tape image offset
@@ -1148,13 +1157,24 @@ B5500MagTapeDrive.prototype.bcdWrite = function bcdWrite(oddParity) {
if (this.atBOT) {
this.setAtBOT(false);
}
image[imgIndex++] = xlate[buffer[bufIndex++] & 0x7F] | 0x80;
c = xlate[buffer[bufIndex++] & 0x7F];
if (c == 0) {
this.errorMask |= 0x10; // dropout detected: attempt to write no flux changes
}
image[imgIndex++] = c | 0x80;
while (bufIndex < bufLength) {
if (imgIndex >= imgLength) {
this.errorMask |= 0x04; // report not ready beyond end of tape
break;
} else {
image[imgIndex++] = xlate[buffer[bufIndex++] & 0x7F];
c = xlate[buffer[bufIndex++] & 0x7F];
if (c == 0) {
this.errorMask |= 0x10; // dropout detected: attempt to write no flux changes
}
image[imgIndex++] = c;
}
} // while
}

View File

@@ -24,6 +24,7 @@ function B5500SPOUnit(mnemonic, unitIndex, designate, statusChange, signal, opti
this.maxScrollLines = 5000; // Maximum amount of printer scrollback
this.charPeriod = 100; // Printer speed, milliseconds per character
this.printGreeting = false; // Print initial greeting message
this.mnemonic = mnemonic; // Unit mnemonic
this.unitIndex = unitIndex; // Ready-mask bit number
@@ -471,6 +472,16 @@ B5500SPOUnit.prototype.printText = function printText(msg, finish) {
this.endOfPaper.scrollIntoView();
};
/**************************************/
B5500SPOUnit.prototype.spoInitialize = function spoInitialize() {
/* Initializes the SPO after power-on */
this.setRemote();
this.appendEmptyLine("\xA0");
this.endOfPaper.scrollIntoView();
this.signal(-1); // re-focus the Console window
};
/**************************************/
B5500SPOUnit.prototype.spoOnload = function spoOnload(ev) {
/* Initializes the SPO window and user interface */
@@ -513,19 +524,14 @@ B5500SPOUnit.prototype.spoOnload = function spoOnload(ev) {
B5500SPOUnit.prototype.SPOAlgolGlyphsBtn_onclick.bind(this), false);
this.window.focus();
this.printText("retro-B5500 Emulator Version " + B5500CentralControl.version,
function initFinish() {
this.setRemote();
this.appendEmptyLine("\xA0");
this.endOfPaper.scrollIntoView();
this.signal(-1); // re-focus the Console window
}.bind(this));
// Kludge for Chrome window.outerWidth/Height timing bug
setCallback(null, this, 100, function chromeBug() {
this.window.moveTo(screen.availWidth-this.window.outerWidth,
screen.availHeight-this.window.outerHeight);
});
this.window.moveTo(screen.availWidth-this.window.outerWidth,
screen.availHeight-this.window.outerHeight);
if (this.printGreeting) {
this.printText("retro-B5500 Emulator Version " + B5500CentralControl.version,
B5500SPOUnit.prototype.spoInitialize);
} else {
this.spoInitialize();
}
};
/**************************************/

View File

@@ -86,12 +86,13 @@
* Redesign yet again the delay adjustment mechanism with one from the
* retro-205 project. Replace window.postMessage yield mechanism with one
* from the retro-220 project 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
@@ -151,11 +152,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
@@ -167,7 +167,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.
@@ -177,42 +184,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);

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 618 B