mirror of
https://github.com/pkimpel/retro-b5500.git
synced 2026-04-18 10:06:01 +00:00
1. Commit version 0.03 of emulator and tools: this version successfully performs a hardware load from the disk and initiates the MCP.
2. Redesign B5500Console.html to support the Power On, Power Off, Halt, and Load buttons, along with a primitive mechanism to drive the Normal/Control lights. 3. Implement relative URLs for the <script> elements. This is a work in progress. 4. Commit Nigel's fix for the annoying problem with Firefox where typing "/" on the SPO brings up a QuickFind dialog. 5. Commit Mark XIII DCMCP transcription as of 2013-03-20. 6. Move B5500ColdLoader and KERNEL.DISK under webUI directory tree.
This commit is contained in:
@@ -22592,3 +22592,98 @@ EOF: T~0;% 37297000
|
||||
EOF2: 37297500
|
||||
DISKADDRESS~T;% 37298000
|
||||
END DISKADDRESS;% 37299000
|
||||
PROCEDURE SETNOTINUSE(U,RWL); VALUE U,RWL; REAL U,RWL; 37302000
|
||||
BEGIN REAL I,J; 37303000
|
||||
IF U<16 THEN P(WAITIO(@4200000000,@377,U),DEL); 37303200
|
||||
SLEEP([TOGLE],STATUSMASK); 37304000
|
||||
RRRMECH~((I~TWO(U)) AND SAVEWORD) OR ((I~NOT I) AND RRRMECH);% 37305000
|
||||
READY~READY AND I;% 37306000
|
||||
IF RWL THEN 37312000
|
||||
BEGIN 37313000
|
||||
STREAM(S~[TINU[U]],M~MULTITABLE[U],F~LABELTABLE[U], 37314000
|
||||
N~IF U<16 THEN PRNTABLE[U].[30:18] ELSE 0, 37314100
|
||||
T:=MULTITABLE[U]=0, TT:=U GEQ 16, D:=J:=SPACE(10)); 37314200
|
||||
BEGIN SI~S; SI~SI+5; DS~LIT "#"; DS~3 CHR;% 37315000
|
||||
DS~6 LIT " RW/L "; SI~LOC M; SI~SI+1; 37316000
|
||||
DS~7 CHR; DS~LIT " "; SI~SI+1; DS~7 CHR; 37316100
|
||||
T(M~DI;DI~DI-15;DS~7FILL;DI~M); TT(JUMP 37316200
|
||||
OUT TO LA); DS~LIT "("; DS~5 DEC; DS~LIT")"; 37316300
|
||||
LA: DS~LIT "~"; 37316400
|
||||
END;% 37317000
|
||||
SPOUT(J); 37318000
|
||||
LABELTABLE[U]~@214; 37318100
|
||||
END ELSE LABELTABLE[U]~@114; 37319000
|
||||
MULTITABLE[U]~RDCTABLE[U]~0; 37319010
|
||||
IF U<16 THEN PRNTABLE[U]~0 ; 37319020
|
||||
END SETNOTINUSE; 37319100
|
||||
PROCEDURE BLASTQ(U); 37320000
|
||||
VALUE U; REAL U; 37321000
|
||||
BEGIN 37322000
|
||||
REAL I,X; 37323000
|
||||
BOOLEAN SUBROUTINE CHECKIO; 37323100
|
||||
BEGIN 37323200
|
||||
CHECKIO:=(I:=UNIT[U]).[5:8]!0 OR (I.[14:1] AND I.[13:5]!@31); 37323300
|
||||
END; 37323400
|
||||
IF CHECKIO THEN COMPLEXSLEEP(NOT CHECKIO); 37324000
|
||||
IF I.[16:1] THEN % SKIP I/O IN PROCESS 37326000
|
||||
BEGIN I:=NFLAG(LOCATQUE[X:=I.[FF]]); 37327000
|
||||
LOCATQUE[X].[FF]:=@77777; 37328000
|
||||
UNIT[U].[CF]:=X; 37329000
|
||||
END ELSE 37330000
|
||||
UNIT[U].[5:43]:=(NOT 0).[18:30]; 37331000
|
||||
WHILE (I:=I.[FF])!@77777 DO 37332000
|
||||
BEGIN RETURNIOSPACE(I); 37333000
|
||||
I:=NFLAG(LOCATQUE[I]); 37334000
|
||||
END; 37335000
|
||||
END BLASTQ; 37336000
|
||||
PROCEDURE BUILDLABEL(LABLE,MID,FID,REEL,CDATE,CYCLE,PFACT,PTN,BLKODE,% 37337000
|
||||
BSIZE,RSIZE);% 37338000
|
||||
VALUE LABLE,MID,FID,REEL,CDATE,CYCLE,PFACT,PTN,BLKODE,37339000
|
||||
BSIZE,RSIZE;% 37340000
|
||||
ARRAY LABLE[*];% 37341000
|
||||
REAL MID,FID,REEL,CDATE,CYCLE,PFACT,PTN,BLKODE,% 37342000
|
||||
BSIZE,RSIZE;% 37343000
|
||||
BEGIN;STREAM(D~[PFACT]); BEGIN SI~D; SI~SI+5; DS~3 OCT END;% 37344000
|
||||
PFACT~CALCULATEPURGE(PFACT);% 37345000
|
||||
STREAM(S~M[MID],LABLE);% 37346000
|
||||
BEGIN DS~8 LIT " LABEL "; SI~S; DS~2 WDS;% 37347000
|
||||
DS~3 DEC; DS~5 DEC; DS~2 DEC; SI~SI+3; DS~5 CHR;% 37348000
|
||||
DS~14 LIT "0"; DS~5 DEC; SI~SI+7; DS~CHR;% 37349000
|
||||
DS~5 DEC; DS~5 DEC; DS~11 LIT "0"% 37350000
|
||||
END;% 37351000
|
||||
IF (RSIZE~LABLE.[8:10])>10 THEN% 37352000
|
||||
STREAM(J~JARROW[P1MIX],D~[LABLE[10]]);% 37353000
|
||||
BEGIN SI~J; SI~SI+1; DS~LIT " "; DS~7 CHR;% 37354000
|
||||
SI~SI+1; DS~LIT "/"; DS~7 CHR; 12(DS~2 LIT " ");% 37355000
|
||||
END END GUILDLABEL;% 37356000
|
||||
$ SET OMIT = PACKETS 37356999
|
||||
$ SET OMIT = NOT(PACKETS) 37357299
|
||||
PROCEDURE FILEMESSAGE(I,K,M,F,R,D,C,TYPE); 37357300
|
||||
VALUE I,K,M,F,R,D,C,TYPE; 37357400
|
||||
REAL I,K,M,F,R,D,C,TYPE; 37357500
|
||||
$ POP OMIT 37357501
|
||||
BEGIN REAL Z,L;% 37359000
|
||||
L~SPACE(12);% 37360000
|
||||
STREAM(Z:I~[I],J~[JAR[P1MIX,*]],P1MIX,L); 37361000
|
||||
BEGIN SI~I; 37362000
|
||||
IF SC="+" THEN BEGIN TALLY~1; DS~LIT "-"; SI~SI+1 END ELSE% 37363000
|
||||
BEGIN SI~SI+1; IF SC!"#" THEN DS~LIT " " END;% 37364000
|
||||
DS~7 CHR; DS~LIT " "; L~DI;% 37365000
|
||||
2(DI~LOC Z; IF 8 SC!DC THEN BEGIN DI~L; SI~SI-7; DS~7 CHR;% 37366000
|
||||
DS~LIT " "; L~DI END);% 37367000
|
||||
DI~L; SI~SI+1; DS~7 CHR; DS~LIT " "; L~DI;% 37368000
|
||||
3(DI~LOC Z; IF 8 SC!DC THEN BEGIN DI~L; SI~SI-8; DS~7 DEC; 37369000
|
||||
L~DI; DI~DI-7; DS~6 FILL; 37370000
|
||||
DI~L; DS~LIT " "; L~DI; 37371000
|
||||
END); 37372000
|
||||
DI~L; DS~SI-1; DS~LIT ":";% 37375000
|
||||
Z~TALLY; SI~LOC Z; SI~SI+7;% 37376000
|
||||
IF SC="0" THEN BEGIN SI~J; SI~SI+1; DS~7 CHR; DS~LIT "/";% 37377000
|
||||
SI~SI+1; DS~7 CHR; DS~LIT "=";% 37378000
|
||||
SI~LOC P1MIX; DS~2 DEC; 37379000
|
||||
L~DI; DI~DI-2; DS~FILL; DI~L END; 37379500
|
||||
DS~LIT "~";% 37380000
|
||||
END;% 37381000
|
||||
IF P THEN BEGIN TERMINATE(P1MIX); TERMINALMESSAGE(-L) END;% 37382000
|
||||
SPOUTER(L,0,TYPE); 37383000
|
||||
END FILEMESS;% 37384000
|
||||
|
||||
@@ -46,14 +46,16 @@ function B5500CentralControl() {
|
||||
this.unitBusyMask = 0; // Peripheral unit busy-status bitmask
|
||||
|
||||
this.PB1L = 0; // 0=> PA is P1, 1=> PB is P1
|
||||
this.inhCCI03F = 0; // 0=> allow timer interrupts; 1=> inhibit 'em
|
||||
this.cardLoadSelect = 0; // 0=> load from disk/drum; 1=> load from cards
|
||||
|
||||
this.nextTimeStamp = 0; // Next actual Date.getTime() for timer tick
|
||||
this.timer = null; // Reference to the RTC setTimeout id.
|
||||
this.loadTimer = null; // Reference to the load setTimeout id.
|
||||
|
||||
this.tock.that = this; // Establish contexts for when called from setTimeout().
|
||||
this.loadComplete.that = this;
|
||||
// Establish contexts for asynchronously-called methods
|
||||
this.boundTock = B5500CentralControl.bindMethod(this.tock, this);
|
||||
this.boundLoadComplete = B5500CentralControl.bindMethod(this.loadComplete, this);
|
||||
|
||||
this.clear(); // Create and initialize the Central Control state
|
||||
}
|
||||
@@ -61,7 +63,7 @@ function B5500CentralControl() {
|
||||
/**************************************/
|
||||
/* Global constants */
|
||||
|
||||
B5500CentralControl.version = "0.02";
|
||||
B5500CentralControl.version = "0.03";
|
||||
|
||||
B5500CentralControl.rtcTick = 1000/60; // Real-time clock period, milliseconds
|
||||
|
||||
@@ -148,6 +150,15 @@ B5500CentralControl.unitSpecs = {
|
||||
MTT: {unitIndex: 32, designate: 31, unitClass: null}};
|
||||
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.bindMethod = function(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 */
|
||||
|
||||
return (function() {f.apply(context, arguments)});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.clear = function() {
|
||||
/* Initializes (and if necessary, creates) the system and starts the
|
||||
@@ -155,11 +166,9 @@ B5500CentralControl.prototype.clear = function() {
|
||||
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
|
||||
this.nextTimeStamp = new Date().getTime() + B5500CentralControl.rtcTick;
|
||||
this.timer = setTimeout(this.tock, B5500CentralControl.rtcTick);
|
||||
|
||||
this.IAR = 0; // Interrupt address register
|
||||
this.TM = 0; // Real-time clock (6 bits, 60 ticks per second)
|
||||
|
||||
@@ -531,20 +540,19 @@ B5500CentralControl.prototype.clearInterrupt = function() {
|
||||
B5500CentralControl.prototype.tock = function tock() {
|
||||
/* Handles the 1/60th second real-time clock tick */
|
||||
var interval; // milliseconds to next tick
|
||||
var that = tock.that; // capture the current closure context
|
||||
var thisTime = new Date().getTime();
|
||||
|
||||
if (that.TM < 63) {
|
||||
that.TM++;
|
||||
if (this.TM < 63) {
|
||||
this.TM++;
|
||||
} else {
|
||||
that.TM = 0;
|
||||
/********** INHIBIT FOR NOW **********
|
||||
that.CCI03F = 1; // set timer interrupt
|
||||
that.signalInterrupt();
|
||||
*************************************/
|
||||
this.TM = 0;
|
||||
if (!this.inhCCI03F) {
|
||||
this.CCI03F = 1; // set timer interrupt
|
||||
this.signalInterrupt();
|
||||
}
|
||||
}
|
||||
interval = (that.nextTimeStamp += B5500CentralControl.rtcTick) - thisTime;
|
||||
that.timer = setTimeout(that.tock, (interval < 0 ? 1 : interval));
|
||||
interval = (this.nextTimeStamp += B5500CentralControl.rtcTick) - thisTime;
|
||||
this.timer = setTimeout(this.boundTock, (interval < 0 ? 1 : interval));
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -653,6 +661,15 @@ B5500CentralControl.prototype.setUnitBusy = function(index, busy) {
|
||||
B5500CentralControl.prototype.halt = function() {
|
||||
/* Halts the processors. Any in-process I/Os are allowed to complete */
|
||||
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
if (this.loadTimer) {
|
||||
clearTimeout(this.loadTimer);
|
||||
this.loadTimer = null;
|
||||
}
|
||||
|
||||
if (this.PA && this.PA.busy) {
|
||||
this.PA.busy = 0;
|
||||
this.PA.cycleLimit = 0;
|
||||
@@ -670,11 +687,6 @@ B5500CentralControl.prototype.halt = function() {
|
||||
this.PB.scheduler = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.loadTimer) {
|
||||
clearTimeout(this.loadTimer);
|
||||
this.loadTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -682,33 +694,32 @@ B5500CentralControl.prototype.loadComplete = function loadComplete() {
|
||||
/* Monitors an initial load I/O operation for complete status.
|
||||
When complete, initiates P1 */
|
||||
var completed = false; // true if some I/O Unit finished
|
||||
var that = loadComplete.that; // capture the current closure context
|
||||
|
||||
if (that.CCI08F) { // I/O Unit 1 finished
|
||||
if (this.CCI08F) { // I/O Unit 1 finished
|
||||
completed = true;
|
||||
that.CCI08F = 0;
|
||||
that.AD1F = 0;
|
||||
} else if (that.CCI09F) { // I/O Unit 2 finished
|
||||
this.CCI08F = 0;
|
||||
this.AD1F = 0;
|
||||
} else if (this.CCI09F) { // I/O Unit 2 finished
|
||||
completed = true;
|
||||
that.CCI09F = 0;
|
||||
that.AD2F = 0;
|
||||
} else if (that.CCI10F) { // I/O Unit 3 finished
|
||||
this.CCI09F = 0;
|
||||
this.AD2F = 0;
|
||||
} else if (this.CCI10F) { // I/O Unit 3 finished
|
||||
completed = true;
|
||||
that.CCI10F = 0;
|
||||
that.AD3F = 0;
|
||||
} else if (that.CCI11F) { // I/O Unit 4 finished
|
||||
this.CCI10F = 0;
|
||||
this.AD3F = 0;
|
||||
} else if (this.CCI11F) { // I/O Unit 4 finished
|
||||
completed = true;
|
||||
that.CCI11F = 0;
|
||||
that.AD4F = 0;
|
||||
} else { // Nothing finished yet (or there was an error)
|
||||
that.loadTimer = setTimeout(that.loadComplete, 100);
|
||||
this.CCI11F = 0;
|
||||
this.AD4F = 0;
|
||||
//} else { // Nothing finished yet (or there was an error)
|
||||
// this.loadTimer = setTimeout(this.boundLoadComplete, 1000);
|
||||
}
|
||||
|
||||
if (completed) {
|
||||
that.loadTimer = null;
|
||||
that.LOFF = 0;
|
||||
that.P1.preset(0x10); // start execution at C=@20
|
||||
that.P1.start(); // let'er rip
|
||||
this.loadTimer = null;
|
||||
this.LOFF = 0;
|
||||
this.P1.preset(0x10); // start execution at C=@20
|
||||
this.P1.start(); // let'er rip
|
||||
}
|
||||
};
|
||||
|
||||
@@ -718,23 +729,21 @@ B5500CentralControl.prototype.load = function() {
|
||||
|
||||
if (this.P1 && !this.P1.busy) {
|
||||
this.clear();
|
||||
this.nextTimeStamp = new Date().getTime() + B5500CentralControl.rtcTick;
|
||||
this.timer = setTimeout(this.boundTock, B5500CentralControl.rtcTick);
|
||||
this.LOFF = 1;
|
||||
if (this.IO1 && this.IO1.REMF && !this.AD1F) {
|
||||
this.AD1F = 1;
|
||||
this.IO1.initiateLoad(this.cardLoadSelect);
|
||||
this.loadComplete();
|
||||
this.IO1.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
|
||||
} else if (this.IO2 && this.IO2.REMF && !this.AD2F) {
|
||||
this.AD2F = 1;
|
||||
this.IO2.initiateLoad(this.cardLoadSelect);
|
||||
this.loadComplete();
|
||||
this.IO2.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
|
||||
} else if (this.IO3 && this.IO3.REMF && !this.AD3F) {
|
||||
this.AD3F = 1;
|
||||
this.IO3.initiateLoad(this.cardLoadSelect);
|
||||
this.loadComplete();
|
||||
this.IO3.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
|
||||
} else if (this.IO4 && this.IO4.REMF && !this.AD4F) {
|
||||
this.AD4F = 1;
|
||||
this.IO4.initiateLoad(this.cardLoadSelect);
|
||||
this.loadComplete();
|
||||
this.IO4.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
|
||||
} else {
|
||||
this.CCI04F = 1; // set I/O busy interrupt
|
||||
}
|
||||
@@ -744,11 +753,11 @@ B5500CentralControl.prototype.load = function() {
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.loadTest = function(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,
|
||||
the first executable location is @20, so you will typically want to load
|
||||
to address 0 and call cc.runTest(0x10) [where 0x10 = @20]. This routine
|
||||
should not be used to load ESPOL "DECK" files */
|
||||
"loadAddr" from the ArrayBuffer "buf". Returns the number of B5500
|
||||
words loaded into memory. Note that when loading an ESPOL "DISK" file,
|
||||
the first executable location is @20, so you will typically want to load
|
||||
to address 0 and call cc.runTest(0x10) [where 0x10 = @20]. This routine
|
||||
should not be used to load ESPOL "DECK" files */
|
||||
var addr = loadAddr; // starting B5500 memory address
|
||||
var bytes = buf.byteLength;
|
||||
var data = new DataView(buf); // use DataView() to avoid problems with littleendians.
|
||||
@@ -799,8 +808,8 @@ B5500CentralControl.prototype.loadTest = function(buf, loadAddr) {
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.runTest = function(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]) */
|
||||
P1. "runAddr" is the B5500 word address at which execution will begin
|
||||
(typically 0x10 [octal 20]) */
|
||||
|
||||
this.clear();
|
||||
this.loadTimer = null;
|
||||
@@ -908,7 +917,7 @@ B5500CentralControl.prototype.configureSystem = function() {
|
||||
}
|
||||
}
|
||||
|
||||
// Peripheral unit configuration should take place here once we have it.
|
||||
this.clear();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
|
||||
@@ -60,6 +60,9 @@ function B5500IOUnit(ioUnitID, cc) {
|
||||
this.bufferArea = new ArrayBuffer(16384);
|
||||
this.buffer = new Uint8Array(this.bufferArea);
|
||||
|
||||
// Establish contexts for asynchronously-called methods
|
||||
this.boundForkIO = B5500CentralControl.bindMethod(this.forkIO, this);
|
||||
|
||||
this.clear(); // Create and initialize the processor state
|
||||
}
|
||||
|
||||
@@ -554,11 +557,9 @@ B5500IOUnit.prototype.makeFinish = function(f) {
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500IOUnit.prototype.finishGeneric = function(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
|
||||
busyUnit mask bit in CC */
|
||||
B5500IOUnit.prototype.decodeErrorMask = function(errorMask) {
|
||||
/* Decodes the errorMask returned by the device drivers and ORs it into
|
||||
the D-register error bits */
|
||||
|
||||
if (errorMask & 0x01) {this.D32F = 1}
|
||||
if (errorMask & 0x02) {this.D31F = 1}
|
||||
@@ -567,6 +568,16 @@ B5500IOUnit.prototype.finishGeneric = function(errorMask, length) {
|
||||
if (errorMask & 0x10) {this.D28F = 1}
|
||||
if (errorMask & 0x20) {this.D27F = 1}
|
||||
if (errorMask & 0x40) {this.D26F = 1}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500IOUnit.prototype.finishGeneric = function(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
|
||||
busyUnit mask bit in CC */
|
||||
|
||||
this.decodeErrorMask(errorMask);
|
||||
this.cc.setUnitBusy(this.busyUnit, 0);
|
||||
this.finish();
|
||||
};
|
||||
@@ -758,7 +769,6 @@ B5500IOUnit.prototype.initiate = function() {
|
||||
actual I/O operation to run asynchronously from the processor. Of course, in a browser
|
||||
environment, all of the Javascript action occurs on one thread, so this allows us to
|
||||
multiplex what are supposed to be asynchronous operations on that thread */
|
||||
var that = this; // Establish object context for the callback
|
||||
|
||||
this.clearD();
|
||||
this.AOFF = 0;
|
||||
@@ -774,7 +784,56 @@ B5500IOUnit.prototype.initiate = function() {
|
||||
} else {
|
||||
this.D31F = 0; // reset the IOD-fetch error condition
|
||||
this.D = this.W;
|
||||
this.forkHandle = setTimeout(function() {that.forkIO()}, 0);
|
||||
this.forkHandle = setTimeout(this.boundForkIO, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500IOUnit.prototype.initiateLoad = function(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.
|
||||
CentralControl calls this function in response to the Load button being
|
||||
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 index;
|
||||
var u;
|
||||
|
||||
function finishDiskLoad(errorMask, length) {
|
||||
var memWords = Math.floor((length+7)/8);
|
||||
|
||||
this.storeBuffer(length, 0, this.D21F, memWords);
|
||||
this.decodeErrorMask(errorMask);
|
||||
this.cc.setUnitBusy(this.busyUnit, 0);
|
||||
if (errorMask) {
|
||||
this.busy = 0;
|
||||
this.busyUnit = 0;
|
||||
} else {
|
||||
this.finish();
|
||||
}
|
||||
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.D24F = 1; // read
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -43,7 +43,9 @@ function B5500Processor(procID, cc) {
|
||||
MPED: 0, // Truthy if memory parity error
|
||||
MAED: 0 // Truthy if memory address/inhibit error
|
||||
};
|
||||
this.schedule.that = this; // Establish context for when called from setTimeout()
|
||||
|
||||
// Establish context for asynchronously-called methods
|
||||
this.boundSchedule = B5500CentralControl.bindMethod(this.schedule, this);
|
||||
|
||||
this.clear(); // Create and initialize the processor state
|
||||
}
|
||||
@@ -1341,7 +1343,7 @@ B5500Processor.prototype.start = function() {
|
||||
|
||||
this.busy = 1;
|
||||
this.procTime = new Date().getTime()*1000;
|
||||
this.scheduler = setTimeout(this.schedule, 0);
|
||||
this.scheduler = setTimeout(this.boundSchedule, 0);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -1457,7 +1459,7 @@ B5500Processor.prototype.initiateAsP2 = function() {
|
||||
|
||||
// Now start scheduling P2 on the Javascript thread
|
||||
this.procTime = new Date().getTime()*1000;
|
||||
this.scheduler = setTimeout(this.schedule, 0);
|
||||
this.scheduler = setTimeout(this.boundSchedule, 0);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -3418,6 +3420,7 @@ B5500Processor.prototype.run = function() {
|
||||
}
|
||||
this.M = this.B % 0x8000;
|
||||
this.G = (this.B % 0x40000) >>> 15;
|
||||
this.AROF = 0; // invalidate A
|
||||
break;
|
||||
|
||||
case 0x2F: // XX57: JRV=Jump reverse unconditional
|
||||
@@ -4535,8 +4538,8 @@ B5500Processor.prototype.run = function() {
|
||||
/**************************************/
|
||||
B5500Processor.prototype.schedule = function schedule() {
|
||||
/* Schedules the processor run time and attempts to throttle performance
|
||||
to approximate that of a real B5500. Well, at least we hope this will run
|
||||
fast enough that the performance will need to be throttled. It establishes
|
||||
to approximate that of a real B5500 (well, at least we hope this will run
|
||||
fast enough that the performance will need to be throttled). It establishes
|
||||
a timeslice in terms of a number of processor "cycles" of 1 microsecond
|
||||
each and calls run() to execute at most that number of cycles. run()
|
||||
counts up cycles until it reaches this limit or some terminating event
|
||||
@@ -4545,20 +4548,19 @@ B5500Processor.prototype.schedule = function schedule() {
|
||||
throttling the performance and allowing other modules a chance at the
|
||||
Javascript execution thread. */
|
||||
var delayTime;
|
||||
var that = schedule.that;
|
||||
|
||||
that.scheduler = null;
|
||||
that.cycleLimit = B5500Processor.timeSlice;
|
||||
that.cycleCount = 0;
|
||||
this.scheduler = null;
|
||||
this.cycleLimit = B5500Processor.timeSlice;
|
||||
this.cycleCount = 0;
|
||||
|
||||
that.run();
|
||||
this.run(); // execute syllables for the timeslice
|
||||
|
||||
that.totalCycles += that.cycleCount
|
||||
that.procTime += that.cycleCount;
|
||||
if (that.busy) {
|
||||
delayTime = that.procTime/1000 - new Date().getTime();
|
||||
that.procSlack += delayTime;
|
||||
that.scheduler = setTimeout(that.schedule, (delayTime < 0 ? 1 : delayTime));
|
||||
this.totalCycles += this.cycleCount
|
||||
this.procTime += this.cycleCount;
|
||||
if (this.busy) {
|
||||
delayTime = this.procTime/1000 - new Date().getTime();
|
||||
this.procSlack += delayTime;
|
||||
this.scheduler = setTimeout(this.boundSchedule, (delayTime < 0 ? 1 : delayTime));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -7,107 +7,122 @@
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500Console.css">
|
||||
|
||||
<script src="/B5500/B5500DummyUnit.js"></script>
|
||||
<script src="/B5500/B5500SPOUnit.js"></script>
|
||||
<script src="/B5500/B5500DiskUnit.js"></script>
|
||||
<script src="./B5500DummyUnit.js"></script>
|
||||
<script src="./B5500SPOUnit.js"></script>
|
||||
<script src="./B5500DiskUnit.js"></script>
|
||||
|
||||
<script src="/B5500EMU/B5500SystemConfiguration.js"></script>
|
||||
<script src="/B5500EMU/B5500CentralControl.js"></script>
|
||||
<script src="/B5500EMU/B5500Processor.js"></script>
|
||||
<script src="/B5500EMU/B5500IOUnit.js"></script>
|
||||
<script src="../emulator/B5500SystemConfiguration.js"></script>
|
||||
<script src="../emulator/B5500CentralControl.js"></script>
|
||||
<script src="../emulator/B5500Processor.js"></script>
|
||||
<script src="../emulator/B5500IOUnit.js"></script>
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
var aControl;
|
||||
var aNormal;
|
||||
var bControl;
|
||||
var bNormal;
|
||||
var boundBlinkenlicht;
|
||||
var cc = new B5500CentralControl();
|
||||
var paPanel;
|
||||
var paState = 0;
|
||||
var paTimer = null;
|
||||
var pbState = 0;
|
||||
var pbTimer = null;
|
||||
var timer;
|
||||
var timerInterval = 50; // milliseconds
|
||||
|
||||
var PAStateChange = function() {
|
||||
var aNormal = document.getElementById("ANormalBtn");
|
||||
var aControl = document.getElementById("AControlBtn");
|
||||
var delay = Math.random();
|
||||
function $$(id) {
|
||||
return document.getElementById(id)
|
||||
}
|
||||
|
||||
if (paState || !pbState) { // PA will go to Normal State onlyl if PB is already in Normal State
|
||||
paState = 0;
|
||||
aNormal.className = "yellowButton";
|
||||
aControl.className = "yellowButton yellowLit";
|
||||
delay = Math.log(delay+1)*250;
|
||||
} else {
|
||||
paState = 1;
|
||||
aNormal.className = "yellowButton yellowLit";
|
||||
aControl.className = "yellowButton";
|
||||
delay = Math.log(2-delay)*delay*250;
|
||||
}
|
||||
paTimer = setTimeout(PAStateChange, delay);
|
||||
};
|
||||
function bindMethod(f, context) {
|
||||
return function() {f.apply(context, arguments)};
|
||||
}
|
||||
|
||||
var PBStateChange = function() {
|
||||
var bNormal = document.getElementById("BNormalBtn");
|
||||
var delay = Math.random();
|
||||
|
||||
if (pbState) {
|
||||
pbState = 0;
|
||||
bNormal.className = "yellowButton";
|
||||
delay = Math.log(delay+1)*1000;
|
||||
} else {
|
||||
pbState = 1;
|
||||
bNormal.className = "yellowButton yellowLit";
|
||||
delay = Math.log(2-delay)*delay*delay*1000;
|
||||
}
|
||||
pbTimer = setTimeout(PBStateChange, delay);
|
||||
};
|
||||
|
||||
var PowerOnBtn_Click = function() {
|
||||
document.getElementById("PowerOnBtn").className = "whiteButton whiteLit";
|
||||
document.getElementById("AControlBtn").className = "yellowButton yellowLit";
|
||||
paState = pbState = 0;
|
||||
paTimer = setTimeout(PAStateChange, 3000);
|
||||
pbTimer = setTimeout(PBStateChange, 10000);
|
||||
function PowerOnBtn_Click(ev) {
|
||||
$$("PowerOnBtn").className = "whiteButton whiteLit";
|
||||
$$("AControlBtn").className = "yellowButton yellowLit";
|
||||
cc.powerOn();
|
||||
/******
|
||||
if (!paPanel) {
|
||||
paPanel = window.open("B5500ProcessorPanel.html", "PAPanel", "resizable=yes,scrollbars=yes,width=1,height=1");
|
||||
}
|
||||
*****/
|
||||
$$("LoadBtn").disabled = false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
var PowerOffBtn_Click = function() {
|
||||
paState = pbSate = 0;
|
||||
document.getElementById("PowerOnBtn").className = "whiteButton";
|
||||
document.getElementById("ANormalBtn").className = "yellowButton";
|
||||
document.getElementById("AControlBtn").className = "yellowButton";
|
||||
document.getElementById("BNormalBtn").className = "yellowButton";
|
||||
function PowerOffBtn_Click(ev) {
|
||||
$$("PowerOnBtn").className = "whiteButton";
|
||||
$$("ANormalBtn").className = "yellowButton";
|
||||
$$("AControlBtn").className = "yellowButton";
|
||||
$$("BNormalBtn").className = "yellowButton";
|
||||
cc.powerOff();
|
||||
/*****
|
||||
if (paPanel) {
|
||||
paPanel.close();
|
||||
paPanel = null;
|
||||
}
|
||||
*****/
|
||||
if (paTimer) {
|
||||
clearTimeout(paTimer);
|
||||
paTimer = null;
|
||||
}
|
||||
if (pbTimer) {
|
||||
clearTimeout(pbTimer);
|
||||
pbTimer = null;
|
||||
$$("HaltBtn").disabled = true;
|
||||
$$("LoadBtn").disabled = true;
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
function HaltBtn_Click(ev) {
|
||||
cc.halt();
|
||||
$$("HaltBtn").disabled = true;
|
||||
$$("LoadBtn").disabled = false;
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function LoadBtn_Click(ev) {
|
||||
cc.load();
|
||||
$$("HaltBtn").disabled = false;
|
||||
$$("LoadBtn").disabled = true;
|
||||
boundBlinkenlicht();
|
||||
}
|
||||
|
||||
function dasBlinkenlicht() {
|
||||
var pa = cc.PA;
|
||||
var pb = cc.PB;
|
||||
|
||||
if (pa) {
|
||||
if (!pa.busy) {
|
||||
aControl.className = "yellowButton";
|
||||
aNormal.className = "yellowButton";
|
||||
} else if (pa.NCSF) {
|
||||
aControl.className = "yellowButton";
|
||||
aNormal.className = "yellowButton yellowLit";
|
||||
} else {
|
||||
aNormal.className = "yellowButton";
|
||||
if (pa === cc.P1) {
|
||||
aControl.className = "yellowButton yellowLit";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pb) {
|
||||
if (!pb.busy) {
|
||||
bControl.className = "yellowButton";
|
||||
bNormal.className = "yellowButton";
|
||||
} else if (pb.NCSF) {
|
||||
bControl.className = "yellowButton";
|
||||
bNormal.className = "yellowButton yellowLit";
|
||||
} else {
|
||||
bNormal.className = "yellowButton";
|
||||
if (pb === cc.P1) {
|
||||
bControl.className = "yellowButton yellowLit";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer = setTimeout(boundBlinkenlicht, timerInterval);
|
||||
}
|
||||
|
||||
/***** window.onload() outer block *****/
|
||||
|
||||
document.getElementById("PowerOnBtn").onclick = function() {
|
||||
return PowerOnBtn_Click();
|
||||
};
|
||||
$$("PowerOnBtn").addEventListener("click", PowerOnBtn_Click);
|
||||
$$("PowerOffBtn").addEventListener("click", PowerOffBtn_Click);
|
||||
$$("HaltBtn").addEventListener("click", HaltBtn_Click);
|
||||
$$("LoadBtn").addEventListener("click", LoadBtn_Click);
|
||||
|
||||
document.getElementById("PowerOffBtn").onclick = function() {
|
||||
return PowerOffBtn_Click();
|
||||
};
|
||||
aControl = $$("AControlBtn");
|
||||
aNormal = $$("ANormalBtn");
|
||||
bControl = $$("BControlBtn");
|
||||
bNormal = $$("BNormalBtn");
|
||||
boundBlinkenlicht = bindMethod(dasBlinkenlicht, this);
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
@@ -115,11 +130,11 @@ window.onload = function() {
|
||||
<body>
|
||||
|
||||
<div id=consoleDiv>
|
||||
<button id=HaltBtn class=blackButton>HALT</button>
|
||||
<button id=HaltBtn class=blackButton DISABLED>HALT</button>
|
||||
|
||||
<button id=NotReadyBtn class=yellowButton>NOT READY</button>
|
||||
<button id=LoadSelectBtn class=blackButton>LOAD SELECT</button>
|
||||
<button id=LoadBtn class=blackButton>LOAD</button>
|
||||
<button id=LoadBtn class=blackButton DISABLED>LOAD</button>
|
||||
|
||||
<button id=MemoryCheckBtn class=yellowButton>MEMORY CHECK</button>
|
||||
<button id=ANormalBtn class=yellowButton>A NORMAL</button>
|
||||
|
||||
@@ -23,25 +23,25 @@ function B5500SPOUnit(mnemonic, unitIndex, designate, statusChange, signal) {
|
||||
|
||||
this.maxScrollLines = 500; // Maximum amount of printer scrollback
|
||||
this.charPeriod = 100; // Printer speed, milliseconds per character
|
||||
|
||||
|
||||
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.backspaceChar.that = this; // Store object context for these functions
|
||||
this.printChar.that = this;
|
||||
this.outputChar.that = this;
|
||||
this.outputChar.that = this;
|
||||
|
||||
this.window = window.open("", "SPOWin");
|
||||
if (this.window) {
|
||||
this.window.close(); // destroy the previously-existing window
|
||||
this.window = null;
|
||||
}
|
||||
this.window = window.open("/B5500/B5500SPOUnit.html", "SPOWin", "scrollbars,resizable,width=600,height=500");
|
||||
this.window = window.open("./B5500SPOUnit.html", "SPOWin", "scrollbars,resizable,width=600,height=500");
|
||||
this.window.onload = function() {
|
||||
that.spoOnload();
|
||||
};
|
||||
@@ -53,7 +53,7 @@ B5500SPOUnit.prototype.spoLocal = 1;
|
||||
B5500SPOUnit.prototype.spoRemote = 2;
|
||||
B5500SPOUnit.prototype.spoInput = 3;
|
||||
B5500SPOUnit.prototype.spoOutput = 4;
|
||||
|
||||
|
||||
B5500SPOUnit.prototype.keyFilter = [ // Filter keyCode values to valid B5500 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
|
||||
@@ -88,7 +88,7 @@ B5500SPOUnit.prototype.clear = function() {
|
||||
this.spoLocalRequested = false; // LOCAL button pressed while active
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.hasClass = function(e, name) {
|
||||
/* returns true if element "e" has class "name" in its class list */
|
||||
var classes = e.className;
|
||||
@@ -148,7 +148,7 @@ B5500SPOUnit.prototype.setLocal = function() {
|
||||
this.addClass(this.$$("SPOLocalBtn"), "yellowLit");
|
||||
this.removeClass(this.$$("SPORemoteBtn"), "yellowLit");
|
||||
this.statusChange(0);
|
||||
|
||||
|
||||
// Set up to echo characters from the keyboard
|
||||
this.buffer = null;
|
||||
this.bufLength = 0;
|
||||
@@ -173,11 +173,11 @@ B5500SPOUnit.prototype.setRemote = function() {
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.appendEmptyLine = function() {
|
||||
/* Removes excess lines already printed, then appends a new <pre> element
|
||||
/* 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;
|
||||
var line = document.createElement("pre");
|
||||
|
||||
|
||||
while (count-- > this.maxScrollLines) {
|
||||
this.paper.removeChild(this.paper.firstChild);
|
||||
}
|
||||
@@ -185,7 +185,7 @@ B5500SPOUnit.prototype.appendEmptyLine = function() {
|
||||
this.paper.appendChild(line);
|
||||
line.scrollIntoView();
|
||||
};
|
||||
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.backspaceChar = function backspaceChar() {
|
||||
/* Handles backspace for SPO input */
|
||||
@@ -194,7 +194,7 @@ B5500SPOUnit.prototype.backspaceChar = function backspaceChar() {
|
||||
|
||||
if (that.bufLength > 0) {
|
||||
that.bufIndex--;
|
||||
}
|
||||
}
|
||||
if (that.printCol > 0) {
|
||||
that.printCol--;
|
||||
}
|
||||
@@ -218,13 +218,13 @@ B5500SPOUnit.prototype.printChar = function printChar(c) {
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.outputChar = function outputChar() {
|
||||
/* Outputs one character from the buffer to the SPO. If more characters remain
|
||||
/* Outputs one character from the buffer to the SPO. If more characters remain
|
||||
to be printed, schedules itself 100 ms later to print the next one, otherwise
|
||||
calls finished(). If the column counter exceeds 72, a CR/LF pair is output.
|
||||
A CR/LF pair is also output at the end of the message. Note the use of the local
|
||||
function property "that" (initialized in the constructor), which supplies the
|
||||
necessary SPOUnit object context across setTimeout() calls */
|
||||
var that = outputChar.that; // retrieve our object context
|
||||
var that = outputChar.that; // retrieve our object context
|
||||
var nextTime = that.nextCharTime + that.charPeriod;
|
||||
var delay = nextTime - new Date().getTime();
|
||||
|
||||
@@ -235,16 +235,16 @@ B5500SPOUnit.prototype.outputChar = function outputChar() {
|
||||
that.bufIndex++;
|
||||
that.printCol++;
|
||||
setTimeout(that.outputChar, delay);
|
||||
} else { // set up for the final CR/LF
|
||||
} else { // set up for the final CR/LF
|
||||
that.printCol = 72;
|
||||
setTimeout(that.outputChar, delay);
|
||||
}
|
||||
} else if (that.printCol == 72) { // delay to fake the output of a new-line
|
||||
} else if (that.printCol == 72) { // delay to fake the output of a new-line
|
||||
that.printCol++;
|
||||
setTimeout(that.outputChar, delay+that.charPeriod);
|
||||
} else { // actually output the CR/LF
|
||||
} else { // actually output the CR/LF
|
||||
that.appendEmptyLine();
|
||||
if (that.bufIndex < that.bufLength) {
|
||||
if (that.bufIndex < that.bufLength) {
|
||||
that.printCol = 0; // more characters to print after the CR/LF
|
||||
setTimeout(that.outputChar, delay);
|
||||
} else { // message text is exhausted
|
||||
@@ -257,11 +257,11 @@ B5500SPOUnit.prototype.outputChar = function outputChar() {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.terminateInput = function() {
|
||||
/* Handles the End of Message event. Turns off then Input Request lamp, then
|
||||
calls outputChar(), which will find bufIndex==bufLength, output a new-line,
|
||||
calls outputChar(), which will find bufIndex==bufLength, output a new-line,
|
||||
set the state to Remote, and call finish() for us. Slick, eh? */
|
||||
|
||||
if (this.spoState == this.spoInput) {
|
||||
@@ -271,10 +271,10 @@ B5500SPOUnit.prototype.terminateInput = function() {
|
||||
this.outputChar();
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.cancelInput = function() {
|
||||
/* Handles the Error message event. This is identical to terminateInput(),
|
||||
/* Handles the Error message event. This is identical to terminateInput(),
|
||||
but it also sets a parity error so the input message will be rejected */
|
||||
|
||||
if (this.spoState = this.spoInput) {
|
||||
@@ -285,9 +285,9 @@ B5500SPOUnit.prototype.cancelInput = function() {
|
||||
this.outputChar();
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.keyPress = function(ev) {
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.keyPress = function(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 */
|
||||
@@ -332,7 +332,7 @@ B5500SPOUnit.prototype.keyPress = function(ev) {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.keyDown = function(ev) {
|
||||
/* Handles key-down events to capture ESC, BS, and Enter keystrokes */
|
||||
@@ -394,7 +394,7 @@ B5500SPOUnit.prototype.keyDown = function(ev) {
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.printText = function(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
|
||||
it for printing. This is intended only for printing an initialization message
|
||||
in Local state */
|
||||
var buf = new Uint8Array(msg.length);
|
||||
var length = msg.length;
|
||||
@@ -425,7 +425,7 @@ B5500SPOUnit.prototype.spoOnload = function() {
|
||||
"PRE {margin: 0; font-size: 10pt; font-family: Lucida Sans Typewriter, Courier New, Courier, monospace}" +
|
||||
"</style>";
|
||||
|
||||
this.window.resizeTo(this.window.outerWidth+this.$$("SPODiv").scrollWidth-this.window.innerWidth+8,
|
||||
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.focus();
|
||||
@@ -459,10 +459,12 @@ B5500SPOUnit.prototype.spoOnload = function() {
|
||||
};
|
||||
|
||||
this.window.onkeypress = function(ev) {
|
||||
if (ev.keyCode == 191) ev.preventDefault();
|
||||
that.keyPress(ev);
|
||||
};
|
||||
|
||||
this.window.onkeydown = function(ev) {
|
||||
if (ev.keyCode == 191) ev.preventDefault();
|
||||
that.keyDown(ev);
|
||||
};
|
||||
|
||||
@@ -479,11 +481,11 @@ B5500SPOUnit.prototype.spoOnload = function() {
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.read = function(finish, buffer, length, mode, control) {
|
||||
/* Initiates a read operation on the unit */
|
||||
|
||||
|
||||
this.errorMask = 0;
|
||||
switch (this.spoState) {
|
||||
case this.spoRemote:
|
||||
this.spoState = this.spoInput;
|
||||
this.spoState = this.spoInput;
|
||||
this.addClass(this.$$("SPOInputRequestBtn"), "yellowLit");
|
||||
this.buffer = buffer;
|
||||
this.bufLength = length;
|
||||
@@ -540,34 +542,34 @@ B5500SPOUnit.prototype.write = function(finish, buffer, length, mode, control) {
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.erase = function(finish, length) {
|
||||
/* Initiates an erase operation on the unit */
|
||||
|
||||
|
||||
finish(0x04, 0); // report unit not ready
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.rewind = function(finish) {
|
||||
/* Initiates a rewind operation on the unit */
|
||||
|
||||
|
||||
finish(0x04, 0); // report unit not ready
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.readCheck = function(finish, length, control) {
|
||||
/* Initiates a read check operation on the unit */
|
||||
|
||||
|
||||
finish(0x04, 0); // report unit not ready
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.readInterrogate = function(finish, control) {
|
||||
/* Initiates a read interrogate operation on the unit */
|
||||
|
||||
|
||||
finish(0x04, 0); // report unit not ready
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B5500SPOUnit.prototype.writeInterrogate = function (finish, control) {
|
||||
/* Initiates a write interrogate operation on the unit */
|
||||
|
||||
|
||||
finish(0x04, 0); // report unit not ready
|
||||
};
|
||||
|
||||
@@ -22,15 +22,18 @@
|
||||
* Electronics Units specified by the "euSet" constant, each consisting of the number
|
||||
* of 30-word segments (sectors) specified by the "EUn" properties of "euSet".
|
||||
*
|
||||
* If the ColdStart box is checked on the page, the disk directory structure on
|
||||
* If the ColdStart button is clicked on the page, the disk directory structure on
|
||||
* EU0 is overwritten with a new, empty directory structure, and a default set of
|
||||
* the system parameters are created.
|
||||
* the system parameters is created.
|
||||
*
|
||||
* Once the disk subsystem has been coldstarted, you can load files from a local
|
||||
* file on your workstation. You can run the loader to load files without cold-
|
||||
* starting first, but the disk subsystem must have been previously coldstarted
|
||||
* in order to load any files.
|
||||
*
|
||||
*=======================================================================
|
||||
* The script then reads a Burroughs B5500 Library/Maintenance tape as one
|
||||
* large blob and extracts all files, converting the 6-bit B5500 Internal Code
|
||||
* (BIC) characters to 8-bit ASCII. All files are extracted.
|
||||
* To load files, use the file picker on the upper-right of the page (usually
|
||||
* identified by a "Browse" or "Choose File" button) and select a blob file that
|
||||
* represents a Burroughs B5500 Library/Maintenance tape.
|
||||
*
|
||||
* The blob is assumed to be in the so-called ".bcd" format. Each 7-bit frame
|
||||
* from the tape is represented as one 8-bit unsigned byte. The low-order six
|
||||
@@ -39,11 +42,19 @@
|
||||
* at the start of a physical tape block. Tape marks (EOF) are indicated by a
|
||||
* block containing a single 0x8F byte.
|
||||
*
|
||||
* The extraction process is driven by the tape directory at the beginning of
|
||||
* the tape volume. Continuation "reels" are not currently supported.
|
||||
* After selecting the file, the page will display the file directory on the tape.
|
||||
* Each file name has a checkbox to its left that will select that file as one to
|
||||
* be loaded. Radio buttons on the right may be used optionally to designate one
|
||||
* of the selected files as the MCP and another as the System Intrinsics (INT).
|
||||
* Marking a file as the MCP or Intrinsics causes the bootstrap parameters in
|
||||
* sector 0 of DKA EU0 to be updated accordingly.
|
||||
*
|
||||
* To use, select the .bcd file using the file selection control on the page.
|
||||
* The script writes a log of activity to the web page.
|
||||
* Once you have selected the files to load, click the "Load" button at the bottom
|
||||
* of the page. The page will output a log of the load activity at the end of the
|
||||
* page.
|
||||
*
|
||||
* The files to be loaded must be on one contiguous tape image, contained in one
|
||||
* blob file. Continuation "reels" are not currently supported.
|
||||
************************************************************************
|
||||
* 2012-12-29 P.Kimpel
|
||||
* Original version, from B5500LibMaintExtract.html.
|
||||
@@ -51,14 +62,14 @@
|
||||
"use strict";
|
||||
|
||||
window.onload = function() {
|
||||
const configName = "CONFIG"; // database configuration store name
|
||||
const dbName = "B5500DiskUnit"; // IDB database name
|
||||
const dbVersion = 1; // current IDB database version
|
||||
const directoryTop = 2000; // start of directory area
|
||||
const directoryEnd = 3008; // end of directory area
|
||||
const euSize = 200000; // model I size (5 Storage Units: 6MW or 48MC)
|
||||
const euPrefix = "EU"; // prefix for EU object store names
|
||||
const tapeMark = 0x8F; // .bcd file tapemark (EOF) octet code
|
||||
var configName = "CONFIG"; // database configuration store name
|
||||
var dbName = "B5500DiskUnit"; // IDB database name
|
||||
var dbVersion = 1; // current IDB database version
|
||||
var directoryTop = 2000; // start of directory area
|
||||
var directoryEnd = 3008; // end of directory area
|
||||
var euSize = 200000; // model I size (5 Storage Units: 6MW or 48MC)
|
||||
var euPrefix = "EU"; // prefix for EU object store names
|
||||
var tapeMark = 0x8F; // .bcd file tapemark (EOF) octet code
|
||||
|
||||
var availDisk = null; // available disk space map
|
||||
var config = null; // copy of CONFIG store contents
|
||||
@@ -1642,6 +1653,15 @@ window.onload = function() {
|
||||
function initializeDirectory(config) {
|
||||
/* Initializes the directory structure on EU0. "config" is the
|
||||
database CONFIG structure */
|
||||
var b55Date;
|
||||
var stamp = new Date();
|
||||
var x;
|
||||
|
||||
// Compute a 1980s date based on today's date, formatted as BIC
|
||||
x = stamp.getTime() - new Date(stamp.getFullYear, stamp.getMonth(), 1);
|
||||
x = Math.floor(x/86400000) + 1; // day-of-year number
|
||||
b55Date = (((8*64 + stamp.getYear()%10)*64 +
|
||||
Math.floor(x/100))*64 + Math.floor(x/10)%10)*64 + x%10;
|
||||
|
||||
// Initialize the directory labels segment
|
||||
stringToANSI("0000001?", fileLabels, 14*16); // @114, last-entry marker
|
||||
@@ -1713,7 +1733,7 @@ window.onload = function() {
|
||||
// 1: UNUSED
|
||||
0; // 0: (flag bit)
|
||||
|
||||
info[ 1] = 0x8000001; // Date: BIC "00080001" = 80001 = 1980-01-01
|
||||
info[ 1] = b55Date; // date as BIC
|
||||
info[ 2] = config.eus; // number of EUs
|
||||
info[ 3] = 0; // not used
|
||||
info[ 4] = directoryEnd; // DIRECT deck option
|
||||
@@ -7,23 +7,24 @@
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500SyllableDebugger.css">
|
||||
|
||||
<script src="/B5500/B5500DummyUnit.js"></script>
|
||||
<script src="/B5500/B5500SPOUnit.js"></script>
|
||||
<script src="/B5500/B5500DiskUnit.js"></script>
|
||||
<script src="/B5500/webUI/B5500DummyUnit.js"></script>
|
||||
<script src="/B5500/webUI/B5500SPOUnit.js"></script>
|
||||
<script src="/B5500/webUI/B5500DiskUnit.js"></script>
|
||||
|
||||
<script src="/B5500EMU/B5500SystemConfiguration.js"></script>
|
||||
<script src="/B5500EMU/B5500CentralControl.js"></script>
|
||||
<script src="/B5500EMU/B5500Processor.js"></script>
|
||||
<script src="/B5500EMU/B5500IOUnit.js"></script>
|
||||
<script src="/B5500/emulator/B5500SystemConfiguration.js"></script>
|
||||
<script src="/B5500/emulator/B5500CentralControl.js"></script>
|
||||
<script src="/B5500/emulator/B5500Processor.js"></script>
|
||||
<script src="/B5500/emulator/B5500IOUnit.js"></script>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
const timerCycles = 1000; // Number of instructions per pseudo-timer interrupt
|
||||
var runningCycles = 1000; // Number of instructions per run-mode interval
|
||||
|
||||
var cc;
|
||||
var injected = false; // true if syllable manually injected into T
|
||||
var memAddr = 0x40; // @100
|
||||
var running = false; // true if in run mode
|
||||
var runSilently = false; // true if system state is not to be refreshed after each step
|
||||
var stopAddress = 0; // run-until-address stop point
|
||||
|
||||
@@ -647,6 +648,15 @@ function displaySystemState() {
|
||||
//window.focus();
|
||||
}
|
||||
|
||||
function establishSilence(beQuiet) {
|
||||
/* Maintains synchronization between the global "runSilently" flag, the
|
||||
RunSilently checkbox, and cc.inhCCI03F */
|
||||
|
||||
runSilently = beQuiet;
|
||||
cc.inhCCI03F = !(beQuiet && running);
|
||||
$$("RunSilently").checked = beQuiet;
|
||||
}
|
||||
|
||||
function goIt(ev) {
|
||||
/* Branches to the location specified by the C and L registers: loads
|
||||
P and T to set up for the execution of the instruction at that syllable
|
||||
@@ -689,7 +699,7 @@ function runIt(ev) {
|
||||
/* Steps through instructions continuously until the C register matches the
|
||||
StopAddr address. StopAddr can be changed while running. Setting it to zero
|
||||
(or blank) will halt the continuous stepping */
|
||||
var count = timerCycles;
|
||||
var count = runningCycles;
|
||||
var runBtn = $$("RunBtn");
|
||||
var saveStopAddress = stopAddress;
|
||||
var stopAddr = $$("StopAddr");
|
||||
@@ -708,9 +718,7 @@ function runIt(ev) {
|
||||
}
|
||||
***************************/
|
||||
if (--count <= 0) {
|
||||
count = timerCycles;
|
||||
cc.CCI03F = 1; // set timer interrupt
|
||||
cc.signalInterrupt();
|
||||
count = runningCycles;
|
||||
break; // exit loop to pick up events
|
||||
}
|
||||
} while (runSilently && stopAddress && cc.P1.C != stopAddress);
|
||||
@@ -724,11 +732,15 @@ function runIt(ev) {
|
||||
stopAddress = 0; // bad address
|
||||
stopAddr.style.backgroundColor = "red";
|
||||
runBtn.value = "Run";
|
||||
running = false;
|
||||
cc.inhCCI03F = true;
|
||||
} else {
|
||||
stopAddress = saveStopAddress;
|
||||
stopAddr.style.backgroundColor = "";
|
||||
stopAddr.value = padOctal(stopAddress, stopAddr.maxLength);
|
||||
runBtn.value = "Run";
|
||||
running = false;
|
||||
cc.inhCCI03F = true;
|
||||
if (runSilently) {
|
||||
displaySystemState();
|
||||
}
|
||||
@@ -743,6 +755,8 @@ function runIt(ev) {
|
||||
injected = false;
|
||||
stopAddr.style.backgroundColor = "green";
|
||||
runBtn.value = "Stop";
|
||||
running = true;
|
||||
cc.inhCCI03F = !runSilently;
|
||||
syllabicate();
|
||||
}
|
||||
}
|
||||
@@ -817,7 +831,7 @@ function tos_onChange(ev, bicID, valueID, origID) {
|
||||
function runSilently_onClick(ev) {
|
||||
/* Handle the onchange event for the RunSilently checkbox */
|
||||
|
||||
runSilently = ev.target.checked;
|
||||
establishSilence(ev.target.checked);
|
||||
}
|
||||
|
||||
function fileLoader_onLoad(ev) {
|
||||
@@ -851,6 +865,10 @@ function fileSelector_onChange(ev) {
|
||||
reader.readAsArrayBuffer(f);
|
||||
}
|
||||
|
||||
function hardwareLoad_onClick(ev) {
|
||||
/* Handle the "Hardware Load" button click */
|
||||
}
|
||||
|
||||
function checkBrowser() {
|
||||
/* Checks whether this browser can support the necessary stuff */
|
||||
var missing = "";
|
||||
@@ -1025,6 +1043,7 @@ function initialize() {
|
||||
};
|
||||
|
||||
$$("FileSelector").addEventListener("change", fileSelector_onChange, false);
|
||||
$$("HardwareLoad").addEventListener("click", hardwareLoad_onClick, false);
|
||||
$$("GoBtn").addEventListener("click", goIt, false);
|
||||
$$("StepBtn").addEventListener("click", stepIt, false);
|
||||
$$("RunBtn").addEventListener("click", runIt, false);
|
||||
@@ -1032,7 +1051,6 @@ function initialize() {
|
||||
|
||||
cc = new B5500CentralControl();
|
||||
cc.powerOn();
|
||||
cc.clear();
|
||||
|
||||
cc.P1.S = 0x40; // stack at @100
|
||||
cc.P1.R = 0x005; // PRT at @500 (R has addr div 64)
|
||||
@@ -1047,7 +1065,7 @@ function initialize() {
|
||||
|
||||
displaySystemState();
|
||||
displayOctal("StopAddr", stopAddress, 5);
|
||||
$$("RunSilently").checked = runSilently;
|
||||
establishSilence(runSilently);
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
@@ -1071,6 +1089,8 @@ window.onload = function() {
|
||||
<h3>B5500 Syllable Debugger</h3>
|
||||
<p>
|
||||
<input id=FileSelector type=file size=60>
|
||||
|
||||
<input id=HardwareLoad type=button value="Hardware Load">
|
||||
</p>
|
||||
|
||||
<table id=RegisterBank1 class="normal border">
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500DistributionAndDisplay.css">
|
||||
|
||||
<script src="/B5500/B5500DummyUnit.js"></script>
|
||||
<script src="/B5500/B5500SPOUnit.js"></script>
|
||||
<script src="/B5500/B5500DiskUnit.js"></script>
|
||||
<script src="./B5500DummyUnit.js"></script>
|
||||
<script src="./B5500SPOUnit.js"></script>
|
||||
<script src="./B5500DiskUnit.js"></script>
|
||||
|
||||
<script src="/B5500EMU/emulator/B5500SystemConfiguration.js"></script>
|
||||
<script src="/B5500EMU/emulator/B5500CentralControl.js"></script>
|
||||
<script src="/B5500EMU/emulator/B5500Processor.js"></script>
|
||||
<script src="/B5500EMU/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";
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500DistributionAndDisplay.css">
|
||||
|
||||
<script src="/B5500/B5500DummyUnit.js"></script>
|
||||
<script src="/B5500/B5500SPOUnit.js"></script>
|
||||
<script src="/B5500/B5500DiskUnit.js"></script>
|
||||
<script src="./B5500DummyUnit.js"></script>
|
||||
<script src="./B5500SPOUnit.js"></script>
|
||||
<script src="./B5500DiskUnit.js"></script>
|
||||
|
||||
<script src="/B5500EMU/emulator/B5500SystemConfiguration.js"></script>
|
||||
<script src="/B5500EMU/emulator/B5500CentralControl.js"></script>
|
||||
<script src="/B5500EMU/emulator/B5500Processor.js"></script>
|
||||
<script src="/B5500EMU/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";
|
||||
|
||||
Reference in New Issue
Block a user