1
0
mirror of https://github.com/pkimpel/retro-220.git synced 2026-01-11 23:52:46 +00:00

Commit retro-220 emulator version 0.07:

1. Implement centralized pop-up window opening mechanism to enforce a delay between pop-up opens. This is to satisfy new restrictions on multiple pop-ups imposed by the Apple Safari 11.0 browser.
2. Correct Reload-Lockout behavior and format band 6 initialization in B220CardatronInput.
3. Correct translation of sign digits and skip-to-channel behavior in B220CardatronOutput.
4. Strip sign digit from search/scan argument word when storing into B220MagTapeControl T register.
5. Remove option for 1000-word system memory size and correct handling of memory size list selection in B220SystemConfig.
6. Change reel-to-reel magnetic tape name from DataReader to TSU in B220SystemConfig.
This commit is contained in:
Paul Kimpel 2018-03-03 10:18:55 -08:00
parent f19f4e9b65
commit a29f2cac5d
21 changed files with 849 additions and 677 deletions

33
.gitattributes vendored Normal file
View File

@ -0,0 +1,33 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.html text
*.css text
*.js text
*.md text
*.txt text
*.lst text
*.svg text
*.card text
*.tape text
*.pt text
*.bacg text
*.baca text
*.cmd text
*.bat text
*.wsf text
*.vbs text
# Denote all files that are truly binary and should not be modified.
*.png binary
*.gif binary
*.jpg binary
*.ttf binary
*.woff binary
*.pdf binary
*.doc binary
*.docx binary
*.xls binary
*.xlsx binary

38
.gitignore vendored
View File

@ -1,19 +1,19 @@
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
#IIS config file
web.config
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
#IIS config file
web.config
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store

View File

@ -1,21 +1,21 @@
Copyright (c) 2016 Paul Kimpel
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Copyright (c) 2016 Paul Kimpel
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,19 +1,19 @@
The Burroughs 220 was a late-1950s, decimal, vacuum-tube, core-memory computer system. Some consider it to be the last of the major vacuum-tube computers.
The 220 was the follow-on product to the ElectroData/Burroughs Datatron 205. It was initially developed as the ElectroData Datatron 220 but renamed after Burroughs bought ElectroData in 1956. The system was initially released in 1958. It did well with both scientific and commercial applications, but being a vacuum-tube system at the beginning of the transistorized era, was only modestly successful.
The ElectroData Division of Burroughs went on to create a number of successful systems after the 220, including the B100/200/300 series, the B1700/1800/1900 series, the B2000/3000/4000/V Series, the B5000/5500, and finally the B6000/7000/A Series, which are still produced and sold today as Unisys ClearPath MCP systems.
The main goal of this project is creation of a web browser-based emulator for the 220.
A second goal is reconstruction of the Burroughs Algebraic Compiler (BALGOL), an Algol-58 compiler written for the 220 by a team from Burroughs that included Joel Erdwinn, Jack Merner, Donald Knuth, Dave Dahm, and Clark Oliphint.
The contents of this project are licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
| Related Sites | URL |
| ------------- | ----- |
| Emulator hosting site | http://www.phkimpel.us/Burroughs-220/ |
| Burroughs 205/220 blog | http://datatron.blogspot.com |
| Datatron 205 site | http://www.phkimpel.us/ElectroData-205/ |
| Documents at bitsavers | http://bitsavers.org/pdf/burroughs/electrodata/220/ |
| BALGOL compiler listing | http://archive.computerhistory.org/resources/text/Knuth_Don_X4100/PDF_index/k-1-pdf/k-1-u2196-balgol220compiler.pdf |
The Burroughs 220 was a late-1950s, decimal, vacuum-tube, core-memory computer system. Some consider it to be the last of the major vacuum-tube computers.
The 220 was the follow-on product to the ElectroData/Burroughs Datatron 205. It was initially developed as the ElectroData Datatron 220 but renamed after Burroughs bought ElectroData in 1956. The system was initially released in 1958. It did well with both scientific and commercial applications, but being a vacuum-tube system at the beginning of the transistorized era, was only modestly successful.
The ElectroData Division of Burroughs went on to create a number of successful systems after the 220, including the B100/200/300 series, the B1700/1800/1900 series, the B2000/3000/4000/V Series, the B5000/5500, and finally the B6000/7000/A Series, which are still produced and sold today as Unisys ClearPath MCP systems.
The main goal of this project is creation of a web browser-based emulator for the 220.
A second goal is reconstruction of the Burroughs Algebraic Compiler (BALGOL), an Algol-58 compiler written for the 220 by a team from Burroughs that included Joel Erdwinn, Jack Merner, Donald Knuth, Dave Dahm, and Clark Oliphint.
The contents of this project are licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
| Related Sites | URL |
| ------------- | ----- |
| Emulator hosting site | http://www.phkimpel.us/Burroughs-220/ |
| Burroughs 205/220 blog | http://datatron.blogspot.com |
| Datatron 205 site | http://www.phkimpel.us/ElectroData-205/ |
| Documents at bitsavers | http://bitsavers.org/pdf/burroughs/electrodata/220/ |
| BALGOL compiler listing | http://archive.computerhistory.org/resources/text/Knuth_Don_X4100/PDF_index/k-1-pdf/k-1-u2196-balgol220compiler.pdf |

View File

@ -61,6 +61,7 @@
/**************************************/
function B220Processor(config, devices) {
/* Constructor for the 220 Processor module object */
var staticLampGlow = false; // compute fractional lamp glow (experimental)
this.mnemonic = "CPU";
B220Processor.instance = this; // externally-available object reference (for DiagMonitor)
@ -101,14 +102,14 @@ function B220Processor(config, devices) {
this.delayRequested = 0; // last requested setCallback() delay, ms
// Primary Registers
this.A = new B220Processor.Register(11*4, this, false);
this.B = new B220Processor.Register( 4*4, this, false);
this.C = new B220Processor.Register(10*4, this, false);
this.D = new B220Processor.Register(11*4, this, false);
this.E = new B220Processor.Register( 4*4, this, false);
this.P = new B220Processor.Register( 4*4, this, false);
this.R = new B220Processor.Register(11*4, this, false);
this.S = new B220Processor.Register( 4*4, this, false);
this.A = new B220Processor.Register(11*4, this, staticLampGlow);
this.B = new B220Processor.Register( 4*4, this, staticLampGlow);
this.C = new B220Processor.Register(10*4, this, staticLampGlow);
this.D = new B220Processor.Register(11*4, this, staticLampGlow);
this.E = new B220Processor.Register( 4*4, this, staticLampGlow);
this.P = new B220Processor.Register( 4*4, this, staticLampGlow);
this.R = new B220Processor.Register(11*4, this, staticLampGlow);
this.S = new B220Processor.Register( 4*4, this, staticLampGlow);
// Register E decrements modulo the system memory size, so override dec().
this.E.dec = function decE() {
@ -119,14 +120,14 @@ function B220Processor(config, devices) {
};
// Control Console Lamps
this.digitCheckAlarm = new B220Processor.FlipFlop(this, false);
this.digitCheckAlarm = new B220Processor.FlipFlop(this, staticLampGlow);
this.systemNotReady = new B220Processor.FlipFlop(this, false);
this.computerNotReady = new B220Processor.FlipFlop(this, false);
this.systemNotReady = new B220Processor.FlipFlop(this, staticLampGlow);
this.computerNotReady = new B220Processor.FlipFlop(this, staticLampGlow);
this.compareLowLamp = new B220Processor.FlipFlop(this, false);
this.compareEqualLamp = new B220Processor.FlipFlop(this, false);
this.compareHighLamp = new B220Processor.FlipFlop(this, false);
this.compareLowLamp = new B220Processor.FlipFlop(this, staticLampGlow);
this.compareEqualLamp = new B220Processor.FlipFlop(this, staticLampGlow);
this.compareHighLamp = new B220Processor.FlipFlop(this, staticLampGlow);
// Control Console Switches
this.PC1SW = 0; // program control switches 1-10
@ -159,29 +160,29 @@ function B220Processor(config, devices) {
this.HOLDSEQUENCE8SW = 0;
// Left-Hand Maintenance Panel Registers & Flip-Flops
this.CI = new B220Processor.Register(5, this, false); // carry inverters
this.DC = new B220Processor.Register(6, this, false); // digit counter (modulo 20)
this.SC = new B220Processor.Register(4, this, false); // sequence counter
this.SI = new B220Processor.Register(4, this, false); // sum inverters
this.X = new B220Processor.Register(4, this, false); // adder X (augend) input
this.Y = new B220Processor.Register(4, this, false); // adder Y (addend) input
this.Z = new B220Processor.Register(4, this, false); // decimal sum inverters, adder output
this.CI = new B220Processor.Register(5, this, staticLampGlow); // carry inverters
this.DC = new B220Processor.Register(6, this, staticLampGlow); // digit counter (modulo 20)
this.SC = new B220Processor.Register(4, this, staticLampGlow); // sequence counter
this.SI = new B220Processor.Register(4, this, staticLampGlow); // sum inverters
this.X = new B220Processor.Register(4, this, staticLampGlow); // adder X (augend) input
this.Y = new B220Processor.Register(4, this, staticLampGlow); // adder Y (addend) input
this.Z = new B220Processor.Register(4, this, staticLampGlow); // decimal sum inverters, adder output
this.CI.checkFC = B220Processor.emptyFunction; // these registers generate A-F undigits
this.SI.checkFC = B220Processor.emptyFunction;
this.C10 = new B220Processor.FlipFlop(this, false); // decimal carry toggle
this.DST = new B220Processor.FlipFlop(this, false); // D-sign toggle
this.LT1 = new B220Processor.FlipFlop(this, false); // logical toggle 1
this.LT2 = new B220Processor.FlipFlop(this, false); // logical toggle 2
this.LT3 = new B220Processor.FlipFlop(this, false); // logical toggle 3
this.SCI = new B220Processor.FlipFlop(this, false); // sequence counter inverter
this.SGT = new B220Processor.FlipFlop(this, false); // sign toggle
this.SUT = new B220Processor.FlipFlop(this, false); // subtract toggle
this.TBT = new B220Processor.FlipFlop(this, false); // tape busy toggle
this.TCT = new B220Processor.FlipFlop(this, false); // tape clock toggle
this.TPT = new B220Processor.FlipFlop(this, false); // tape pulse toggle
this.TWT = new B220Processor.FlipFlop(this, false); // tape write toggle
this.C10 = new B220Processor.FlipFlop(this, staticLampGlow); // decimal carry toggle
this.DST = new B220Processor.FlipFlop(this, staticLampGlow); // D-sign toggle
this.LT1 = new B220Processor.FlipFlop(this, staticLampGlow); // logical toggle 1
this.LT2 = new B220Processor.FlipFlop(this, staticLampGlow); // logical toggle 2
this.LT3 = new B220Processor.FlipFlop(this, staticLampGlow); // logical toggle 3
this.SCI = new B220Processor.FlipFlop(this, staticLampGlow); // sequence counter inverter
this.SGT = new B220Processor.FlipFlop(this, staticLampGlow); // sign toggle
this.SUT = new B220Processor.FlipFlop(this, staticLampGlow); // subtract toggle
this.TBT = new B220Processor.FlipFlop(this, staticLampGlow); // tape busy toggle
this.TCT = new B220Processor.FlipFlop(this, staticLampGlow); // tape clock toggle
this.TPT = new B220Processor.FlipFlop(this, staticLampGlow); // tape pulse toggle
this.TWT = new B220Processor.FlipFlop(this, staticLampGlow); // tape write toggle
// Right-Hand Maintenance Panel Switches
this.MULTIPLEACCESSSW = 0;
@ -197,33 +198,33 @@ function B220Processor(config, devices) {
this.FETCHEXECUTELOCKSW = 0;
// Right-Hand Maintenance Panel Registers & Flip-Flops
this.AX = new B220Processor.Register(10, this, false); // A exponent register
this.BI = new B220Processor.Register( 8, this, false); // paper tape buffer inverters
this.DX = new B220Processor.Register( 8, this, false); // D exponent register
this.PA = new B220Processor.Register( 8, this, false); // PA register
this.AX = new B220Processor.Register(10, this, staticLampGlow); // A exponent register
this.BI = new B220Processor.Register( 8, this, staticLampGlow); // paper tape buffer inverters
this.DX = new B220Processor.Register( 8, this, staticLampGlow); // D exponent register
this.PA = new B220Processor.Register( 8, this, staticLampGlow); // PA register
this.ALT = new B220Processor.FlipFlop(this, false); // program check alarm toggle
this.AST = new B220Processor.FlipFlop(this, false); // asynchronous toggle
this.CCT = new B220Processor.FlipFlop(this, false); // ?? toggle
this.CRT = new B220Processor.FlipFlop(this, false); // Cardatron alarm toggle
this.DPT = new B220Processor.FlipFlop(this, false); // decimal point toggle (SPO)
this.EWT = new B220Processor.FlipFlop(this, false); // end of word toggle
this.EXT = new B220Processor.FlipFlop(this, false); // fetch(0)/execute(1) toggle
this.HAT = new B220Processor.FlipFlop(this, false); // high-speed printer alarm toggle
this.HCT = new B220Processor.FlipFlop(this, false); // halt control toggle, for SOR, SOH, IOM
this.HIT = new B220Processor.FlipFlop(this, false); // high comparison toggle
this.MAT = new B220Processor.FlipFlop(this, false); // multiple access toggle
this.MET = new B220Processor.FlipFlop(this, false); // memory (storage) alarm toggle
this.MNT = new B220Processor.FlipFlop(this, false); // manual toggle
this.OFT = new B220Processor.FlipFlop(this, false); // overflow toggle
this.PAT = new B220Processor.FlipFlop(this, false); // paper tape alarm toggle
this.PRT = new B220Processor.FlipFlop(this, false); // paper tape read toggle
this.PZT = new B220Processor.FlipFlop(this, false); // paper tape zone toggle
this.RPT = new B220Processor.FlipFlop(this, false); // repeat toggle
this.RUT = new B220Processor.FlipFlop(this, false); // run toggle
this.SST = new B220Processor.FlipFlop(this, false); // single-step toggle
this.TAT = new B220Processor.FlipFlop(this, false); // magnetic tape alarm toggle
this.UET = new B220Processor.FlipFlop(this, false); // unequal comparison toggle (HIT=UET=0 => off)
this.ALT = new B220Processor.FlipFlop(this, staticLampGlow); // program check alarm toggle
this.AST = new B220Processor.FlipFlop(this, staticLampGlow); // asynchronous toggle
this.CCT = new B220Processor.FlipFlop(this, staticLampGlow); // ?? toggle
this.CRT = new B220Processor.FlipFlop(this, staticLampGlow); // Cardatron alarm toggle
this.DPT = new B220Processor.FlipFlop(this, staticLampGlow); // decimal point toggle (SPO)
this.EWT = new B220Processor.FlipFlop(this, staticLampGlow); // end of word toggle
this.EXT = new B220Processor.FlipFlop(this, staticLampGlow); // fetch(0)/execute(1) toggle
this.HAT = new B220Processor.FlipFlop(this, staticLampGlow); // high-speed printer alarm toggle
this.HCT = new B220Processor.FlipFlop(this, staticLampGlow); // halt control toggle, for SOR, SOH, IOM
this.HIT = new B220Processor.FlipFlop(this, staticLampGlow); // high comparison toggle
this.MAT = new B220Processor.FlipFlop(this, staticLampGlow); // multiple access toggle
this.MET = new B220Processor.FlipFlop(this, staticLampGlow); // memory (storage) alarm toggle
this.MNT = new B220Processor.FlipFlop(this, staticLampGlow); // manual toggle
this.OFT = new B220Processor.FlipFlop(this, staticLampGlow); // overflow toggle
this.PAT = new B220Processor.FlipFlop(this, staticLampGlow); // paper tape alarm toggle
this.PRT = new B220Processor.FlipFlop(this, staticLampGlow); // paper tape read toggle
this.PZT = new B220Processor.FlipFlop(this, staticLampGlow); // paper tape zone toggle
this.RPT = new B220Processor.FlipFlop(this, staticLampGlow); // repeat toggle
this.RUT = new B220Processor.FlipFlop(this, staticLampGlow); // run toggle
this.SST = new B220Processor.FlipFlop(this, staticLampGlow); // single-step toggle
this.TAT = new B220Processor.FlipFlop(this, staticLampGlow); // magnetic tape alarm toggle
this.UET = new B220Processor.FlipFlop(this, staticLampGlow); // unequal comparison toggle (HIT=UET=0 => off)
// Left/Right Maintenance Panel
this.leftPanelOpen = false;
@ -257,7 +258,7 @@ function B220Processor(config, devices) {
* Global Constants *
***********************************************************************/
B220Processor.version = "0.06";
B220Processor.version = "0.07";
B220Processor.tick = 1000/200000; // milliseconds per clock cycle (200KHz)
B220Processor.cyclesPerMilli = 1/B220Processor.tick;

View File

@ -96,11 +96,15 @@ window.addEventListener("load", function() {
/**************************************/
function openDiagPanel(ev) {
/* Opens the emulator's diagnostic monitor panel in a new sub-window */
var global = window;
diagWindow = window.open("B220DiagMonitor.html", "DiagPanel",
"resizable,width=300,height=500,left=0,top=" + screen.availHeight-500);
diagWindow.global = window; // give it access to our globals.
diagWindow.focus();
B220Util.openPopup(window, "B220DiagMonitor.html", "DiagPanel",
"resizable,width=300,height=500,left=0,top=" + screen.availHeight-500,
this, function(ev) {
diagWindow = ev.target.defaultView;
diagWindow.global = global; // give it access to our globals.
diagWindow.focus();
});
}
/**************************************/

View File

@ -26,11 +26,11 @@ function B220CardatronControl(p) {
// Do not call this.clear() here -- call from onLoad instead
this.doc = null;
this.window = window.open("../webUI/B220CardatronControl.html", this.mnemonic,
this.window = null;
B220Util.openPopup(window, "../webUI/B220CardatronControl.html", this.mnemonic,
"location=no,scrollbars=no,resizable,width=140,height=140,left=" + left +
",top=" + (screen.availHeight-140));
this.window.addEventListener("load",
B220CardatronControl.prototype.cardatronOnLoad.bind(this), false);
",top=" + (screen.availHeight-140),
this, B220CardatronControl.prototype.cardatronOnLoad);
// Set up the I/O devices from the system configuration
this.inputUnit = [
@ -127,14 +127,15 @@ B220CardatronControl.prototype.beforeUnload = function beforeUnload(ev) {
};
/**************************************/
B220CardatronControl.prototype.cardatronOnLoad = function cardatronOnLoad() {
B220CardatronControl.prototype.cardatronOnLoad = function cardatronOnLoad(ev) {
/* Initializes the Cardatron Control window and user interface */
var body;
var box;
var e;
var x;
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
body = this.$$("PanelSurface");
this.bufferReadLamp = new NeonLampBox(body, null, null, "BufferReadLamp");

View File

@ -45,17 +45,22 @@ function B220CardatronInput(mnemonic, unitIndex, config) {
new Uint8Array(this.bufferDrum, tks*6, tks), // format band 6 (fixed)
new Uint8Array(this.bufferDrum, tks*7, tks)]; // format band 7 (dummy)
// Initialize format band 6 for all-numeric transfer
// (note that ArrayBuffer storage is initialized to zero, so band[160..233] == 0)
for (x=0; x<160; x+=2) {
// Initialize format band 6 for all-numeric transfer.
for (x=0; x<160; x+=2) { // transfer 80 numeric digits
this.formatBand[6][x] = 1;
this.formatBand[6][x+1] = 3;
}
for (x=234; x<this.info.length; ++x) {
// Fill 77 digits of zeroes (8 to complete the word from cols 1-3, 66 to supply six
// computer words of zeroes, and three "pusher" digits to release the last word from D
// (note that ArrayBuffer storage is initialized to zero, so band[160..236] == 0).
for (x=237; x<this.info.length; ++x) { // fill inactive segment with delete codes
this.formatBand[6][x] = 3;
}
this.doc = null;
this.window = null;
this.hopperBar = null;
this.outHopperFrame = null;
this.outHopper = null;
@ -63,12 +68,12 @@ function B220CardatronInput(mnemonic, unitIndex, config) {
this.formatColumnList = null;
this.formatSelect = 0; // current format selection
this.formatSelectList = null;
this.window = window.open("../webUI/B220CardatronInput.html", mnemonic,
B220Util.openPopup(window, "../webUI/B220CardatronInput.html", mnemonic,
"location=no,scrollbars,resizable,width=" + w + ",height=" + h +
",left=" + ((unitIndex-1)*32) +
",top=" + (screen.availHeight - h - (unitIndex-1)*32));
this.window.addEventListener("load",
B220CardatronInput.prototype.readerOnLoad.bind(this), false);
",left=" + ((unitIndex-1)*32) +
",top=" + (screen.availHeight - h - (unitIndex-1)*32),
this, B220CardatronInput.prototype.readerOnLoad);
}
/**************************************/
@ -119,6 +124,7 @@ B220CardatronInput.prototype.clear = function clear() {
this.ready = false; // ready status
this.bufferReady = false; // buffer drum info band is ready to send data to Processor
this.noFormatAlarm = false; // No Formal Alarm toggle
this.noReload = false; // Reload/Format Lockout was set on last op or card
this.reloadLockout = false; // Reload Lockout toggle
this.formatLockout = false; // Format Lockout toggle
this.readRequested = false; // Processor has initiated a read, waiting for buffer
@ -282,6 +288,7 @@ B220CardatronInput.prototype.CIHopperBar_onClick = function CIHopperBar_onClick(
this.bufLength = 0;
this.bufIndex = 0;
this.hopperBar.value = 0;
this.clearUnit();
this.$$("CIFileSelector").value = null; // reset the control
while (this.outHopper.childNodes.length > 0) {
this.outHopper.removeChild(this.outHopper.firstChild);
@ -439,33 +446,40 @@ B220CardatronInput.prototype.determineFormatBand = function determineFormatBand(
break;
case "`": // 1-8 punch
format = 1;
this.noReload = true;
this.setFormatLockout(true);
break;
case ":": // 2-8 punch
format = 2;
this.noReload = true;
this.setFormatLockout(true);
break;
case "#": // 3-8 punch
format = 3;
this.noReload = true;
this.setFormatLockout(true);
break;
case "@": // 4-8 punch
format = 4;
this.noReload = true;
this.setFormatLockout(true);
break;
case "'": // 5-8 punch
case "|": // translates to a 5-numeric digit
format = 5;
this.noReload = true;
this.setFormatLockout(true);
break;
case "=": // 6-8 punch
case "}": // translates to a 6-numeric digit
format = 6;
this.noReload = true;
this.setFormatLockout(true);
break;
case "\"": // 7-8 punch -- reject plus lockout
case "~": // translates to a 7-numeric digit
format = 7+8;
this.noReload = true;
this.setFormatLockout(true);
break;
default:
@ -573,13 +587,14 @@ B220CardatronInput.prototype.beforeUnload = function beforeUnload(ev) {
};
/**************************************/
B220CardatronInput.prototype.readerOnLoad = function readerOnLoad() {
B220CardatronInput.prototype.readerOnLoad = function readerOnLoad(ev) {
/* Initializes the reader window and user interface */
var body;
var de;
var prefs = this.config.getNode("Cardatron.units", this.unitIndex);
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
de = this.doc.documentElement;
this.doc.title = "retro-220 Cardatron Reader " + this.mnemonic;
@ -742,7 +757,8 @@ B220CardatronInput.prototype.inputStop = function inputStop() {
/* Terminates data transfer from the input unit and releases the card */
this.setFormatSelectLamps(0);
if (this.rDigit % 2) { // set reload-lockout
if (this.noReload) { // set reload-lockout
this.noReload = false;
if (!this.reloadLockout) {
this.setReloadLockout(true);
}
@ -785,6 +801,7 @@ B220CardatronInput.prototype.inputInitiate = function inputInitiate(rDigit, word
}
} else {
this.rDigit = rDigit;
this.noReload |= (rDigit%2 == 1);
this.infoIndex = 0; // start at the beginning of the info band
this.digitCount = 0;
this.pendingInputWord = 0;
@ -831,7 +848,16 @@ B220CardatronInput.prototype.inputFormatTransfer = function inputFormatTransfer(
this.pendingFinish(); // call signalFinished();
this.pendingFinish = null;
this.inputStop();
this.setFormatSelectLamps(0);
if (this.noReload) { // set reload-lockout
this.noReload = false;
if (!this.reloadLockout) {
this.setReloadLockout(true);
}
} else if (this.reloadLockout) { // reset reload-lockout
this.setReloadLockout(false);
this.initiateCardRead();
}
};
/**************************************/
@ -849,6 +875,7 @@ B220CardatronInput.prototype.inputFormatInitiate = function inputFormatInitiate(
signalFinished();
} else {
this.rDigit = rDigit;
this.noReload |= (rDigit%2 == 1);
this.selectedFormat = ((rDigit >>> 1) & 0x07) + 1;
this.pendingFinish = signalFinished; // stash the call-back function
this.setFormatSelectLamps(this.selectedFormat);
@ -872,7 +899,7 @@ B220CardatronInput.prototype.clearUnit = function clearUnit() {
// If there is a pending read, confirm that this.pendingParams[1] is a
// function and call it with the end-of-data signal. We assume it's the
// Processor's wordReceiver function. This will prevent the Processor
// Processor's wordReceiver function. This will prevent the Processor
// from hanging on an I/O to a cleared input unit.
if (this.readRequested) {
if (Object.prototype.toString.call(this.pendingParams) === "[object Array]") {

View File

@ -59,18 +59,19 @@ function B220CardatronOutput(mnemonic, unitIndex, config) {
// Device window
this.doc = null;
this.window = null;
this.barGroup = null; // current greenbar line group
this.supplyDoc = null; // the content document for the supply frame
this.supply = null; // the "paper" or "cards" we print/punch on
this.endOfSupply = null; // dummy element used to control scrolling
this.supplyMeter = null; // <meter> element showing amount of paper/card supply remaining
w = (this.isPrinter ? 790 : 608);
this.window = window.open("../webUI/B220CardatronOutput.html", mnemonic,
B220Util.openPopup(window, "../webUI/B220CardatronOutput.html", mnemonic,
"location=no,scrollbars,resizable,width=" + w + ",height=" + h +
",left=" + (screen.availWidth - w) +
",top=" + (screen.availHeight - h - (unitIndex-3)*32));
this.window.addEventListener("load",
B220CardatronOutput.prototype.deviceOnLoad.bind(this), false);
",left=" + (screen.availWidth - w) +
",top=" + (screen.availHeight - h - (unitIndex-3)*32),
this, B220CardatronOutput.prototype.deviceOnLoad);
}
/**************************************/
@ -93,8 +94,8 @@ B220CardatronOutput.prototype.outputXlate = [
[0x2D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x20,0x24,0x2A], // zone digit 2
[0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20], // zone digit 3
[0x30,0x2F,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x20,0x2C,0x25], // zone digit 4
[0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20], // zone digit 5
[0x2D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20], // zone digit 6
[0x26,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x20,0x2E,0xA4], // zone digit 5
[0x2D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x20,0x24,0x2A], // zone digit 6
[0x20,0x20,0x39,0x2E,0xA4,0xA4,0x2E,0xA4,0x20,0x20,0x20,0x2E,0xA4], // zone digit 7
[0x20,0x4A,0x49,0x24,0x2A,0x2A,0x24,0x2A,0x20,0x20,0x20,0x24,0x2A], // zone digit 8
[0x20,0x20,0x52,0x27,0x25,0x25,0x2C,0x25,0x20,0x20,0x20,0x27,0x25], // zone digit 9
@ -102,9 +103,9 @@ B220CardatronOutput.prototype.outputXlate = [
[0x20,0x26,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20], // zone digit 11
[0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20]]; // zone digit 12
// Translate buffer zone digits to internal zone decades.
// Each row is indexed by the zone digit from the buffer drum info band;
// each column is indexed by the PREVIOUS numeric digit from the info band.
// Translate internal zone decades to buffer zone digits.
// Each row is indexed by the zone digit from the internal character code;
// each column is indexed by the PREVIOUS numeric digit from the character code.
// See U.S. Patent 3,072,328, January 8, 1963, L.L. Bewley et al, Figure 12;
// and ElectroData Technical Newsletter #5 of February 14, 1958.
B220CardatronOutput.prototype.zoneXlate = [ // numeric digit:0 1 2 3 4 5 6 7 8 9
@ -157,7 +158,7 @@ B220CardatronOutput.prototype.clear = function clear() {
this.supplyLeft = this.maxSupplyLines; // lines/cards remaining in output supply
this.runoutSupplyCount = 0; // counter for triple-formfeed => rip paper/empty hopper
this.groupLinesLeft = 0; // lines remaining in current greenbar group
this.topOfForm = false; // start new page flag
this.atTopOfForm = false; // start new page flag
this.pendingSpaceBefore = -1; // pending carriage control (eat the initial space-before)
this.pendingCall = null; // stashed pending function reference
@ -244,22 +245,22 @@ B220CardatronOutput.prototype.copySupply = function copySupply(ev) {
var barGroup = this.supply.firstChild;
var text = "";
var title = "B220 " + this.mnemonic + " Text Snapshot";
var win = window.open("./B220FramePaper.html", this.mnemonic + "-Snapshot",
"scrollbars,resizable,width=500,height=500");
while (barGroup) {
text += barGroup.textContent + "\n";
barGroup = barGroup.nextSibling;
}
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
win.addEventListener("load", function() {
var doc;
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Snapshot",
"scrollbars,resizable,width=500,height=500",
this, function(ev) {
var doc = ev.target;
var win = doc.defaultView;
doc = win.document;
doc.title = title;
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
doc.getElementById("Paper").textContent = text;
}, false);
});
this.runoutSupply();
ev.preventDefault();
@ -303,30 +304,36 @@ B220CardatronOutput.prototype.appendLine = function appendLine(text) {
--this.groupLinesLeft;
};
/**************************************/
B220CardatronOutput.prototype.skipToChannel = function skipToChannel() {
/* Finishes the current page and sets up for top-of-form formatting on the
next line printed. Adjusts the supply of forms left */
var lines = 0;
while(this.groupLinesLeft > 0) {
++lines;
this.appendLine("\xA0");
}
this.atTopOfForm = true;
this.supplyMeter.value = this.supplyLeft -= lines;
};
/**************************************/
B220CardatronOutput.prototype.printLine = function printLine(text, spaceBefore) {
/* Prints one line to the output, handling carriage control and greenbar
group completion. For now, SPACE 0 (overprinting) is treated as single-spacing */
var lines = 0;
var lines = spaceBefore;
if (spaceBefore < 0) { // skip to channel 1
while(this.groupLinesLeft > 0) {
++lines;
this.appendLine("\xA0");
}
this.atTopOfForm = true;
} else { // space before print
lines = spaceBefore;
while (lines > 1) {
--lines;
--this.supplyLeft;
this.appendLine("\xA0");
}
while (lines > 1) { // space before print
--lines;
--this.supplyLeft;
this.appendLine("\xA0");
}
this.appendLine(text || "\xA0");
if (this.supplyLeft > 0) {
this.supplyMeter.value = this.supplyLeft -= lines;
this.supplyMeter.value = this.supplyLeft -= 1;
} else {
this.setDeviceReady(false);
B220Util.addClass(this.$$("COEndOfSupplyBtn"), "redLit");
@ -433,7 +440,8 @@ B220CardatronOutput.prototype.initiateWrite = function initiateWrite() {
case 1: // Relay 1 (eject page after printing)
case 9: // same as 1
this.printLine(line, this.pendingSpaceBefore);
this.pendingSpaceBefore = -99;
this.skipToChannel();
this.pendingSpaceBefore = 0;
break;
case 2: // Relay 2 (single space before and after printing)
this.printLine(line, this.pendingSpaceBefore+1);
@ -442,7 +450,8 @@ B220CardatronOutput.prototype.initiateWrite = function initiateWrite() {
case 3: // Relay 3 (eject page before printing)
case 5: // Relay 5 (skip to channel 2 before printing)
case 7: // Relay 3+5 (skip to channel 3 before printing)
this.printLine(line, -1);
this.skipToChannel();
this.printLine(line, 0);
this.pendingSpaceBefore = 0;
break;
case 4: // Relay 4 (double space before printing)
@ -627,11 +636,9 @@ B220CardatronOutput.prototype.parseZeroSuppressList = function parseZeroSuppress
B220CardatronOutput.prototype.COSetZSBtn_onClick = function COSetZSBtn_onClick(ev) {
/* Displays the Zero Suppress Panel window to capture a list of column numbers */
var $$$ = null; // getElementById shortcut for loader window
var doc = null; // loader window.document
var doc = null; // zero-suppress window.document
var tron = this; // this B220CardatronOutput device instance
var win = this.window.open("B220CardatronZeroSuppressPanel.html", this.mnemonic + "ZS",
"location=no,scrollbars=no,resizable,width=508,height=120,left=" +
(this.window.screenX+16) +",top=" + (this.window.screenY+16));
var win = null; // zero-suppress window defaultView
function zsOK(ev) {
/* Handler for the OK button. Parses the list of column numbers; if successful,
@ -660,7 +667,9 @@ B220CardatronOutput.prototype.COSetZSBtn_onClick = function COSetZSBtn_onClick(e
/* Driver for the tape loader window */
var de;
doc = win.document;
doc = ev.target;
win = doc.defaultView;
this.zsWindow = win;
doc.title = "retro-220 " + tron.mnemonic + " Zero-Suppress Panel";
de = doc.documentElement;
$$$ = function $$$(id) {
@ -676,17 +685,20 @@ B220CardatronOutput.prototype.COSetZSBtn_onClick = function COSetZSBtn_onClick(e
win.resizeBy(de.scrollWidth - win.innerWidth,
de.scrollHeight - win.innerHeight);
$$$("COZSColumnList").focus();
win.addEventListener("unload", function zsUnload(ev) {
this.zsWindow = null;
}, false);
}
// Outer block of COSetZSBtn_onClick
if (this.zsWindow && !this.zsWindow.closed) {
this.zsWindow.close();
}
this.zsWindow = win;
win.addEventListener("load", zsOnload, false);
win.addEventListener("unload", function zsUnload(ev) {
this.zsWindow = null;
}, false);
B220Util.openPopup(this.window, "B220CardatronZeroSuppressPanel.html", this.mnemonic + "ZS",
"location=no,scrollbars=no,resizable,width=508,height=120,left=" +
(this.window.screenX+16) +",top=" + (this.window.screenY+16),
this, zsOnload);
};
/**************************************/
@ -700,7 +712,7 @@ B220CardatronOutput.prototype.beforeUnload = function beforeUnload(ev) {
};
/**************************************/
B220CardatronOutput.prototype.deviceOnLoad = function deviceOnLoad() {
B220CardatronOutput.prototype.deviceOnLoad = function deviceOnLoad(ev) {
/* Initializes the printer/punch window and user interface */
var body;
var de;
@ -708,7 +720,8 @@ B220CardatronOutput.prototype.deviceOnLoad = function deviceOnLoad() {
var prefs = this.config.getNode("Cardatron.units", this.unitIndex);
var zsCol;
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
de = this.doc.documentElement;
this.doc.title = "retro-220 Cardatron " +
(this.isPrinter ? "Printer " : "Punch ") + this.mnemonic;
@ -841,11 +854,13 @@ B220CardatronOutput.prototype.outputWord = function outputWord(requestNextWord)
nu = true; // next is a numeric digit
if (x > 9) {
// For a zone digit in the sign position, store a 5 (+) or 6 (-)
// so that the sign will be printed/punched as a zone 11/12.
if (d == 0 && this.suppress12Mode) {
// so that the sign will be printed/punched as a zone 11/12, UNLESS
// the sign is positive and Suppress-12 mode is in effect. In that
// case, store a zero to the zone so the sign will not print/punch.
if (d%2 == 0 && this.suppress12Mode) {
info[ix] = 0; // suppress the 12-zone output
} else {
info[ix] = (d & 0x01) + 5;
info[ix] = d%2 + 5;
}
} else if (d > 3) {
info[ix] = this.zoneXlate[d][lastNumeric];

View File

@ -25,7 +25,6 @@ function B220ConsoleKeyboard(p) {
this.boundKeypress = B220ConsoleKeyboard.prototype.keypress.bind(this);
this.boundButton_Click = B220ConsoleKeyboard.prototype.button_Click.bind(this);
this.boundKeyboard_OnLoad = B220ConsoleKeyboard.prototype.keyboardOnLoad.bind(this);
this.boundKeyboard_Unload = B220ConsoleKeyboard.prototype.keyboardUnload.bind(this);
this.clear();
@ -188,10 +187,10 @@ B220ConsoleKeyboard.prototype.keyboardOpen = function keyboardOpen() {
var w = 240;
if (!this.window) {
this.window = window.open("../webUI/B220ConsoleKeyboard.html", this.mnemonic,
B220Util.openPopup(window, "../webUI/B220ConsoleKeyboard.html", this.mnemonic,
"resizable,width=" + w + ",height=" + h +
",left=" + (screen.availWidth - w) + ",top=" + (screen.availHeight - h));
this.window.addEventListener("load", this.boundKeyboard_OnLoad, false);
",left=" + (screen.availWidth - w) + ",top=" + (screen.availHeight - h),
this, B220ConsoleKeyboard.prototype.keyboardOnLoad);
}
};
@ -207,13 +206,13 @@ B220ConsoleKeyboard.prototype.keyboardUnload = function keyboardUnload(ev) {
};
/**************************************/
B220ConsoleKeyboard.prototype.keyboardOnLoad = function keyboardOnLoad() {
B220ConsoleKeyboard.prototype.keyboardOnLoad = function keyboardOnLoad(ev) {
/* Initializes the Control Console window and user interface */
var body;
var de;
this.window.removeEventListener("load", this.boundKeyboard_OnLoad, false);
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
body = this.$$("KeyboardCase");
de = this.doc.documentElement;
@ -237,7 +236,7 @@ B220ConsoleKeyboard.prototype.keyboardOnLoad = function keyboardOnLoad() {
// Kludge for Chrome window.outerWidth/Height timing bug
setCallback(null, this, 100, function chromeBug() {
this.window.moveTo(screen.availWidth-this.window.outerWidth,
this.window.moveTo(screen.availWidth - this.window.outerWidth,
screen.availHeight - this.window.outerHeight);
});
};

View File

@ -49,11 +49,10 @@ function B220ConsolePrinter(mnemonic, unitIndex, config) {
this.printerEOP = null;
this.printerLine = 0;
this.printerCol = 0;
this.window = window.open("../webUI/B220ConsolePrinter.html", mnemonic,
B220Util.openPopup(window, "../webUI/B220ConsolePrinter.html", mnemonic,
"location=no,scrollbars=no,resizable,width=640,height=240," +
"left=" + left + ",top=" + top);
this.window.addEventListener("load",
B220ConsolePrinter.prototype.printerOnLoad.bind(this), false);
"left=" + left + ",top=" + top,
this, B220ConsolePrinter.prototype.printerOnLoad);
}
/**************************************/
@ -210,17 +209,17 @@ B220ConsolePrinter.prototype.copyPaper = function copyPaper(ev) {
or saved by the user */
var text = this.paper.textContent;
var title = "B220 " + this.mnemonic + " Text Snapshot";
var win = window.open("./B220FramePaper.html", "TTY-Snapshot",
"scrollbars,resizable,width=500,height=500");
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
win.addEventListener("load", function() {
var doc;
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Snapshot",
"scrollbars,resizable,width=500,height=500",
this, function(ev) {
var doc = ev.target;
var win = doc.defaultView;
doc = win.document;
doc.title = title;
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
doc.getElementById("Paper").textContent = text;
}, false);
});
this.emptyPaper();
this.emptyLine();
@ -381,7 +380,7 @@ B220ConsolePrinter.prototype.parseTabStops = function parsetabStops(text, alertW
};
/**************************************/
B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad() {
B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad(ev) {
/* Initializes the Teletype printer window and user interface */
var body;
var id;
@ -390,7 +389,8 @@ B220ConsolePrinter.prototype.printerOnLoad = function printerOnLoad() {
var tabStop;
var x;
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
this.doc.title = "retro-220 Printer - " + this.mnemonic;
this.paper = this.$$("Paper");
this.printerEOP = this.$$("EndOfPaper");

View File

@ -95,11 +95,11 @@ function B220ControlConsole(p, systemShutdown) {
// Create the Console window
this.doc = null;
this.window = window.open("../webUI/B220ControlConsole.html", mnemonic,
this.window = null;
B220Util.openPopup(window, "../webUI/B220ControlConsole.html", mnemonic,
"location=no,scrollbars,resizable,width=" + w + ",height=" + h +
",top=0,left=" + (screen.availWidth - w));
this.window.addEventListener("load",
B220ControlConsole.prototype.consoleOnLoad.bind(this), false);
",top=0,left=" + (screen.availWidth - w),
this, B220ControlConsole.prototype.consoleOnLoad);
}
/**************************************/
@ -172,12 +172,11 @@ B220ControlConsole.prototype.beforeUnload = function beforeUnload(ev) {
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 doc = null; // dump 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 win = null; // dump window
var xlate = B220ControlConsole.codeXlate; // local copy
function formatWord(w) {
@ -378,22 +377,24 @@ B220ControlConsole.prototype.meatballMemdump = function meatballMemdump() {
writer("End dump, memory size: " + (top+1).toString() + " words");
}
function memdumpSetup() {
function memdumpSetup(ev) {
/* 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 = ev.target;
win = doc.defaultView
doc.title = "retro-220 Console: Meatball Memdump";
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
paper = doc.getElementById("Paper");
writer("Rendering the dump... please wait...");
setTimeout(memdumpDriver, 50);
win.focus();
}
// Outer block of meatBallMemdump
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
win.focus();
win.addEventListener("load", memdumpSetup, false);
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-MEMDUMP",
"location=no,scrollbars=yes,resizable,width=800,height=600",
this, memdumpSetup);
};
/**************************************/
@ -789,7 +790,7 @@ B220ControlConsole.prototype.switch_Click = function switch_Click(ev) {
};
/**************************************/
B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad() {
B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad(ev) {
/* Initializes the Supervisory Panel window and user interface */
var body;
var p = this.p; // local copy of processor object
@ -797,7 +798,8 @@ B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad() {
var prefs = this.config.getNode("ControlConsole");
var x;
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
body = this.$$("PanelSurface");
this.intervalTimer = this.$$("IntervalTimer");

View File

@ -16,7 +16,7 @@
function B220MagTapeControl(p) {
/* Constructor for the MagTapeControl object */
var left = 0; // control window left position
var top = 412; // control window top-from-bottom position
var top = 432; // control window top-from-bottom position
var u; // unit configuration object
var x; // unit index
@ -28,11 +28,11 @@ function B220MagTapeControl(p) {
// Do not call this.clear() here -- call this.clearUnit() from onLoad instead
this.doc = null;
this.window = window.open("../webUI/B220MagTapeControl.html", this.mnemonic,
this.window = null;
B220Util.openPopup(window, "../webUI/B220MagTapeControl.html", this.mnemonic,
"location=no,scrollbars=no,resizable,width=712,height=144,top=" +
(screen.availHeight - top) + ",left=" + left);
this.window.addEventListener("load",
B220MagTapeControl.prototype.magTapeOnLoad.bind(this), false);
(screen.availHeight - top) + ",left=" + left,
this, B220MagTapeControl.prototype.magTapeOnLoad);
this.boundReleaseControl = B220MagTapeControl.prototype.releaseControl.bind(this);
this.boundCancelIO = B220MagTapeControl.prototype.cancelIO.bind(this);
@ -212,7 +212,7 @@ B220MagTapeControl.prototype.findDesignate = function findDesignate(u) {
var unit;
var x;
for (x=this.tapeUnit.length-1; x>=0; --x) {
for (x=this.tapeUnit.length-1; x>0; --x) {
unit = this.tapeUnit[x];
if (unit && unit.ready) {
if (unit.unitDesignate == u) {
@ -523,14 +523,15 @@ B220MagTapeControl.prototype.beforeUnload = function beforeUnload(ev) {
};
/**************************************/
B220MagTapeControl.prototype.magTapeOnLoad = function magTapeOnLoad() {
B220MagTapeControl.prototype.magTapeOnLoad = function magTapeOnLoad(ev) {
/* Initializes the MagTape Control window and user interface */
var body;
var box;
var e;
var x;
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
body = this.$$("PanelSurface");
// Misc Register
@ -656,7 +657,7 @@ B220MagTapeControl.prototype.scan = function scan(dReg, bReg) {
this.releaseControl();
} else {
// Start the scan after changing lane, as appropriate
this.T = searchWord;
this.T = searchWord%0x10000000000;
this.regT.update(this.T);
this.releaseProcessor(false, 0);
this.TFLamp.set(1);
@ -773,7 +774,7 @@ B220MagTapeControl.prototype.search = function search(dReg, bReg) {
this.releaseControl();
} else {
// Start the search after changing lane, as appropriate
this.T = searchWord;
this.T = searchWord%0x10000000000;
this.regT.update(this.T);
this.releaseProcessor(false, 0);
this.TFLamp.set(1);

View File

@ -141,10 +141,10 @@ function B220MagTapeDrive(mnemonic, unitIndex, tcu, config) {
this.boundStartUpForward = B220MagTapeDrive.prototype.startUpForward.bind(this);
this.doc = null;
this.window = window.open("../webUI/B220MagTapeDrive.html", mnemonic,
"location=no,scrollbars=no,resizable,width=384,height=184,left=0,top=" + y);
this.window.addEventListener("load",
B220MagTapeDrive.prototype.tapeDriveOnload.bind(this), false);
this.window = null;
B220Util.openPopup(window, "../webUI/B220MagTapeDrive.html", mnemonic,
"location=no,scrollbars=no,resizable,width=384,height=184,left=0,top=" + y,
this, B220MagTapeDrive.prototype.tapeDriveOnload);
}
// this.tapeState enumerations
@ -554,9 +554,7 @@ B220MagTapeDrive.prototype.loadTape = function loadTape() {
var file = null; // FileReader instance
var fileSelect = null; // file picker element
var mt = this; // this B220MagTapeDrive instance
var win = this.window.open("B220MagTapeLoadPanel.html", this.mnemonic + "Load",
"location=no,scrollbars=no,resizable,width=508,height=112,left=" +
(this.window.screenX+16) +",top=" + (this.window.screenY+16));
var win = null; // loader window
function fileSelector_onChange(ev) {
/* Handle the <input type=file> onchange event when a file is selected */
@ -891,14 +889,16 @@ B220MagTapeDrive.prototype.loadTape = function loadTape() {
/* Driver for the tape loader window */
var de;
doc = win.document;
doc = ev.target;
win = doc.defaultView;
doc.title = "retro-220 " + mt.mnemonic + " Tape Loader";
this.loadWindow = win;
de = doc.documentElement;
$$$ = function $$$(id) {
return doc.getElementById(id);
};
win.removeEventListener("load", tapeLoadOnload, false);
win.addEventListener("unload", tapeLoadUnload, false);
fileSelect = $$$("MTLoadFileSelector");
fileSelect.addEventListener("change", fileSelector_onChange, false);
@ -921,20 +921,21 @@ B220MagTapeDrive.prototype.loadTape = function loadTape() {
if (this.loadWindow && !this.loadWindow.closed) {
this.loadWindow.close();
}
this.loadWindow = win;
win.addEventListener("load", tapeLoadOnload, false);
win.addEventListener("unload", tapeLoadUnload, false);
B220Util.openPopup(this.window, "B220MagTapeLoadPanel.html", this.mnemonic + "Load",
"location=no,scrollbars=no,resizable,width=508,height=112,left=" +
(this.window.screenX+16) +",top=" + (this.window.screenY+16),
this, tapeLoadOnload);
};
/**************************************/
B220MagTapeDrive.prototype.unloadTape = function unloadTape() {
/* Reformats the tape image data as ASCII text and displays it in a new
window so the user can save or copy/paste it elsewhere */
var doc = null; // loader window.document
var doc = null; // unloader window.document
var image; // <pre> element to receive tape image data
var mt = this; // tape drive object
var win = this.window.open("./B220FramePaper.html", this.mnemonic + "-Unload",
"location=no,scrollbars=yes,resizable,width=800,height=600");
var win = null; // unloader window
function findBlockStart() {
/* Searches forward in the tape image on the currently-selected lane for the
@ -1071,23 +1072,25 @@ B220MagTapeDrive.prototype.unloadTape = function unloadTape() {
mt.setTapeUnloaded();
}
function unloadSetup() {
function unloadSetup(ev) {
/* Loads a status message into the "paper" rendering area, then calls
unloadDriver after a short wait to allow the message to appear */
win.removeEventListener("load", unloadSetup, false);
doc = win.document;
doc = ev.target;
win = doc.defaultView;
doc.title = "retro-220 " + mt.mnemonic + " Unload Tape";
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
image = doc.getElementById("Paper");
image.appendChild(win.document.createTextNode(
"Rendering tape image... please wait..."));
setTimeout(unloadDriver, 50);
win.focus();
}
// Outer block of unloadTape
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
win.focus();
win.addEventListener("load", unloadSetup, false);
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Unload",
"location=no,scrollbars=yes,resizable,width=800,height=600",
this, unloadSetup);
};
/**************************************/
@ -1174,12 +1177,13 @@ B220MagTapeDrive.prototype.beforeUnload = function beforeUnload(ev) {
};
/**************************************/
B220MagTapeDrive.prototype.tapeDriveOnload = function tapeDriveOnload() {
B220MagTapeDrive.prototype.tapeDriveOnload = function tapeDriveOnload(ev) {
/* Initializes the reader window and user interface */
var body;
var prefs = this.config.getNode("MagTape.units", this.unitIndex);
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
this.doc.title = "retro-220 Tape Drive " + this.mnemonic;
body = this.$$("MTDiv");

View File

@ -34,13 +34,13 @@ function B220PaperTapePunch(mnemonic, unitIndex, config) {
// Create the punch window and onload event
this.doc = null;
this.window = null;
this.punchTape = null;
this.punchEOP = null;
this.window = window.open("../webUI/B220PaperTapePunch.html", mnemonic,
B220Util.openPopup(window, "../webUI/B220PaperTapePunch.html", mnemonic,
"location=no,scrollbars=no,resizable,width=240,height=160," +
"left=" + left + ",top=" + top);
this.window.addEventListener("load",
B220PaperTapePunch.prototype.punchOnLoad.bind(this), false);
"left=" + left + ",top=" + top,
this, B220PaperTapePunch.prototype.punchOnLoad);
}
/**************************************/
@ -156,15 +156,15 @@ B220PaperTapePunch.prototype.punchCopyTape = function punchCopyTape(ev) {
or saved by the user */
var text = this.punchTape.textContent;
var title = "B220 " + this.mnemonic + " Text Snapshot";
var win = window.open("./B220FramePaper.html", "PaperTape-Snapshot",
"scrollbars,resizable,width=500,height=500");
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
win.addEventListener("load", function() {
var doc;
B220Util.openPopup(this.window, "./B220FramePaper.html", this.mnemonic + "-Snapshot",
"scrollbars,resizable,width=500,height=500",
this, function(ev) {
var doc = ev.target;
var win = doc.defaultView;
doc = win.document;
doc.title = title;
win.moveTo((screen.availWidth-win.outerWidth)/2, (screen.availHeight-win.outerHeight)/2);
doc.getElementById("Paper").textContent = text;
});
@ -205,14 +205,15 @@ B220PaperTapePunch.prototype.flipSwitch = function flipSwitch(ev) {
};
/**************************************/
B220PaperTapePunch.prototype.punchOnLoad = function punchOnLoad() {
B220PaperTapePunch.prototype.punchOnLoad = function punchOnLoad(ev) {
/* Initializes the Paper Tape Punch window and user interface */
var body;
var mask;
var prefs = this.config.getNode("ConsoleOutput.units", this.unitIndex);
var x;
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
this.doc.title = "retro-220 Punch - " + this.mnemonic;
this.punchTape = this.$$("Paper");

View File

@ -43,12 +43,12 @@ function B220PaperTapeReader(mnemonic, unitIndex, config) {
// Create the reader window and onload event
this.doc = null;
this.window = null;
this.tapeSupplyBar = null;
this.tapeView = null;
this.window = window.open("../webUI/B220PaperTapeReader.html", mnemonic,
"location=no,scrollbars=no,resizable,width=420,height=160,left=" + left + ",top=" + top);
this.window.addEventListener("load",
B220PaperTapeReader.prototype.readerOnload.bind(this), false);
B220Util.openPopup(window, "../webUI/B220PaperTapeReader.html", mnemonic,
"location=no,scrollbars=no,resizable,width=420,height=160,left=" + left + ",top=" + top,
this, B220PaperTapeReader.prototype.readerOnload);
}
/**************************************/
@ -229,14 +229,15 @@ B220PaperTapeReader.prototype.flipSwitch = function flipSwitch(ev) {
};
/**************************************/
B220PaperTapeReader.prototype.readerOnload = function readerOnload() {
B220PaperTapeReader.prototype.readerOnload = function readerOnload(ev) {
/* Initializes the reader window and user interface */
var body;
var mask;
var prefs = this.config.getNode("ConsoleInput.units", this.unitIndex);
var x;
this.doc = this.window.document;
this.doc = ev.target;
this.window = this.doc.defaultView;
//de = this.doc.documentElement;
this.doc.title = "retro-220 - Reader - " + this.mnemonic;

View File

@ -1,275 +1,275 @@
/***********************************************************************
* retro-220/webUI B220SetCallback.js
************************************************************************
* Copyright (c) 2014,2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B220 emulator universal function call-back module.
*
* Implements a combination setTimeout() and setImmediate() facility for the
* B220 emulator web-based user interface. setCallback() is used in a manner
* similar to setTimeout(), except that for low values of the timeout parameter
* it merely yields control to any other pending events and timers before calling
* the call-back function.
*
* This facility is needed because modern browsers implement a minimum delay
* when calling setTimeout(). HTML5 specs require 4ms, but browsers vary in the
* minimum they use, and their precision in activating the call-back function
* once the actual delay is established varies even more. This module will use
* setTimeout() if the requested delay time is above a certain threshold, and
* a setImmediate-like mechanism (based on Promise) if the requested delay is
* below that threshold.
*
* To help compensate for the fact that the call-back function may be called
* sooner than requested, and that due either to other activity or to browser
* limitations the delay may be longer than requested, the timing behavior of
* setCallback() may be divided into "categories." For each category, a separate
* record is kept of the current total deviation between the requested delay and
* the actual delay. A portion of this deviation is then applied to the requested
* delay on subsequent calls in an attempt to smooth out the differences. We are
* going for good average behavior here, and some too-quick call-backs are better
* than consistently too-long callbacks in this environment, particularly so that
* I/Os can be initiated and their finish detected in finer-grained time increments.
*
* The SetCallback mechanism defines three functions that become members of the
* global (window) object:
*
* token = setCallback(category, context, delay, fcn[, arg])
*
* Requests that the function "fcn" be called after "delay" milliseconds.
* The function will be called as a method of "context", passing a
* single optional argument "arg". The call-back "fcn" may be called
* earlier or later than the specified delay. The string "category" (which
* may be empty, null, or undefined) defines the category under which the
* average delay difference will be maintained. setCallBack returns a
* numeric token identifying the call-back event, which can be used with
* clearCallback() to cancel the callback. Note that passing a string in
* lieu of a function object is not permitted.
*
* clearCallBack(token)
*
* Cancels a pending call-back event, if in fact it is still pending.
* The "token" parameter is a value returned from setCallback().
*
* object = getCallbackState(optionMask)
*
* This is a diagnostic function intended for use in monitoring the callback
* mechanism. It returns an object that, depending upon bits set in its mask
* parameter, contains copies of the lastTokenNr value, poolLength
* value, current delayDev hash, pendingCallbacks hash, and pool array.
* The optionMask parameter supports the following bit values:
* bit 0x01: delayDev hash
* bit 0x02: pendingCallbacks hash
* bit 0x04: pool array
* The lastTokenNr and poolLength values are always returned. If no mask
* is supplied, no additional items are returned.
*
* This implementation has been inspired by Domenic Denicola's shim for the
* setImmediate() API at https://github.com/NobleJS/setImmediate, and
* David Baron's setZeroTimeout() implemenmentation described in his blog
* at http://dbaron.org/log/20100309-faster-timeouts.
*
* I stole a little of their code, too.
*
************************************************************************
* 2017-01-01 P.Kimpel
* Original version, cloned from retro-205 emulator D205SetCallback.js.
* 2017-02-18 P.Kimpel
* Redesign yet again the delay adjustment mechanism with one from the
* retro-205 project.
* 2017-10-16 P.Kimpel
* Replace window.postMessage yield mechanism with one based on Promise().
***********************************************************************/
"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
var pendingCallbacks = {}; // hash of pending callbacks, indexed by token as a string
var perf = global.performance; // cached window.performance object
var pool = []; // pool of reusable callback objects
var poolLength = 0; // length of active entries in pool
/**************************************/
function activateCallback(token) {
/* Activates a callback after its delay period has expired */
var endStamp = perf.now();
var thisCallback;
var tokenName = token.toString();
thisCallback = pendingCallbacks[tokenName];
if (thisCallback) {
delete pendingCallbacks[tokenName];
delayDev[thisCallback.category] += endStamp - thisCallback.startStamp - thisCallback.delay;
try {
thisCallback.fcn.call(thisCallback.context, thisCallback.arg);
} catch (err) {
console.log("B220SetCallback.activateCallback: " + err.name + ", " + err.message);
}
thisCallback.context = null;
thisCallback.fcn = null;
thisCallback.arg = null;
pool[poolLength++] = thisCallback;
}
}
/**************************************/
function clearCallback(token) {
/* Disables a pending callback, if it still exists and is still pending */
var thisCallback;
var tokenName = token.toString();
thisCallback = pendingCallbacks[tokenName];
if (thisCallback) {
delete pendingCallbacks[tokenName];
if (thisCallback.cancelToken) {
global.clearTimeout(thisCallback.cancelToken);
}
thisCallback.context = null;
thisCallback.fcn = null;
thisCallback.arg = null;
pool[poolLength++] = thisCallback;
}
}
/**************************************/
function setCallback(category, context, callbackDelay, fcn, arg) {
/* Sets up and schedules a callback for function "fcn", called with context
"context", after a delay of "delay" ms. An optional "arg" value will be passed
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 token = ++lastTokenNr; // call-back token number
var tokenName = token.toString(); // call-back token ID
// Allocate a call-back object from the pool.
if (poolLength <= 0) {
thisCallback = {};
} else {
thisCallback = pool[--poolLength];
pool[poolLength] = null;
}
thisCallback.startStamp = perf.now();
// Adjust the requested delay based on the current delay deviation
// for this category.
delayBias = delayDev[categoryName];
if (!delayBias) {
delayDev[categoryName] = 0; // bias was zero, or got a new one: no adjustment
} 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;
}
} 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;
}
} else {
if (delay > minTimeout) {
adj = 0;
} else if (delay - minTimeout < delayBias) {
adj = -delayBias;
} else {
adj = minTimeout - delay;
}
}
}
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);
} else {
thisCallback.cancelToken = 0;
Promise.resolve(token).then(activateCallback);
}
return token;
}
/**************************************/
function getCallbackState(optionMask) {
/* Diagnostic function. Returns an object that, depending upon bits in
the option mask, contains copies of the lastTokenNr value, poolLength
value, current delayDev hash, pendingCallbacks hash, and pool array.
bit 0x01: delayDev hash
bit 0x02: pendingCallbacks hash
bit 0x04: pool array
If no mask is supplied, no additional items are returned */
var e;
var mask = optionMask || 0;
var state = {
lastTokenNr: lastTokenNr,
poolLength: poolLength,
delayDev: {},
pendingCallbacks: {},
pool: []};
if (mask & 0x01) {
for (e in delayDev) {
state.delayDev[e] = delayDev[e];
}
}
if (mask & 0x02) {
for (e in pendingCallbacks) {
state.pendingCallbacks[e] = pendingCallbacks[e];
}
}
if (mask & 0x04) {
for (e=0; e<poolLength; ++e) {
state.pool[e] = pool[e];
}
}
return state;
}
/********** Outer block of anonymous closure **********/
if (!global.setCallback && !global.importScripts) {
// Attach to the prototype of global, if possible, otherwise to global itself
var attachee = global;
/*****
if (typeof Object.getPrototypeOf === "function") {
if ("setTimeout" in Object.getPrototypeOf(global)) {
attachee = Object.getPrototypeOf(global);
}
}
*****/
attachee.setCallback = setCallback;
attachee.clearCallback = clearCallback;
attachee.getCallbackState = getCallbackState;
}
}(typeof global === "object" && global ? global : this));
/***********************************************************************
* retro-220/webUI B220SetCallback.js
************************************************************************
* Copyright (c) 2014,2017, Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B220 emulator universal function call-back module.
*
* Implements a combination setTimeout() and setImmediate() facility for the
* B220 emulator web-based user interface. setCallback() is used in a manner
* similar to setTimeout(), except that for low values of the timeout parameter
* it merely yields control to any other pending events and timers before calling
* the call-back function.
*
* This facility is needed because modern browsers implement a minimum delay
* when calling setTimeout(). HTML5 specs require 4ms, but browsers vary in the
* minimum they use, and their precision in activating the call-back function
* once the actual delay is established varies even more. This module will use
* setTimeout() if the requested delay time is above a certain threshold, and
* a setImmediate-like mechanism (based on Promise) if the requested delay is
* below that threshold.
*
* To help compensate for the fact that the call-back function may be called
* sooner than requested, and that due either to other activity or to browser
* limitations the delay may be longer than requested, the timing behavior of
* setCallback() may be divided into "categories." For each category, a separate
* record is kept of the current total deviation between the requested delay and
* the actual delay. A portion of this deviation is then applied to the requested
* delay on subsequent calls in an attempt to smooth out the differences. We are
* going for good average behavior here, and some too-quick call-backs are better
* than consistently too-long callbacks in this environment, particularly so that
* I/Os can be initiated and their finish detected in finer-grained time increments.
*
* The SetCallback mechanism defines three functions that become members of the
* global (window) object:
*
* token = setCallback(category, context, delay, fcn[, arg])
*
* Requests that the function "fcn" be called after "delay" milliseconds.
* The function will be called as a method of "context", passing a
* single optional argument "arg". The call-back "fcn" may be called
* earlier or later than the specified delay. The string "category" (which
* may be empty, null, or undefined) defines the category under which the
* average delay difference will be maintained. setCallBack returns a
* numeric token identifying the call-back event, which can be used with
* clearCallback() to cancel the callback. Note that passing a string in
* lieu of a function object is not permitted.
*
* clearCallBack(token)
*
* Cancels a pending call-back event, if in fact it is still pending.
* The "token" parameter is a value returned from setCallback().
*
* object = getCallbackState(optionMask)
*
* This is a diagnostic function intended for use in monitoring the callback
* mechanism. It returns an object that, depending upon bits set in its mask
* parameter, contains copies of the lastTokenNr value, poolLength
* value, current delayDev hash, pendingCallbacks hash, and pool array.
* The optionMask parameter supports the following bit values:
* bit 0x01: delayDev hash
* bit 0x02: pendingCallbacks hash
* bit 0x04: pool array
* The lastTokenNr and poolLength values are always returned. If no mask
* is supplied, no additional items are returned.
*
* This implementation has been inspired by Domenic Denicola's shim for the
* setImmediate() API at https://github.com/NobleJS/setImmediate, and
* David Baron's setZeroTimeout() implemenmentation described in his blog
* at http://dbaron.org/log/20100309-faster-timeouts.
*
* I stole a little of their code, too.
*
************************************************************************
* 2017-01-01 P.Kimpel
* Original version, cloned from retro-205 emulator D205SetCallback.js.
* 2017-02-18 P.Kimpel
* Redesign yet again the delay adjustment mechanism with one from the
* retro-205 project.
* 2017-10-16 P.Kimpel
* Replace window.postMessage yield mechanism with one based on Promise().
***********************************************************************/
"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
var pendingCallbacks = {}; // hash of pending callbacks, indexed by token as a string
var perf = global.performance; // cached window.performance object
var pool = []; // pool of reusable callback objects
var poolLength = 0; // length of active entries in pool
/**************************************/
function activateCallback(token) {
/* Activates a callback after its delay period has expired */
var endStamp = perf.now();
var thisCallback;
var tokenName = token.toString();
thisCallback = pendingCallbacks[tokenName];
if (thisCallback) {
delete pendingCallbacks[tokenName];
delayDev[thisCallback.category] += endStamp - thisCallback.startStamp - thisCallback.delay;
try {
thisCallback.fcn.call(thisCallback.context, thisCallback.arg);
} catch (err) {
console.log("B220SetCallback.activateCallback: " + err.name + ", " + err.message);
}
thisCallback.context = null;
thisCallback.fcn = null;
thisCallback.arg = null;
pool[poolLength++] = thisCallback;
}
}
/**************************************/
function clearCallback(token) {
/* Disables a pending callback, if it still exists and is still pending */
var thisCallback;
var tokenName = token.toString();
thisCallback = pendingCallbacks[tokenName];
if (thisCallback) {
delete pendingCallbacks[tokenName];
if (thisCallback.cancelToken) {
global.clearTimeout(thisCallback.cancelToken);
}
thisCallback.context = null;
thisCallback.fcn = null;
thisCallback.arg = null;
pool[poolLength++] = thisCallback;
}
}
/**************************************/
function setCallback(category, context, callbackDelay, fcn, arg) {
/* Sets up and schedules a callback for function "fcn", called with context
"context", after a delay of "delay" ms. An optional "arg" value will be passed
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 token = ++lastTokenNr; // call-back token number
var tokenName = token.toString(); // call-back token ID
// Allocate a call-back object from the pool.
if (poolLength <= 0) {
thisCallback = {};
} else {
thisCallback = pool[--poolLength];
pool[poolLength] = null;
}
thisCallback.startStamp = perf.now();
// Adjust the requested delay based on the current delay deviation
// for this category.
delayBias = delayDev[categoryName];
if (!delayBias) {
delayDev[categoryName] = 0; // bias was zero, or got a new one: no adjustment
} 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;
}
} 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;
}
} else {
if (delay > minTimeout) {
adj = 0;
} else if (delay - minTimeout < delayBias) {
adj = -delayBias;
} else {
adj = minTimeout - delay;
}
}
}
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);
} else {
thisCallback.cancelToken = 0;
Promise.resolve(token).then(activateCallback);
}
return token;
}
/**************************************/
function getCallbackState(optionMask) {
/* Diagnostic function. Returns an object that, depending upon bits in
the option mask, contains copies of the lastTokenNr value, poolLength
value, current delayDev hash, pendingCallbacks hash, and pool array.
bit 0x01: delayDev hash
bit 0x02: pendingCallbacks hash
bit 0x04: pool array
If no mask is supplied, no additional items are returned */
var e;
var mask = optionMask || 0;
var state = {
lastTokenNr: lastTokenNr,
poolLength: poolLength,
delayDev: {},
pendingCallbacks: {},
pool: []};
if (mask & 0x01) {
for (e in delayDev) {
state.delayDev[e] = delayDev[e];
}
}
if (mask & 0x02) {
for (e in pendingCallbacks) {
state.pendingCallbacks[e] = pendingCallbacks[e];
}
}
if (mask & 0x04) {
for (e=0; e<poolLength; ++e) {
state.pool[e] = pool[e];
}
}
return state;
}
/********** Outer block of anonymous closure **********/
if (!global.setCallback && !global.importScripts) {
// Attach to the prototype of global, if possible, otherwise to global itself
var attachee = global;
/*****
if (typeof Object.getPrototypeOf === "function") {
if ("setTimeout" in Object.getPrototypeOf(global)) {
attachee = Object.getPrototypeOf(global);
}
}
*****/
attachee.setCallback = setCallback;
attachee.clearCallback = clearCallback;
attachee.getCallbackState = getCallbackState;
}
}(typeof global === "object" && global ? global : this));

View File

@ -47,7 +47,6 @@
<div class=heading>System Properties:</div>
<select id=SystemMemorySize>
<option value=1000>1000
<option value=2000>2000
<option value=3000>3000
<option value=4000>4000
@ -935,7 +934,7 @@
<td class=center>
<select id=MagTape1Type>
<option value=NONE>(not used)
<option selected value=MTA>DataReader
<option selected value=MTA>TSU
<option value=DFA>DataFile
</select>
<td class=center>
@ -955,7 +954,7 @@
<td class=center>
<select id=MagTape2Type>
<option selected value=NONE>(not used)
<option value=MTB>DataReader
<option value=MTB>TSU
<option value=DFB>DataFile
</select>
<td class=center>
@ -975,7 +974,7 @@
<td class=center>
<select id=MagTape3Type>
<option selected value=NONE>(not used)
<option value=MTC>DataReader
<option value=MTC>TSU
<option value=DFC>DataFile
</select>
<td class=center>
@ -995,7 +994,7 @@
<td class=center>
<select id=MagTape4Type>
<option selected value=NONE>(not used)
<option value=MTD>DataReader
<option value=MTD>TSU
<option value=DFD>DataFile
</select>
<td class=center>
@ -1015,7 +1014,7 @@
<td class=center>
<select id=MagTape5Type>
<option selected value=NONE>(not used)
<option value=MTE>DataReader
<option value=MTE>TSU
<option value=DFE>DataFile
</select>
<td class=center>
@ -1035,7 +1034,7 @@
<td class=center>
<select id=MagTape6Type>
<option selected value=NONE>(not used)
<option value=MTF>DataReader
<option value=MTF>TSU
<option value=DFG>DataFile
</select>
<td class=center>
@ -1055,7 +1054,7 @@
<td class=center>
<select id=MagTape7Type>
<option selected value=NONE>(not used)
<option value=MTG>DataReader
<option value=MTG>TSU
<option value=DFG>DataFile
</select>
<td class=center>
@ -1075,7 +1074,7 @@
<td class=center>
<select id=MagTape8Type>
<option selected value=NONE>(not used)
<option value=MTH>DataReader
<option value=MTH>TSU
<option value=DFH>DataFile
</select>
<td class=center>
@ -1095,7 +1094,7 @@
<td class=center>
<select id=MagTape9Type>
<option selected value=NONE>(not used)
<option value=MTI>DataReader
<option value=MTI>TSU
<option value=DFI>DataFile
</select>
<td class=center>
@ -1115,7 +1114,7 @@
<td class=center>
<select id=MagTape10Type>
<option selected value=NONE>(not used)
<option value=MTJ>DataReader
<option value=MTJ>TSU
<option value=DFJ>DataFile
</select>
<td class=center>

View File

@ -41,7 +41,7 @@ B220SystemConfig.prototype.flushDelay = 60000; // flush timer setting, ms
B220SystemConfig.defaultConfig = {
version: this.configVersion,
memorySize: 5000, // 11-digit words
memorySize: 5000, // 11-digit words
ControlConsole: {
PCS1SW: 0, // Program Control Switches 1-0
@ -123,7 +123,7 @@ B220SystemConfig.defaultConfig = {
/**************************************/
B220SystemConfig.prototype.$$ = function $$(id) {
return this.window.document.getElementById(id);
return this.doc.getElementById(id);
}
/**************************************/
@ -412,7 +412,7 @@ B220SystemConfig.prototype.saveConfigDialog = function saveConfigDialog() {
// System Properties
e = this.$$("SystemMemorySize");
x = parseInt(e.options[e.selectedIndex], 10);
x = parseInt(e.options[e.selectedIndex].value, 10);
cd.memorySize = (isNaN(x) ? 5000 : x);
// Console Input units
@ -543,6 +543,12 @@ B220SystemConfig.prototype.openConfigUI = function openConfigUI() {
system configuration */
function configUI_Load(ev) {
this.doc = ev.target;
this.window = this.doc.defaultView;
this.window.moveTo(screen.availWidth-this.window.outerWidth-40,
(screen.availHeight-this.window.outerHeight)/2);
this.window.focus();
this.alertWin = this.window;
this.$$("SaveBtn").addEventListener("click",
this.saveConfigDialog.bind(this), false);
this.$$("CancelBtn").addEventListener("click",
@ -558,12 +564,8 @@ B220SystemConfig.prototype.openConfigUI = function openConfigUI() {
}
this.doc = null;
this.window = window.open("../webUI/B220SystemConfig.html", this.configStorageName,
"location=no,scrollbars,resizable,width=800,height=800");
this.window.moveTo(screen.availWidth-this.window.outerWidth-40,
(screen.availHeight-this.window.outerHeight)/2);
this.window.focus();
this.alertWin = this.window;
this.window.addEventListener("load",
configUI_Load.bind(this), false);
this.window = null;
B220Util.openPopup(window, "../webUI/B220SystemConfig.html", this.configStorageName,
"location=no,scrollbars,resizable,width=800,height=800",
this, configUI_Load);
};

View File

@ -18,6 +18,13 @@ function B220Util() {
// Nothing to construct at present...
}
/**************************************/
B220Util.popupOpenDelayIncrement = 250; // increment for pop-up open delay adjustment, ms
B220Util.popupOpenDelay = 500; // current pop-up open delay, ms
B220Util.popupOpenQueue = []; // queue of pop-up open argument objects
/**************************************/
B220Util.xlateASCIIToAlgolRex = // For translation of 220-ASCII to Algol-ASCII glyphs
/[^\r\n\xA0 $()*+,-./0-9=@A-Za-z]/g;
@ -73,9 +80,9 @@ B220Util.deepCopy = function deepCopy(source, dest) {
Adapted (with thanks) from the "extend" routine by poster Kamarey on 2011-03-26 at
http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object
*/
var constr;
var copy;
var name;
var constr = null;
var copy = null;
var name = "";
if (source === null) {
return source;
@ -141,7 +148,7 @@ B220Util.xlateAlgolToASCII = function xlateAlgolToASCII(text) {
B220Util.xlateDOMTreeText = function xlateDOMTreeText(n, xlate) {
/* If Node "n" is a text node, translates its value using the "xlate"
function. For all other Node types, translates all subordinate text nodes */
var kid;
var kid = null;
if (n.nodeType == Node.TEXT_NODE) {
n.nodeValue = xlate(n.nodeValue);
@ -153,3 +160,78 @@ B220Util.xlateDOMTreeText = function xlateDOMTreeText(n, xlate) {
}
}
};
/**************************************/
B220Util.openPopup = function openPopup(parent, url, windowName, options, context, onload) {
/* Schedules the opening of a pop-up window so that browsers such as Apple
Safari (11.0+) will not block the opens if they occur too close together.
Parameters:
parent: parent window for the pop-up
url: url of window context, passed to window.open()
windowName: internal name of the window, passed to window.open()
options: string of window options, passed to window.open()
context: object context ("this") for the onload function (may be null)
onload: event handler for the window's onload event (may be null).
If the queue of pending pop-up opens in B220Util.popupOpenQueue[] is empty,
then attempts to open the window immediately. Otherwise queues the open
parameters, which will be dequeued and acted upon after the previously-
queued entries are completed by B220Util.dequeuePopup() */
B220Util.popupOpenQueue.push({
parent: parent,
url: url,
windowName: windowName,
options: options,
context: context,
onload: onload});
if (B220Util.popupOpenQueue.length == 1) { // queue was empty
B220Util.dequeuePopup();
}
};
/**************************************/
B220Util.dequeuePopup = function dequeuePopup() {
/* Dequeues a popupOpenQueue[] entry and attempts to open the pop-up window.
Called either directly by B220Util.openPopup() when an entry is inserted
into an empty queue, or by setTimeout() after a delay. If the open fails,
the entry is reinserted into the head of the queue, the open delay is
incremented, and this function is rescheduled for the new delay. If the
open is successful, and the queue is non-empty, then this function is
scheduled for the current open delay to process the next entry in the queue */
var entry = B220Util.popupOpenQueue.shift();
var loader1 = null;
var loader2 = null;
var win = null;
if (entry) {
try {
win = entry.parent.open(entry.url, entry.windowName, entry.options);
} catch (e) {
win = null;
}
if (!win) { // window open failed, requeue
B220Util.popupOpenQueue.unshift(entry);
B220Util.popupOpenDelay += B220Util.popupOpenDelayIncrement;
setTimeout(B220Util.dequeuePopup, B220Util.popupOpenDelay);
//console.log("Pop-up open failed: " + entry.windowName + ", new delay=" + B220Util.popupOpenDelay + "ms");
} else { // window open was successful
if (entry.onload) {
loader1 = entry.onload.bind(entry.context);
win.addEventListener("load", loader1, false);
}
loader2 = function(ev) { // remove the load event listeners after loading
win.removeEventListener("load", loader2, false);
if (loader1) {
win.removeEventListener("load", loader1, false);
}
};
win.addEventListener("load", loader2, false);
if (B220Util.popupOpenQueue.length > 0) {
setTimeout(B220Util.dequeuePopup, B220Util.popupOpenDelay);
}
}
}
};

View File

@ -1,97 +1,97 @@
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
Bitstream Vera Fonts Copyright
------------------------------
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and is distributed under the "Bitstream
Vera" names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively. For further information, contact: fonts at gnome dot
org.
Arev Fonts Copyright
------------------------------
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
Bitstream Vera Fonts Copyright
------------------------------
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and is distributed under the "Bitstream
Vera" names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively. For further information, contact: fonts at gnome dot
org.
Arev Fonts Copyright
------------------------------
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
. fr.