1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-04-09 23:18:20 +00:00

Emulator version 0.06:

Implement B5500CardReader peripheral device.
This commit is contained in:
paul.kimpel@digm.com
2013-06-15 12:17:05 +00:00
parent 0563664c73
commit 0071af88c8
17 changed files with 1043 additions and 139 deletions

View File

@@ -62,7 +62,7 @@ function B5500CentralControl() {
/**************************************/
/* Global constants */
B5500CentralControl.version = "0.05";
B5500CentralControl.version = "0.06";
B5500CentralControl.rtcTick = 1000/60; // Real-time clock period, milliseconds
@@ -119,8 +119,8 @@ B5500CentralControl.unitSpecs = {
SPO: {unitIndex: 22, designate: 30, unitClass: B5500SPOUnit},
DKA: {unitIndex: 29, designate: 6, unitClass: B5500DiskUnit},
DKB: {unitIndex: 28, designate: 12, unitClass: B5500DiskUnit},
CRA: {unitIndex: 24, designate: 10, unitClass: null},
CRB: {unitIndex: 23, designate: 14, unitClass: null},
CRA: {unitIndex: 24, designate: 10, unitClass: B5500CardReader},
CRB: {unitIndex: 23, designate: 14, unitClass: B5500CardReader},
CPA: {unitIndex: 25, designate: 10, unitClass: null},
LPA: {unitIndex: 27, designate: 22, unitClass: null},
LPB: {unitIndex: 26, designate: 26, unitClass: null},
@@ -150,7 +150,7 @@ B5500CentralControl.unitSpecs = {
/**************************************/
B5500CentralControl.bindMethod = function(f, context) {
B5500CentralControl.bindMethod = function bindMethod(f, context) {
/* Returns a new function that binds the function "f" to the object "context".
Note that this is a constructor property function, NOT an instance method of
the CC object */
@@ -159,7 +159,7 @@ B5500CentralControl.bindMethod = function(f, context) {
};
/**************************************/
B5500CentralControl.prototype.clear = function() {
B5500CentralControl.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the system and starts the
real-time clock */
@@ -218,7 +218,7 @@ B5500CentralControl.prototype.clear = function() {
};
/**************************************/
B5500CentralControl.prototype.bit = function(word, bit) {
B5500CentralControl.prototype.bit = function bit(word, bit) {
/* Extracts and returns the specified bit from the word */
var e = 47-bit; // word lower power exponent
var p; // bottom portion of word power of 2
@@ -231,7 +231,7 @@ B5500CentralControl.prototype.bit = function(word, bit) {
};
/**************************************/
B5500CentralControl.prototype.bitSet = function(word, bit) {
B5500CentralControl.prototype.bitSet = function bitSet(word, bit) {
/* Sets the specified bit in word and returns the updated word */
var ue = 48-bit; // word upper power exponent
var le = ue-1; // word lower power exponent
@@ -245,7 +245,7 @@ B5500CentralControl.prototype.bitSet = function(word, bit) {
};
/**************************************/
B5500CentralControl.prototype.bitReset = function(word, bit) {
B5500CentralControl.prototype.bitReset = function bitReset(word, bit) {
/* Resets the specified bit in word and returns the updated word */
var ue = 48-bit; // word upper power exponent
var le = ue-1; // word lower power exponent
@@ -258,7 +258,7 @@ B5500CentralControl.prototype.bitReset = function(word, bit) {
};
/**************************************/
B5500CentralControl.prototype.fieldIsolate = function(word, start, width) {
B5500CentralControl.prototype.fieldIsolate = function fieldIsolate(word, start, width) {
/* Extracts a bit field [start:width] from word and returns the field */
var le = 48-start-width; // lower power exponent
var p; // bottom portion of word power of 2
@@ -269,7 +269,7 @@ B5500CentralControl.prototype.fieldIsolate = function(word, start, width) {
};
/**************************************/
B5500CentralControl.prototype.fieldInsert = function(word, start, width, value) {
B5500CentralControl.prototype.fieldInsert = function fieldInsert(word, start, width, value) {
/* Inserts a bit field from the low-order bits of value ([48-width:width])
into word.[start:width] and returns the updated word */
var ue = 48-start; // word upper power exponent
@@ -284,7 +284,7 @@ B5500CentralControl.prototype.fieldInsert = function(word, start, width, value)
};
/**************************************/
B5500CentralControl.prototype.fieldTransfer = function(word, wstart, width, value, vstart) {
B5500CentralControl.prototype.fieldTransfer = function fieldTransfer(word, wstart, width, value, vstart) {
/* Inserts a bit field from value.[vstart:width] into word.[wstart:width] and
returns the updated word */
var ue = 48-wstart; // word upper power exponent
@@ -304,7 +304,7 @@ B5500CentralControl.prototype.fieldTransfer = function(word, wstart, width, valu
};
/**************************************/
B5500CentralControl.prototype.fetch = function(acc) {
B5500CentralControl.prototype.fetch = function fetch(acc) {
/* Called by a requestor module passing accessor object "acc" to fetch a
word from memory. */
var addr = acc.addr;
@@ -348,7 +348,7 @@ B5500CentralControl.prototype.fetch = function(acc) {
};
/**************************************/
B5500CentralControl.prototype.store = function(acc) {
B5500CentralControl.prototype.store = function store(acc) {
/* Called by requestor module passing accessor object "acc" to store a
word into memory. */
var addr = acc.addr;
@@ -392,7 +392,7 @@ B5500CentralControl.prototype.store = function(acc) {
};
/**************************************/
B5500CentralControl.prototype.signalInterrupt = function() {
B5500CentralControl.prototype.signalInterrupt = function signalInterrupt() {
/* Called by all modules to signal that an interrupt has occurred and
to invoke the interrupt prioritization mechanism. This will result in
an updated vector address in the IAR. Can also be called to reprioritize
@@ -430,7 +430,7 @@ B5500CentralControl.prototype.signalInterrupt = function() {
};
/**************************************/
B5500CentralControl.prototype.clearInterrupt = function() {
B5500CentralControl.prototype.clearInterrupt = function clearInterrupt() {
/* Resets an interrupt based on the current setting of this.IAR, then
reprioritizes any remaining interrupts, leaving the new vector address
in this.IAR. */
@@ -555,7 +555,7 @@ B5500CentralControl.prototype.tock = function tock() {
};
/**************************************/
B5500CentralControl.prototype.haltP2 = function() {
B5500CentralControl.prototype.haltP2 = function haltP2() {
/* Called by P1 to halt P2. storeForInterrupt() will set P2BF=0 */
this.HP2F = 1;
@@ -566,7 +566,7 @@ B5500CentralControl.prototype.haltP2 = function() {
};
/**************************************/
B5500CentralControl.prototype.initiateP2 = function() {
B5500CentralControl.prototype.initiateP2 = function initiateP2() {
/* Called by P1 to initiate P2. Assumes that an INCW has been stored at
memory location @10. If P2 is busy or not present, sets the P2 busy
interrupt. Otherwise, loads the INCW into P2's A register and initiates
@@ -583,7 +583,7 @@ B5500CentralControl.prototype.initiateP2 = function() {
};
/**************************************/
B5500CentralControl.prototype.initiateIO = function() {
B5500CentralControl.prototype.initiateIO = function initiateIO() {
/* Selects an I/O unit and initiates an I/O */
if (this.IO1 && this.IO1.REMF && !this.AD1F) {
@@ -605,7 +605,7 @@ B5500CentralControl.prototype.initiateIO = function() {
};
/**************************************/
B5500CentralControl.prototype.interrogateIOChannel = function() {
B5500CentralControl.prototype.interrogateIOChannel = function interrogateIOChannel() {
/* Returns a value as for the processor TIO syllable indicating the first
available and non-busy I/O Unit */
@@ -623,7 +623,7 @@ B5500CentralControl.prototype.interrogateIOChannel = function() {
};
/**************************************/
B5500CentralControl.prototype.interrogateUnitStatus = function() {
B5500CentralControl.prototype.interrogateUnitStatus = function interrogateUnitStatus() {
/* Returns a bitmask as for the processor TUS syllable indicating the
ready status of all peripheral units */
@@ -631,7 +631,7 @@ B5500CentralControl.prototype.interrogateUnitStatus = function() {
};
/**************************************/
B5500CentralControl.prototype.testUnitReady = function(index) {
B5500CentralControl.prototype.testUnitReady = function testUnitReady(index) {
/* Determines whether the unit index "index" is currently in ready status.
Returns 1 if ready, 0 if not ready */
@@ -639,7 +639,7 @@ B5500CentralControl.prototype.testUnitReady = function(index) {
};
/**************************************/
B5500CentralControl.prototype.testUnitBusy = function(index) {
B5500CentralControl.prototype.testUnitBusy = function testUnitBusy(index) {
/* Determines whether the unit index "index" is currently in use by any other
I/O Unit. Returns 1 if busy, 0 if not busy */
@@ -647,7 +647,7 @@ B5500CentralControl.prototype.testUnitBusy = function(index) {
};
/**************************************/
B5500CentralControl.prototype.setUnitBusy = function(index, busy) {
B5500CentralControl.prototype.setUnitBusy = function setUnitBusy(index, busy) {
/* Sets or resets the unit-busy mask bit for unit index "index" */
if (index) {
@@ -657,7 +657,7 @@ B5500CentralControl.prototype.setUnitBusy = function(index, busy) {
};
/**************************************/
B5500CentralControl.prototype.halt = function() {
B5500CentralControl.prototype.halt = function halt() {
/* Halts the processors. Any in-process I/Os are allowed to complete */
if (this.timer) {
@@ -723,10 +723,10 @@ B5500CentralControl.prototype.loadComplete = function loadComplete(dontStart) {
};
/**************************************/
B5500CentralControl.prototype.load = function(dontStart) {
B5500CentralControl.prototype.load = function load(dontStart) {
/* Initiates a Load operation to start the system. If "dontStart" is truthy, then
only the MCP bootstrap is loaded into memory -- P1 is not started */
var boundLoadComplete = (function(that, dontStart) {
var boundLoadComplete = (function boundLoadComplete(that, dontStart) {
return function() {return that.loadComplete(dontStart)}
})(this, dontStart);
@@ -754,7 +754,7 @@ B5500CentralControl.prototype.load = function(dontStart) {
};
/**************************************/
B5500CentralControl.prototype.loadTest = function(buf, loadAddr) {
B5500CentralControl.prototype.loadTest = function loadTest(buf, loadAddr) {
/* Loads a test codestream into memory starting at B5500 word address
"loadAddr" from the ArrayBuffer "buf". Returns the number of B5500
words loaded into memory. Note that when loading an ESPOL "DISK" file,
@@ -809,7 +809,7 @@ B5500CentralControl.prototype.loadTest = function(buf, loadAddr) {
};
/**************************************/
B5500CentralControl.prototype.runTest = function(runAddr) {
B5500CentralControl.prototype.runTest = function runTest(runAddr) {
/* Executes a test program previously loaded by this.loadTest on processor
P1. "runAddr" is the B5500 word address at which execution will begin
(typically 0x10 [octal 20]) */
@@ -822,7 +822,7 @@ B5500CentralControl.prototype.runTest = function(runAddr) {
};
/**************************************/
B5500CentralControl.prototype.configureSystem = function() {
B5500CentralControl.prototype.configureSystem = function configureSystem() {
/* Establishes the hardware module configuration from the
B5500SystemConfiguration module */
var cfg = B5500SystemConfiguration;
@@ -834,7 +834,7 @@ B5500CentralControl.prototype.configureSystem = function() {
var x;
function makeChange(cc, maskBit) {
return function(ready) {
return function statusChange(ready) {
cc.unitStatusMask = (ready ? cc.bitSet(cc.unitStatusMask, maskBit)
: cc.bitReset(cc.unitStatusMask, maskBit));
};
@@ -843,41 +843,41 @@ B5500CentralControl.prototype.configureSystem = function() {
function makeSignal(cc, mnemonic) {
switch (mnemonic) {
case "SPO":
return function() {
return function signalSPO() {
cc.CCI05F = 1;
cc.signalInterrupt();
};
break;
case "LPA":
return function() {
return function signalLPA() {
cc.setUnitBusy(27, 0);
cc.CCI06F = 1;
cc.signalInterrupt();
};
break;
case "LPB":
return function() {
return function signalLPB() {
cc.setUnitBusy(26, 0);
cc.CCI07F = 1;
cc.signalInterrupt();
};
break;
case "DKA":
return function() {
return function signalDKA() {
cc.setUnitBusy(29, 0);
cc.CCI15F = 1;
cc.signalInterrupt();
};
break;
case "DKB":
return function() {
return function signalDKB() {
cc.setUnitBusy(28, 0);
cc.CCI16F = 1;
cc.signalInterrupt();
};
break;
default:
return function() {};
return function signalDefault() {};
break;
}
}
@@ -924,7 +924,7 @@ B5500CentralControl.prototype.configureSystem = function() {
};
/**************************************/
B5500CentralControl.prototype.powerOn = function() {
B5500CentralControl.prototype.powerOn = function powerOn() {
/* Powers up the system and establishes the hardware module configuration.
Redundant power-ons are ignored. */
@@ -935,7 +935,7 @@ B5500CentralControl.prototype.powerOn = function() {
};
/**************************************/
B5500CentralControl.prototype.powerOff = function() {
B5500CentralControl.prototype.powerOff = function powerOff() {
/* Powers down the system and deallocates the hardware modules.
Redundant power-offs are ignored. */
var x;

View File

@@ -63,6 +63,7 @@ function B5500IOUnit(ioUnitID, cc) {
// Establish contexts for asynchronously-called methods
this.boundForkIO = B5500CentralControl.bindMethod(this.forkIO, this);
this.boundFinishGeneric = this.makeFinish(this.finishGeneric);
this.boundFinishGenericRead = this.makeFinish(this.finishGenericRead);
this.boundFinishBusy = this.makeFinish(this.finishBusy);
this.boundFinishDiskRead = this.makeFinish(this.finishDiskRead);
this.boundFinishSPORead = this.makeFinish(this.finishSPORead);
@@ -132,7 +133,7 @@ B5500IOUnit.BCLANSItoBIC = [ // Index by 8-bit BCL-as-ANSI to get 6-b
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C]; // F0-FF
/**************************************/
B5500IOUnit.prototype.clear = function() {
B5500IOUnit.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the I/O Unit state */
this.W = 0; // Memory buffer register
@@ -187,7 +188,7 @@ B5500IOUnit.prototype.clear = function() {
};
/**************************************/
B5500IOUnit.prototype.clearD = function() {
B5500IOUnit.prototype.clearD = function clearD() {
/* Clears the D-register and the exploded field variables used internally */
this.D = 0;
@@ -209,7 +210,7 @@ B5500IOUnit.prototype.clearD = function() {
};
/**************************************/
B5500IOUnit.prototype.fetch = function(addr) {
B5500IOUnit.prototype.fetch = function fetch(addr) {
/* Fetch a word from memory at address "addr" and leave it in the W register.
Returns 1 if a memory access error occurred, 0 if no error */
var acc = this.accessor; // get a local reference to the accessor object
@@ -231,7 +232,7 @@ B5500IOUnit.prototype.fetch = function(addr) {
};
/**************************************/
B5500IOUnit.prototype.store = function(addr) {
B5500IOUnit.prototype.store = function store(addr) {
/* Store a word in memory at address "addr" from the W register.
Returns 1 if a memory access error occurred, 0 if no error */
var acc = this.accessor; // get a local reference to the accessor object
@@ -250,7 +251,7 @@ B5500IOUnit.prototype.store = function(addr) {
};
/**************************************/
B5500IOUnit.prototype.fetchBuffer = function(mode, words) {
B5500IOUnit.prototype.fetchBuffer = function fetchBuffer(mode, words) {
/* Fetches words from memory starting at this.Daddress and coverts the
BIC characters to ANSI or BCLANSI in this.buffer. "mode": 0=BCLANSI, 1=ANSI;
"words": maximum number of words to transfer. At exit, updates this.Daddress
@@ -300,7 +301,7 @@ B5500IOUnit.prototype.fetchBuffer = function(mode, words) {
};
/**************************************/
B5500IOUnit.prototype.fetchBufferWithGM = function(mode, words) {
B5500IOUnit.prototype.fetchBufferWithGM = function fetchBufferWithGM(mode, words) {
/* Fetches words from memory starting at this.Daddress and coverts the
BIC characters to ANSI or BCLANSI in this.buffer. "mode": 0=BCLANSI, 1=ANSI;
"words": maximum number of words to transfer. The transfer can be terminated
@@ -356,7 +357,7 @@ B5500IOUnit.prototype.fetchBufferWithGM = function(mode, words) {
};
/**************************************/
B5500IOUnit.prototype.storeBuffer = function(chars, offset, mode, words) {
B5500IOUnit.prototype.storeBuffer = function storeBuffer(chars, offset, mode, words) {
/* Converts characters in this.buffer from ANSI or BCLANSI to BIC, assembles
them into words, and stores the words into memory starting at this.Daddress.
"chars": the number of characters to store, starting at "offset" in the buffer;
@@ -428,7 +429,7 @@ B5500IOUnit.prototype.storeBuffer = function(chars, offset, mode, words) {
};
/**************************************/
B5500IOUnit.prototype.storeBufferWithGM = function(chars, offset, mode, words) {
B5500IOUnit.prototype.storeBufferWithGM = function storeBufferWithGM(chars, offset, mode, words) {
/* Converts characters in this.buffer from ANSI to BIC, assembles them into
words, and stores the words into memory starting at this.Daddress.
"chars": the number of characters to store, starting at "offset" in the buffer;
@@ -507,7 +508,7 @@ B5500IOUnit.prototype.storeBufferWithGM = function(chars, offset, mode, words) {
};
/**************************************/
B5500IOUnit.prototype.finish = function () {
B5500IOUnit.prototype.finish = function finish() {
/* Called to finish an I/O operation on this I/O Unit. Constructs and stores
the result descriptor, sets the appropriate I/O Finished interrupt in CC */
@@ -553,7 +554,7 @@ B5500IOUnit.prototype.finish = function () {
};
/**************************************/
B5500IOUnit.prototype.makeFinish = function(f) {
B5500IOUnit.prototype.makeFinish = function makeFinish(f) {
/* Utility function to create a closure for I/O finish handlers */
var that = this;
@@ -561,7 +562,7 @@ B5500IOUnit.prototype.makeFinish = function(f) {
};
/**************************************/
B5500IOUnit.prototype.decodeErrorMask = function(errorMask) {
B5500IOUnit.prototype.decodeErrorMask = function decodeErrorMask(errorMask) {
/* Decodes the errorMask returned by the device drivers and ORs it into
the D-register error bits */
@@ -575,7 +576,7 @@ B5500IOUnit.prototype.decodeErrorMask = function(errorMask) {
};
/**************************************/
B5500IOUnit.prototype.finishBusy = function(errorMask, length) {
B5500IOUnit.prototype.finishBusy = function finishBusy(errorMask, length) {
/* Handles a generic I/O finish when no word-count update or input data
transfer is needed, but leaves the unit marked as busy in CC. This is needed
by device operations that have a separate completion signal, such as line
@@ -587,7 +588,7 @@ B5500IOUnit.prototype.finishBusy = function(errorMask, length) {
};
/**************************************/
B5500IOUnit.prototype.finishGeneric = function(errorMask, length) {
B5500IOUnit.prototype.finishGeneric = function finishGeneric(errorMask, length) {
/* Handles a generic I/O finish when no word-count update or input data
transfer is needed. Can also be used to apply common error mask posting
at the end of specialized finish handlers. Note that this turns off the
@@ -599,7 +600,16 @@ B5500IOUnit.prototype.finishGeneric = function(errorMask, length) {
};
/**************************************/
B5500IOUnit.prototype.finishSPORead = function(errorMask, length) {
B5500IOUnit.prototype.finishGenericRead = function finishGenericRead(errorMask, length) {
/* Handles a generic I/O finish when input data transfer, and optionally,
word-count update, is needed. Note that this turns off the busyUnit mask bit in CC */
this.storeBuffer(length, 0, 1, (this.D23F ? this.DwordCount : 0x7FFF));
this.finishGeneric(errorMask, length);
};
/**************************************/
B5500IOUnit.prototype.finishSPORead = function finishSPORead(errorMask, length) {
/* Handles I/O finish for a SPO keyboard input operation */
this.storeBufferWithGM(length, 0, 1, 0x7FFF);
@@ -607,7 +617,7 @@ B5500IOUnit.prototype.finishSPORead = function(errorMask, length) {
};
/**************************************/
B5500IOUnit.prototype.finishDiskRead = function(errorMask, length) {
B5500IOUnit.prototype.finishDiskRead = function finishDiskRead(errorMask, length) {
/* Handles I/O finish for a DFCU data read operation */
var segWords = Math.floor((length+7)/8);
var memWords = (this.D23F ? this.DwordCount : segWords);
@@ -620,7 +630,7 @@ B5500IOUnit.prototype.finishDiskRead = function(errorMask, length) {
};
/**************************************/
B5500IOUnit.prototype.initiateDiskIO = function(u) {
B5500IOUnit.prototype.initiateDiskIO = function initiateDiskIO(u) {
/* Initiates an I/O to the Disk File Control Unit. The disk address is fetched from
the first word of the memory area and converted to binary for the DFCU module. Read
check and interrogate operations are determined from their respective IOD bits. If
@@ -678,7 +688,7 @@ B5500IOUnit.prototype.initiateDiskIO = function(u) {
};
/**************************************/
B5500IOUnit.prototype.initiatePrinterIO = function(u) {
B5500IOUnit.prototype.initiatePrinterIO = function initiatePrinterIO(u) {
/* Initiates an I/O to a Line Printer unit */
var addr = this.Daddress; // initial data transfer address
var cc; // carriage control value to driver
@@ -766,12 +776,22 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
// card #1 reader/punch
case 10:
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
if (this.D24F) { // CRA
u.read(this.boundFinishGenericRead, this.buffer, (this.D21F ? 160 : 80), this.D21F, 0);
} else { // CPA
this.D30F = 1; // >>> temp until CPA implemented <<<
this.finish();
}
break;
// card #2 reader
case 14:
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
if (this.D24F) {
u.read(this.boundFinishGenericRead, this.buffer, (this.D21F ? 160 : 80), this.D21F, 0);
} else {
this.D30F = 1; // can't write to CRB, report as not ready
this.finish();
}
break;
// SPO designate
@@ -812,7 +832,7 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
};
/**************************************/
B5500IOUnit.prototype.initiate = function() {
B5500IOUnit.prototype.initiate = function initiate() {
/* Initiates an I/O operation on this I/O Unit. When P1 executes an IIO instruction,
it calls the CentralControl.initiateIO() function, which selects an idle I/O Unit and
calls this function for that unit. Thus, at entry we are still running on top of the
@@ -842,7 +862,7 @@ B5500IOUnit.prototype.initiate = function() {
};
/**************************************/
B5500IOUnit.prototype.initiateLoad = function(cardLoadSelect, loadComplete) {
B5500IOUnit.prototype.initiateLoad = function initiateLoad(cardLoadSelect, loadComplete) {
/* Initiates a hardware load operation on this I/O unit. "cardLoadSelect" is true
if the load is to come from the card reader, otherwise it will come from sector 1
of DKA EU0. "loadComplete" is called on completion of the I/O.
@@ -850,10 +870,11 @@ B5500IOUnit.prototype.initiateLoad = function(cardLoadSelect, loadComplete) {
pressed and released. Since there is no IOD in memory, we must generate one in the
D register and initiate the I/O intrinsically. Note that if the I/O has an error,
the RD is not stored and the I/O finish interrupt is not set in CC */
var chars;
var index;
var u;
function finishDiskLoad(errorMask, length) {
function finishLoad(errorMask, length) {
var memWords = Math.floor((length+7)/8);
this.storeBuffer(length, 0, this.D21F, memWords);
@@ -870,22 +891,28 @@ B5500IOUnit.prototype.initiateLoad = function(cardLoadSelect, loadComplete) {
this.clearD();
if (cardLoadSelect) {
alert("Card Load Select is not yet implemented");
} else {
this.D = 0x0600009F8010; // unit 6, read, 63 segs, addr @00020
this.Dunit = 6; // 6=DKA
this.D = 0x0A0004800010; // unit 10, read, binary mode, addr @00020
this.Dunit = 10; // 10=CRA
this.D24F = 1; // read
chars = 20*8;
} else {
this.D = 0x0600009F8010; // unit 6, read, alpha mode, 63 segs, addr @00020
this.Dunit = 6; // 6=DKA
this.D21F = 0; // alpha mode
this.LP = 63; // 63 sectors
this.Daddress = 0x10; // memory address @20
this.busyUnit = index = B5500CentralControl.unitIndex[this.D24F & 1][this.Dunit & 0x1F];
if (this.cc.testUnitBusy(index)) {
this.D32F = 1; // set unit busy error
} else if (!this.cc.testUnitReady(index)) {
this.D30F = 1; // set unit not-ready error
} else {
this.cc.setUnitBusy(index, 1);
u = this.cc.unit[index];
u.read(this.makeFinish(finishDiskLoad), this.buffer, 63*240, this.D21F, 1);
}
chars = 63*240;
}
this.D24F = 1; // read
this.Daddress = 0x10; // memory address @20
this.busyUnit = index = B5500CentralControl.unitIndex[this.D24F & 1][this.Dunit & 0x1F];
if (this.cc.testUnitBusy(index)) {
this.D32F = 1; // set unit busy error
} else if (!this.cc.testUnitReady(index)) {
this.D30F = 1; // set unit not-ready error
} else {
this.cc.setUnitBusy(index, 1);
u = this.cc.unit[index];
u.read(this.makeFinish(finishLoad), this.buffer, chars, this.D21F, 1);
}
};

View File

@@ -41,7 +41,7 @@ var B5500SystemConfiguration = {
SPO: true, // SPO keyboard/printer
DKA: true, // Disk File Control A
DKB: false, // Disk File Control B
CRA: false, // Card Reader A
CRA: true, // Card Reader A
CRB: false, // Card Reader B
CPA: false, // Card Punch A
LPA: false, // Line Printer A

99
webUI/B5500CardReader.css Normal file
View File

@@ -0,0 +1,99 @@
/***********************************************************************
* retro-b5500/emulator B5500CardReader.css
************************************************************************
* Copyright (c) 2013, Nigel Williams and Paul Kimpel.
* Licensed under the MIT License, see http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 emulator Card Reader web interface style sheet.
************************************************************************
* 2013-06-09 P.Kimpel
* Original version, from B5500SPOUnit.css.
***********************************************************************/
BODY {
position: relative;
background-color: black;
margin: 4px}
DIV#CRDiv {
position: relative;
background-color: #666;
width: 280px;
height: 112px;
border: 1px solid black;
border-radius: 8px;
padding: 0;
vertical-align: top}
BUTTON.greenButton {
background-color: #060;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.blackButton {
background-color: black;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.redButton {
background-color: #900;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.greenLit {
background-color: green}
BUTTON.redLit {
background-color: #F00}
#CRNotReadyLight {
position: absolute;
top: 8px;
left: 8px}
#CREOFBtn {
position: absolute;
top: 8px;
left: 76px}
#CRStopBtn {
position: absolute;
top: 8px;
left: 144px}
#CRStartBtn {
position: absolute;
top: 8px;
left: 212px;}
#CRFileSelector {
position: absolute;
border: 1px solid white;
top: 56px;
left: 8px;
width: 120px}
#CRProgressBar {
position: absolute;
border: 1px solid white;
top: 84px;
left: 8px;
width: 262px}

View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<head>
<title>B5500 Emulator Card Reader</title>
<meta name="Author" content="Nigel Williams & Paul Kimpel">
<!-- 2013-06-09 Original version, cloned from B5500SPOUnit.html -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500CardReader.css">
</head>
<body>
<div id=CRDiv>
<button id=CRNotReadyLight class="redButton redLit">NOT READY</button>
<button id=CRStartBtn class="greenButton">START</button>
<button id=CREOFBtn class="redButton">EOF</button>
<button id=CRStopBtn class="redButton">STOP</button>
<input id=CRFileSelector type=file size=29>
<progress id=CRProgressBar min=0 max=100 value=0>
</div>
</body>
</html>

398
webUI/B5500CardReader.js Normal file
View File

@@ -0,0 +1,398 @@
/***********************************************************************
* retro-b5500/emulator B5500CardReader.js
************************************************************************
* Copyright (c) 2013, Nigel Williams and Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 Card Reader Peripheral Unit module.
*
* Defines a card reader peripheral unit type.
*
************************************************************************
* 2013-06-05 P.Kimpel
* Original version, from B5500SPOUnit.js.
***********************************************************************/
"use strict";
/**************************************/
function B5500CardReader(mnemonic, unitIndex, designate, statusChange, signal) {
/* Constructor for the CardReader object */
var that = this;
this.mnemonic = mnemonic; // Unit mnemonic
this.unitIndex = unitIndex; // Ready-mask bit number
this.designate = designate; // IOD unit designate number
this.statusChange = statusChange; // external function to call for ready-status change
this.signal = signal; // external function to call for special signals (e.g,. SPO input request)
this.clear();
this.window = window.open("", mnemonic);
if (this.window) {
this.window.close(); // destroy the previously-existing window
this.window = null;
}
this.doc = null;
this.window = window.open("/B5500/webUI/B5500CardReader.html", mnemonic,
"scrollbars=no,resizable,width=200,height=200");
this.window.onload = function() {
that.readerOnload();
};
}
B5500CardReader.prototype.eolRex = /([^\n\r\f]*)((:?\r[\n\f]?)|\n|\f)?/g;
B5500CardReader.prototype.cardsPerMinute = 800;
B5500CardReader.prototype.cardFilter = [ // Filter ASCII character values to valid BIC ones
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, // 00-0F
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, // 10-1F
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x3F,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, // 20-2F
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, // 30-3F
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, // 40-4F
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x3F,0x5D,0x3F,0x3F, // 50-5F
0x3F,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, // 60-6F
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x7B,0x7C,0x7D,0x7E,0x3F]; // 70-7F
/**************************************/
B5500CardReader.prototype.$$ = function $$(e) {
return this.doc.getElementById(e);
};
/**************************************/
B5500CardReader.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the reader unit state */
this.ready = false; // ready status
this.busy = false; // busy status
this.activeIOUnit = 0; // I/O unit currently using this device
this.errorMask = 0; // error mask for finish()
this.finish = null; // external function to call for I/O completion
this.buffer = ""; // Card reader "input hopper"
this.bufLength = 0; // Current input buffer length (characters)
this.bufIndex = 0; // 0-relative offset to next "card" to be read
this.eofArmed = false; // EOF button: armed state
this.stopCount = 0; // stopCount for clearing the input buffer
};
/**************************************/
B5500CardReader.prototype.hasClass = function hasClass(e, name) {
/* returns true if element "e" has class "name" in its class list */
var classes = e.className;
if (!e) {
return false;
} else if (classes == name) {
return true;
} else {
return (classes.search("\\b" + name + "\\b") >= 0);
}
};
/**************************************/
B5500CardReader.prototype.addClass = function addClass(e, name) {
/* Adds a class "name" to the element "e"s class list */
if (!this.hasClass(e, name)) {
e.className += (" " + name);
}
};
/**************************************/
B5500CardReader.prototype.removeClass = function removeClass(e, name) {
/* Removes the class "name" from the element "e"s class list */
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
};
/**************************************/
B5500CardReader.prototype.setReaderReady = function setReaderReady(ready) {
/* Controls the ready-state of the card reader */
this.$$("CRFileSelector").disabled = ready;
this.ready = ready;
if (ready) {
this.statusChange(1);
this.removeClass(this.$$("CRNotReadyLight"), "redLit");
} else {
this.statusChange(0);
this.addClass(this.$$("CRNotReadyLight"), "redLit");
}
};
/**************************************/
B5500CardReader.prototype.armEOF = function armEOF(armed) {
/* Controls the arming/disarming of the EOF signal when starting with
an empty input hopper */
this.eofArmed = armed;
if (armed) {
this.addClass(this.$$("CREOFBtn"), "redLit");
} else {
this.removeClass(this.$$("CREOFBtn"), "redLit");
}
};
/**************************************/
B5500CardReader.prototype.CRStartBtn_onclick = function CRStartBtn_onclick(ev) {
/* Handle the click event for the START button */
var that = this;
if (!this.ready) {
this.stopCount = 0;
if (this.bufIndex < this.bufLength) {
this.setReaderReady(true);
}
}
};
/**************************************/
B5500CardReader.prototype.CRStopBtn_onclick = function CRStopBtn_onclick(ev) {
/* Handle the click event for the STOP button */
if (this.ready) {
this.setReaderReady(false);
} else if (this.eofArmed) {
this.armEOF(false);
} else if (this.bufIndex < this.bufLength) {
if (this.stopCount < 3) {
this.stopCount++;
} else {
if (confirm("Empty the " + this.mnemonic + " input hopper?")) {
this.stopCount = 0;
this.buffer = "";
this.bufLength = 0;
this.bufIndex = 0;
this.$$("CRProgressBar").value = 0;
}
}
}
};
/**************************************/
B5500CardReader.prototype.CREOFBtn_onclick = function CREOFBtn_onclick(ev) {
/* Handle the click event for the EOF button */
this.armEOF(!this.eofArmed);
};
/**************************************/
B5500CardReader.prototype.fileSelector_onChange = function fileSelector_onChange(ev) {
/* Handle the <input type=file> onchange event when a file is selected */
var f = ev.target.files[0];
var reader = new FileReader();
var that = this;
function fileLoader_onLoad(ev) {
/* Handle the onload event for a Text FileReader */
if (that.bufIndex < that.bufLength) {
that.buffer = that.buffer.substring(that.bufIndex) + ev.target.result;
} else {
that.buffer = ev.target.result;
}
that.bufIndex = 0;
that.bufLength = that.buffer.length;
that.$$("CRProgressBar").value = that.bufLength;
that.$$("CRProgressBar").max = that.bufLength;
}
/********************
alert("File selected: " + f.name +
"\nModified " + f.lastModifiedDate +
"\nType=" + f.type + ", Size=" + f.size + " octets");
********************/
reader.onload = fileLoader_onLoad;
reader.readAsText(f);
};
/**************************************/
B5500CardReader.prototype.readCardAlpha = function readCardAlpha(buffer, length) {
/* Reads one card image from the buffer in alpha mode; pads or trims the
image as necessary to the I/O buffer length. Invalid BCL characters are
translated to ASCII "?" and the invalid character bit is set in the errorMask */
var card; // card image
var cardLength; // length of card image
var match; // result of eolRex.exec()
var x; // for loop index
this.eolRex.lastIndex = this.bufIndex;
match = this.eolRex.exec(this.buffer);
if (!match) {
cardLength = 0;
} else {
this.bufIndex += match[0].length;
card = match[1];
cardLength = card.length;
if (length < cardLength) {
cardLength = length;
}
for (x=0; x<cardLength; x++) {
if ((buffer[x] = this.cardFilter[card.charCodeAt(x) & 0x7F]) == 0x3F) { // intentional assignment
this.errorMask |= 0x08;
}
}
}
while (cardLength < length) {
buffer[cardLength++] = 0x20; // pad with spaces
}
};
/**************************************/
B5500CardReader.prototype.readCardBinary = function readCardBinary(buffer, length) {
/* Reads one card image from the buffer in binary mode; pads or trims the
image as necessary to the I/O buffer length. Invalid BCL characters are
translated to ASCII "?", but are not reported in the errorMask */
var card; // card image
var cardLength; // length of card image
var match; // result of eolRex.exec()
var x; // for loop index
this.eolRex.lastIndex = this.bufIndex;
match = this.eolRex.exec(this.buffer);
if (!match) {
cardLength = 0;
} else {
this.bufIndex += match[0].length;
card = match[1];
cardLength = card.length;
if (length < cardLength) {
cardLength = length;
}
for (x=0; x<cardLength; x++) {
buffer[x] = this.cardFilter[card.charCodeAt(x) & 0x7F];
}
}
while (cardLength < length) {
buffer[cardLength++] = 0x30; // pad with ASCII zeroes
}
};
/**************************************/
B5500CardReader.prototype.readerOnload = function readerOnload() {
/* Initializes the reader window and user interface */
var that = this;
var x = (this.mnemonic == "CRA" ? 0 : this.window.outerWidth + 16);
this.doc = this.window.document;
this.doc.title = "retro-B5500 " + this.mnemonic;
this.window.moveTo(x, 0);
this.window.resizeTo(this.window.outerWidth+this.$$("CRDiv").scrollWidth-this.window.innerWidth+8,
this.window.outerHeight+this.$$("CRDiv").scrollHeight-this.window.innerHeight+8);
this.armEOF(false);
this.setReaderReady(false);
this.$$("CRFileSelector").addEventListener("change", function(ev) {
that.fileSelector_onChange(ev);
}, false);
this.$$("CRStartBtn").addEventListener("click", function(ev) {
that.CRStartBtn_onclick(ev);
}, false);
this.$$("CRStopBtn").addEventListener("click", function(ev) {
that.CRStopBtn_onclick(ev);
}, false);
this.$$("CREOFBtn").addEventListener("click", function(ev) {
that.CREOFBtn_onclick(ev);
}, false);
};
/**************************************/
B5500CardReader.prototype.read = function read(finish, buffer, length, mode, control) {
/* Initiates a read operation on the unit. If the reader is not ready and the input
buffer is empty and EOF is armed , returns EOF; otherwise if not ready,
returns Not Ready */
var that = this;
this.errorMask = 0;
if (this.busy) {
finish(0x01, 0); // report unit busy
} else if (!this.ready) {
if (this.eofArmed && this.bufIndex >= this.bufLength) {
this.armEOF(false);
finish(0x24, 0); // report unit EOF + not ready
} else {
finish(0x04, 0); // report unit not ready
}
} else {
this.busy = true;
if (mode == 0) {
this.readCardAlpha(buffer, length);
} else {
this.readCardBinary(buffer, length);
}
if (this.bufIndex < this.bufLength) {
this.$$("CRProgressBar").value = this.bufLength-this.bufIndex;
} else {
this.$$("CRProgressBar").value = 0;
this.buffer = ""; // discard the input buffer
this.bufLength = 0;
this.bufIndex = 0;
this.setReaderReady(false);
}
setTimeout(function() {
that.busy = false;
finish(that.errorMask, length);
}, 60000/this.cardsPerMinute);
}
};
/**************************************/
B5500CardReader.prototype.space = function space(finish, length, control) {
/* Initiates a space operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardReader.prototype.write = function write(finish, buffer, length, mode, control) {
/* Initiates a write operation on the unit */
finish(0x04); // report unit not ready
};
/**************************************/
B5500CardReader.prototype.erase = function erase(finish, length) {
/* Initiates an erase operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardReader.prototype.rewind = function rewind(finish) {
/* Initiates a rewind operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardReader.prototype.readCheck = function readCheck(finish, length, control) {
/* Initiates a read check operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardReader.prototype.readInterrogate = function readInterrogate(finish, control) {
/* Initiates a read interrogate operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardReader.prototype.writeInterrogate = function writeInterrogate(finish, control) {
/* Initiates a write interrogate operation on the unit */
finish(0x04, 0); // report unit not ready
};

View File

@@ -10,6 +10,7 @@
<script src="./B5500DummyUnit.js"></script>
<script src="./B5500SPOUnit.js"></script>
<script src="./B5500DiskUnit.js"></script>
<script src="./B5500CardReader.js"></script>
<script src="../emulator/B5500SystemConfiguration.js"></script>
<script src="../emulator/B5500CentralControl.js"></script>

View File

@@ -27,75 +27,75 @@ function B5500DummyUnit(mnemonic, index, designate, statusChange, signal) {
this.designate = designate; // IOD unit designate number
this.statusChange = statusChange; // external function to call for ready-status change
this.signal = signal; // external function to call for special signals (e.g,. SPO input request)
this.clear();
}
/**************************************/
B5500DummyUnit.prototype.clear = function() {
B5500DummyUnit.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the processor state */
this.ready = false; // ready status
this.busy = false; // busy status
this.activeIOUnit = 0; // I/O unit currently using this device
this.errorMask = 0; // error mask for finish()
this.finish = null; // external function to call for I/O completion
this.buffer = null; //
this.buffer = null; //
};
/**************************************/
B5500DummyUnit.prototype.read = function(finish, buffer, length, mode, control) {
B5500DummyUnit.prototype.read = function read(finish, buffer, length, mode, control) {
/* Initiates a read operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DummyUnit.prototype.space = function(finish, length, control) {
B5500DummyUnit.prototype.space = function space(finish, length, control) {
/* Initiates a space operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DummyUnit.prototype.write = function(finish, buffer, length, mode, control) {
B5500DummyUnit.prototype.write = function write(finish, buffer, length, mode, control) {
/* Initiates a write operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DummyUnit.prototype.erase = function(finish, length) {
B5500DummyUnit.prototype.erase = function erase(finish, length) {
/* Initiates an erase operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DummyUnit.prototype.rewind = function(finish) {
B5500DummyUnit.prototype.rewind = function rewind(finish) {
/* Initiates a rewind operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DummyUnit.prototype.readCheck = function(finish, length, control) {
B5500DummyUnit.prototype.readCheck = function readCheck(finish, length, control) {
/* Initiates a read check operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DummyUnit.prototype.readInterrogate = function(finish, control) {
B5500DummyUnit.prototype.readInterrogate = function readInterrogate(finish, control) {
/* Initiates a read interrogate operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DummyUnit.prototype.writeInterrogate = function (finish, control) {
B5500DummyUnit.prototype.writeInterrogate = function writeInterrogate(finish, control) {
/* Initiates a write interrogate operation on the unit */
finish(0x04, 0); // report unit not ready
};

View File

@@ -1,8 +1,9 @@
<!DOCTYPE html>
<head>
<title>B5500 Emulator SPO Unit</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Nigel Williams & Paul Kimpel">
<!-- 2012-12-16 Original version, cloned from SPO prototype script -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500SPOUnit.css">

View File

@@ -36,12 +36,13 @@ function B5500SPOUnit(mnemonic, unitIndex, designate, statusChange, signal) {
this.printChar.that = this;
this.outputChar.that = this;
this.window = window.open("", "SPOWin");
this.window = window.open("", mnemonic);
if (this.window) {
this.window.close(); // destroy the previously-existing window
this.window = null;
}
this.window = window.open("/B5500/webUI/B5500SPOUnit.html", "SPOWin", "scrollbars,resizable,width=600,height=500");
this.doc = null;
this.window = window.open("/B5500/webUI/B5500SPOUnit.html", mnemonic, "scrollbars,resizable,width=600,height=500");
this.window.onload = function() {
that.spoOnload();
};
@@ -54,7 +55,7 @@ B5500SPOUnit.prototype.spoRemote = 2;
B5500SPOUnit.prototype.spoInput = 3;
B5500SPOUnit.prototype.spoOutput = 4;
B5500SPOUnit.prototype.keyFilter = [ // Filter keyCode values to valid B5500 ones
B5500SPOUnit.prototype.keyFilter = [ // Filter keyCode values to valid BIC ones
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, // 00-0F
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, // 10-1F
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x3F,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, // 20-2F
@@ -65,11 +66,12 @@ B5500SPOUnit.prototype.keyFilter = [ // Filter keyCode values to vali
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x7B,0x7C,0x7D,0x7E,0x3F]; // 70-7F
/**************************************/
B5500SPOUnit.prototype.$$ = function(e) {
return this.doc.getElementById(e)};
B5500SPOUnit.prototype.$$ = function $$(e) {
return this.doc.getElementById(e);
};
/**************************************/
B5500SPOUnit.prototype.clear = function() {
B5500SPOUnit.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the SPO unit state */
this.ready = false; // ready status
@@ -89,7 +91,7 @@ B5500SPOUnit.prototype.clear = function() {
};
/**************************************/
B5500SPOUnit.prototype.hasClass = function(e, name) {
B5500SPOUnit.prototype.hasClass = function hasClass(e, name) {
/* returns true if element "e" has class "name" in its class list */
var classes = e.className;
@@ -103,7 +105,7 @@ B5500SPOUnit.prototype.hasClass = function(e, name) {
};
/**************************************/
B5500SPOUnit.prototype.addClass = function(e, name) {
B5500SPOUnit.prototype.addClass = function addClass(e, name) {
/* Adds a class "name" to the element "e"s class list */
if (!this.hasClass(e, name)) {
@@ -112,14 +114,14 @@ B5500SPOUnit.prototype.addClass = function(e, name) {
};
/**************************************/
B5500SPOUnit.prototype.removeClass = function(e, name) {
B5500SPOUnit.prototype.removeClass = function removeClass(e, name) {
/* Removes the class "name" from the element "e"s class list */
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
};
/**************************************/
B5500SPOUnit.prototype.setNotReady = function() {
B5500SPOUnit.prototype.setNotReady = function setNotReady() {
/* Sets the status of the SPO to Not Ready */
if (this.spoState == this.spoLocal) {
@@ -130,7 +132,7 @@ B5500SPOUnit.prototype.setNotReady = function() {
};
/**************************************/
B5500SPOUnit.prototype.setReady = function() {
B5500SPOUnit.prototype.setReady = function setReady() {
/* Sets the status of the SPO to Ready */
if (this.spoState == this.spoNotReady) {
@@ -140,7 +142,7 @@ B5500SPOUnit.prototype.setReady = function() {
};
/**************************************/
B5500SPOUnit.prototype.setLocal = function() {
B5500SPOUnit.prototype.setLocal = function setLocal() {
/* Sets the status of the SPO to Local */
if (this.spoState == this.spoRemote) {
@@ -160,7 +162,7 @@ B5500SPOUnit.prototype.setLocal = function() {
};
/**************************************/
B5500SPOUnit.prototype.setRemote = function() {
B5500SPOUnit.prototype.setRemote = function setRemote() {
/* Sets the status of the SPO to Remote */
if (this.spoState == this.spoLocal) {
@@ -172,7 +174,7 @@ B5500SPOUnit.prototype.setRemote = function() {
};
/**************************************/
B5500SPOUnit.prototype.appendEmptyLine = function() {
B5500SPOUnit.prototype.appendEmptyLine = function appendEmptyLine() {
/* Removes excess lines already printed, then appends a new <pre> element
to the <iframe>, creating an empty text node inside the new element */
var count = this.paper.childNodes.length;
@@ -259,7 +261,7 @@ B5500SPOUnit.prototype.outputChar = function outputChar() {
};
/**************************************/
B5500SPOUnit.prototype.terminateInput = function() {
B5500SPOUnit.prototype.terminateInput = function terminateInput() {
/* Handles the End of Message event. Turns off then Input Request lamp, then
calls outputChar(), which will find bufIndex==bufLength, output a new-line,
set the state to Remote, and call finish() for us. Slick, eh? */
@@ -273,7 +275,7 @@ B5500SPOUnit.prototype.terminateInput = function() {
};
/**************************************/
B5500SPOUnit.prototype.cancelInput = function() {
B5500SPOUnit.prototype.cancelInput = function cancelInput() {
/* Handles the Error message event. This is identical to terminateInput(),
but it also sets a parity error so the input message will be rejected */
@@ -287,7 +289,7 @@ B5500SPOUnit.prototype.cancelInput = function() {
};
/**************************************/
B5500SPOUnit.prototype.keyPress = function(ev) {
B5500SPOUnit.prototype.keyPress = function keyPress(ev) {
/* Handles keyboard character events. Depending on the state of the unit,
either buffers the character for transmission to the I/O Unit, simply echos
it to the printer, or ignores it altogether */
@@ -334,7 +336,7 @@ B5500SPOUnit.prototype.keyPress = function(ev) {
};
/**************************************/
B5500SPOUnit.prototype.keyDown = function(ev) {
B5500SPOUnit.prototype.keyDown = function keyDown(ev) {
/* Handles key-down events to capture ESC, BS, and Enter keystrokes */
var that = this;
var c = ev.keyCode;
@@ -392,7 +394,7 @@ B5500SPOUnit.prototype.keyDown = function(ev) {
};
/**************************************/
B5500SPOUnit.prototype.printText = function(msg, finish) {
B5500SPOUnit.prototype.printText = function printText(msg, finish) {
/* Utility function to convert a string to a Typed Array buffer and queue
it for printing. This is intended only for printing an initialization message
in Local state */
@@ -413,12 +415,13 @@ B5500SPOUnit.prototype.printText = function(msg, finish) {
};
/**************************************/
B5500SPOUnit.prototype.spoOnload = function() {
B5500SPOUnit.prototype.spoOnload = function spoOnload() {
/* Initializes the SPO window and user interface */
var that = this;
var x;
this.doc = this.window.document;
this.doc.title = "retro-B5500 " + this.mnemonic;
this.paper = this.$$("SPOUT").contentDocument.body;
this.$$("SPOUT").contentDocument.head.innerHTML += "<style>" +
"BODY {background-color: #FFE} " +
@@ -427,7 +430,7 @@ B5500SPOUnit.prototype.spoOnload = function() {
this.window.resizeTo(this.window.outerWidth+this.$$("SPODiv").scrollWidth-this.window.innerWidth+8,
this.window.outerHeight+this.$$("SPODiv").scrollHeight-this.window.innerHeight+8);
this.window.moveTo(0/*screen.availWidth-this.window.outerWidth-8*/, screen.availHeight-this.window.outerHeight-8);
this.window.moveTo(0, screen.availHeight-this.window.outerHeight);
this.window.focus();
this.$$("SPORemoteBtn").onclick = function() {
@@ -479,7 +482,7 @@ B5500SPOUnit.prototype.spoOnload = function() {
};
/**************************************/
B5500SPOUnit.prototype.read = function(finish, buffer, length, mode, control) {
B5500SPOUnit.prototype.read = function read(finish, buffer, length, mode, control) {
/* Initiates a read operation on the unit */
this.errorMask = 0;
@@ -506,14 +509,14 @@ B5500SPOUnit.prototype.read = function(finish, buffer, length, mode, control) {
};
/**************************************/
B5500SPOUnit.prototype.space = function(finish, length, control) {
B5500SPOUnit.prototype.space = function space(finish, length, control) {
/* Initiates a space operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500SPOUnit.prototype.write = function(finish, buffer, length, mode, control) {
B5500SPOUnit.prototype.write = function write(finish, buffer, length, mode, control) {
/* Initiates a write operation on the unit */
this.errorMask = 0;
@@ -540,35 +543,35 @@ B5500SPOUnit.prototype.write = function(finish, buffer, length, mode, control) {
};
/**************************************/
B5500SPOUnit.prototype.erase = function(finish, length) {
B5500SPOUnit.prototype.erase = function erase(finish, length) {
/* Initiates an erase operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500SPOUnit.prototype.rewind = function(finish) {
B5500SPOUnit.prototype.rewind = function rewind(finish) {
/* Initiates a rewind operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500SPOUnit.prototype.readCheck = function(finish, length, control) {
B5500SPOUnit.prototype.readCheck = function readCheck(finish, length, control) {
/* Initiates a read check operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500SPOUnit.prototype.readInterrogate = function(finish, control) {
B5500SPOUnit.prototype.readInterrogate = function readInterrogate(finish, control) {
/* Initiates a read interrogate operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500SPOUnit.prototype.writeInterrogate = function (finish, control) {
B5500SPOUnit.prototype.writeInterrogate = function writeInterrogate(finish, control) {
/* Initiates a write interrogate operation on the unit */
finish(0x04, 0); // report unit not ready

View File

@@ -10,6 +10,7 @@
<script src="/B5500/webUI/B5500DummyUnit.js"></script>
<script src="/B5500/webUI/B5500SPOUnit.js"></script>
<script src="/B5500/webUI/B5500DiskUnit.js"></script>
<script src="./B5500CardReader.js"></script>
<script src="/B5500/emulator/B5500SystemConfiguration.js"></script>
<script src="/B5500/emulator/B5500CentralControl.js"></script>

View File

@@ -0,0 +1,344 @@
<!DOCTYPE html>
<head>
<title>B5500 Card Reader Prototype</title>
<meta name="Author" content="Paul Kimpel">
<!-- 2013-06-08 Original version, cloned from tools/B5500LibMaintDecoder.html -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<style>
BUTTON.greenButton {
background-color: #060;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.blackButton {
background-color: black;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.redButton {
background-color: #900;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.greenLit {
background-color: green}
BUTTON.redLit {
background-color: #F00}
#CardReaderPanel {
position: relative;
background-color: #666;
width: 280px;
height: 112px;
border: 1px solid black;
border-radius: 8px;
padding: 0;
vertical-align: top}
#CRNotReadyLight {
position: absolute;
top: 8px;
left: 8px}
#CREOFBtn {
position: absolute;
top: 8px;
left: 76px}
#CRStopBtn {
position: absolute;
top: 8px;
left: 144px}
#CRStartBtn {
position: absolute;
top: 8px;
left: 212px;}
#CRFileSelector {
position: absolute;
top: 56px;
left: 8px;
width: 120px}
#CRProgressBar {
position: absolute;
top: 84px;
left: 8px;
width: 262px}
</style>
<script>
"use strict";
window.onload = function() {
var buffer = "";
var bufferLength = 0;
var bufferOffset = 0;
var eofArmed = 0;
var panel = $$("TextPanel");
var eolRex = /([^\n\r\f]*)((:?\r[\n\f]?)|\n|\f)?/g;
var blankCard = " "; // 80 spaces
var cardsPerMinute = 800;
var readerState = 0;
var readerNotReady = 0;
var readerReady = 1;
function $$(id) {
return document.getElementById(id);
}
function hasClass(e, name) {
/* returns true if element "e" has class "name" in its class list */
var classes = e.className;
if (!e) {
return false;
} else if (classes == name) {
return true;
} else {
return (classes.search("\\b" + name + "\\b") >= 0);
}
}
function addClass(e, name) {
/* Adds a class "name" to the element "e"s class list */
if (!hasClass(e, name)) {
e.className += (" " + name);
}
}
function removeClass(e, name) {
/* Removes the class "name" from the element "e"s class list */
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
}
function appendLine(panel, text) {
/* Appends "text"+NL as a new text node to the panel DOM element */
var e = document.createTextNode(text + "\n");
panel.appendChild(e);
}
function clearPanel(panel) {
/* Clears the text panel */
var kid;
while (kid = panel.firstChild) {
panel.removeChild(kid);
}
}
function setReaderReady(ready) {
/* Controls the ready-state of the card reader */
$$("CRFileSelector").disabled = ready;
if (ready) {
readerState = readerReady;
removeClass($$("CRNotReadyLight"), "redLit");
} else {
readerState = readerNotReady;
addClass($$("CRNotReadyLight"), "redLit");
}
}
function armEOF(armed) {
/* Controls the arming/disarming of the EOF signal when starting with
an empty input hopper */
if (armed) {
eofArmed = 1;
addClass($$("CREOFBtn"), "redLit");
} else {
eofArmed = 0;
removeClass($$("CREOFBtn"), "redLit");
}
}
function readACard(ev) {
/* Reads one card image from the buffer, pads or trims the image as
necessary to 80 columns, and displays it */
var bx = bufferOffset;
var card;
var cardLength;
var match;
if (bx >= bufferLength) {
setReaderReady(false);
$$("CRProgressBar").value = 0;
} else {
eolRex.lastIndex = bx;
match = eolRex.exec(buffer);
if (!match) {
card = blankCard;
} else {
bx += match[0].length;
card = match[1];
cardLength = card.length;
if (cardLength < 80) {
card += blankCard.substring(0, 80-cardLength);
} else if (cardLength > 80) {
card = card.substring(0, 80);
}
}
$$("CRProgressBar").value = bufferLength-bx;
appendLine(panel, card);
if (readerState == readerReady) {
setTimeout(readACard, 60000/cardsPerMinute);
}
}
bufferOffset = bx;
}
function CRStartBtn_onclick(ev) {
/* Handle the click event for the START button */
if (readerState != readerReady) {
if (bufferOffset >= bufferLength) {
//alert("Empty hopper.");
if (eofArmed) {
appendLine(panel, "\\\\\\\\\\ [EOF] /////");
armEOF(false);
}
} else {
setReaderReady(true);
setTimeout(readACard, 1000); // delay until the reader can come up to speed...
}
}
}
function CRStopBtn_onclick(ev) {
/* Handle the click event for the STOP button */
if (readerState == readerNotReady) {
armEOF(false);
} else if (readerState == readerReady) {
setReaderReady(false);
}
}
function CREOFBtn_onclick(ev) {
/* Handle the click event for the EOF button */
armEOF(!eofArmed);
}
function fileLoader_onLoad(ev) {
/* Handle the onload event for a Text FileReader */
if (bufferOffset < bufferLength) {
buffer = buffer.substring(bufferOffset);
} else {
clearPanel(panel);
buffer = "";
}
buffer += ev.target.result;
bufferOffset = 0;
bufferLength = buffer.length;
$$("CRProgressBar").value = buffer.length;
$$("CRProgressBar").max = buffer.length;
}
function fileSelector_onChange(ev) {
/* Handle the <input type=file> onchange event when a file is selected */
var f = ev.target.files[0];
var reader = new FileReader();
/********************
alert("File selected: " + f.name +
"\nModified " + f.lastModifiedDate +
"\nType=" + f.type + ", Size=" + f.size + " octets");
********************/
reader.onload = fileLoader_onLoad;
reader.readAsText(f);
}
function checkBrowser() {
/* Checks whether this browser can support the necessary stuff */
var missing = "";
if (!window.File) {missing += ", File"}
if (!window.FileReader) {missing += ", FileReader"}
if (!window.FileList) {missing += ", FileList"}
if (!window.Blob) {missing += ", Blob"}
if (!window.ArrayBuffer) {missing += ", ArrayBuffer"}
if (!window.DataView) {missing += ", DataView"}
if (missing.length == 0) {
return false;
} else {
alert("No can do... your browser does not support the following features:\n" + missing.substring(2));
return true;
}
}
/* Start of window.onload() */
if (checkBrowser()) {
return;
}
armEOF(false);
setReaderReady(false);
$$("CRFileSelector").addEventListener("change", fileSelector_onChange, false);
$$("CRStartBtn").addEventListener("click", CRStartBtn_onclick, false);
$$("CRStopBtn").addEventListener("click", CRStopBtn_onclick, false);
$$("CREOFBtn").addEventListener("click", CREOFBtn_onclick, false);
}
</script>
</head>
<body>
<div>
retro-B5500 Card Reader Prototype
</div>
<div id=CardReaderPanel>
<button id=CRNotReadyLight class="redButton redLit">NOT READY</button>
<button id=CRStartBtn class="greenButton">START</button>
<button id=CREOFBtn class="redButton">EOF</button>
<button id=CRStopBtn class="redButton">STOP</button>
<input id=CRFileSelector type=file size=29>
<progress id=CRProgressBar min=0 max=100 value=0>
</div>
<pre id=TextPanel>
</pre>
</body>
</html>

BIN
webUI/retro-Button-Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

BIN
webUI/retro-Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

View File

@@ -7,14 +7,15 @@
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500DistributionAndDisplay.css">
<script src="./B5500DummyUnit.js"></script>
<script src="./B5500SPOUnit.js"></script>
<script src="./B5500DiskUnit.js"></script>
<script src="../B5500DummyUnit.js"></script>
<script src="../B5500SPOUnit.js"></script>
<script src="../B5500DiskUnit.js"></script>
<script src="../B5500CardReader.js"></script>
<script src="../emulator/emulator/B5500SystemConfiguration.js"></script>
<script src="../emulator/emulator/B5500CentralControl.js"></script>
<script src="../emulator/emulator/B5500Processor.js"></script>
<script src="../emulator/emulator/B5500IOUnit.js"></script>
<script src="../../emulator/emulator/B5500SystemConfiguration.js"></script>
<script src="../../emulator/emulator/B5500CentralControl.js"></script>
<script src="../../emulator/emulator/B5500Processor.js"></script>
<script src="../../emulator/emulator/B5500IOUnit.js"></script>
<script>
"use strict";

View File

@@ -7,14 +7,15 @@
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500DistributionAndDisplay.css">
<script src="./B5500DummyUnit.js"></script>
<script src="./B5500SPOUnit.js"></script>
<script src="./B5500DiskUnit.js"></script>
<script src="../B5500DummyUnit.js"></script>
<script src="../B5500SPOUnit.js"></script>
<script src="../B5500DiskUnit.js"></script>
<script src="../B5500CardReader.js"></script>
<script src="../emulator/emulator/B5500SystemConfiguration.js"></script>
<script src="../emulator/emulator/B5500CentralControl.js"></script>
<script src="../emulator/emulator/B5500Processor.js"></script>
<script src="../emulator/emulator/B5500IOUnit.js"></script>
<script src="../../emulator/emulator/B5500SystemConfiguration.js"></script>
<script src="../../emulator/emulator/B5500CentralControl.js"></script>
<script src="../../emulator/emulator/B5500Processor.js"></script>
<script src="../../emulator/emulator/B5500IOUnit.js"></script>
<script>
"use strict";

View File

@@ -8,6 +8,8 @@
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500DistributionAndDisplay.css">
<script src="../B5500SPOUnit.js"></script>
<script src="../B5500DiskUnit.js"></script>
<script src="../B5500CardReader.js"></script>
<script src="../../emulator/B5500SystemConfiguration.js"></script>
<script src="../../emulator/B5500CentralControl.js"></script>
@@ -40,7 +42,7 @@ function testIt(e) {
cc.P1.step();
cc.P1.step();
cc.P1.step();
alert("Test completed");
}