1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-04-28 04:55:59 +00:00

1. Commit DCMCP transcription as of 2013-03-02.

2. Debugging mods to complete single-stepping through KERNEL bootstrap.
3. Implement FBS and LLL in Processor.
4. Delete old this.access() logic in Processor.
This commit is contained in:
paul
2013-03-03 02:56:25 +00:00
parent 05593d0079
commit 587989c11b
6 changed files with 463 additions and 485 deletions

View File

@@ -21943,3 +21943,75 @@ END; % OF LIBRARYZERO 28892000
GO INITIATE; 31023000
END; END; 31024000
END ERRORFIXER; 31025000
PROCEDURE JOBMESS(MIX,Q,A,B,C,D); VALUE MIX,Q,A,B,C,D;% 32000000
REAL MIX,Q,A,B,C,D;% 32000100
COMMENT : THIS PROCEDURE CAN BE USED TO BUILD AND SPOUT A MESSAGE 32000110
THAT IS TO BE PRECEEDED BY A <JOB SPECIFIER> WHICH IT 32000120
BUILDS AUTOMATICALLY FOR THE MIX GIVEN; 32000130
BEGIN REAL BUF,T;% 32000200
$ SET OMIT = NOT(PACKETS) 32000249
REAL UNITNO; 32000250
$ POP OMIT 32000251
LABEL EXIT; 32000280
BUF ~ SPACE(9); 32000300
IF MIX = 0 THEN 32000400
BEGIN T:=SPACE(30);DISKWAIT(-T,30,0); 32000500
STREAM(M:=M[T+10+5|SYSNO],F:=M[T+11+5|SYSNO],BUF); 32000510
BEGIN DS:=3 LIT" D:"; SI:=LOC M; SI:=SI+1; DS:=7 CHR; 32000520
DS:=LIT"/";SI:=SI+1;DS:=7CHR;DS:=3LIT"= 0"; 32000530
END; 32000540
FORGETSPACE(T); 32000600
T:=(BUF+2)&5[30:45:3]; 32000650
END ELSE% 32000700
IF JARROW[MIX[!0 THEN 32000750
BEGIN; STREAM(C!0:R~ IF (T~ PRYOR[MIX])<0 THEN T ELSE T INX 0, 32000800
J ~ JARROW[MIX],MIX,A ~ IF JAR[MIX,0]<0 THEN JAR[MIX,30] 32000810
ELSE 0,BUF); 32000812
BEGIN DS ~ LIT " "; SI ~ LOC R; DS ~ 6 DEC;% 32000850
DI ~ DI-6; DS ~ 5 FILL; DI ~ BUF; DI ~ DI+7;% 32001000
DS ~ LIT ":"; SI ~ J; 32001100
IF SC="+" THEN 32001120
BEGIN SI ~ SI+1; DS ~ 7 CHR; DS ~ LIT " "; 32001140
SI ~ SI+1; DS ~ 7 CHR; DS ~ LIT "/"; 32001160
SI ~ LOC A; SI ~ SI+1; DS ~ 7 CHR; 32001180
END ELSE 32001200
BEGIN SI ~ SI+1; DS ~ 7 CHR; DS ~ LIT "/"; 32001220
SI ~ SI+1; DS ~ 7 CHR; 32001240
END; 32001260
DS ~ LIT "="; SI ~ LOC MIX; DS ~ 2 DEC;% 32001300
C ~ DI; DI ~ DI -2; DS ~ 2 FILL;% 32001400
END STREAM; 32001450
T := POLISH; 32001475
$ SET OMIT = NOT(PACKETS) 32001499
IF Q.[CF]=MIX THEN UNITNO:=PSEUDOMIX[MIX]; 32001500
$ POP OMIT 32001501
END ELSE % NO SUCH MIX 32001550
BEGIN FORGETSPACE(BUF); 32001575
GO TO EXIT; 32001600
END; 32001625
STREAM(A~[A],Z~0,T);% 32001700
BEGIN SI ~ A; DS ~ LIT " ";% 32001800
4(IF SC ! "+" THEN 32001900
BEGIN TALLY ~ 7; SI ~ SI +1; % 32001910
6(L: IF SC = "0" THEN% 32001920
BEGIN TALLY ~ TALLY + 63; SI ~ SI + 1; 32002000
END ELSE JUMP OUT);% 32002050
Z ~ TALLY; DS ~ Z CHR;% 32002070
END ELSE SI ~ SI + 8);% 32002090
DS ~ LIT "~";% 32002100
END STREAM;% 32002200
SPOUTER(BUF & Q[9:9:9],UNITNO,1); 32002300
EXIT: 32002350
END JOBMESS;% 32002400
PROCEDURE MIXPRINT(Q); VALUE Q; REAL Q; 32100000
COMMENT THIS PROCEDURE INVOKES JOBMESS TO TYPE THE JOB SPECIFIERS 32100010
OF EACH ACTIVE MIX;% 32100020
BEGIN REAL T,I; 32100100
FOR I~1 STEP 1 UNTIL MIXMAX DO 32100200
IF JAR[I,*] ! 0 THEN% 32100300
BEGIN JOBMESS(I,Q,-0,-0,-0,-0); T ~ 1 END;% 32100350
IF NOT T THEN% NULL MIX 32100400
BEGIN; STREAM(T~T~SPACE(2)); DS~11LIT " NULL MIX~";% 32100500
SPOUT(T & Q[9:9:9]);% 32100600
END NULL MIX; 32100700
END MIXPRINT;% 32100800

View File

@@ -54,10 +54,10 @@ function B5500IOUnit(ioUnitID, cc) {
MPED: 0, // Truthy if memory parity error
MAED: 0 // Truthy if memory address/inhibit error
};
// Establish a buffer for the peripheral modules to use during their I/O.
// The size is sufficient for 63 disk sectors, rounded up to the next 8KB.
this.bufferArea = new ArrayBuffer(16384);
this.bufferArea = new ArrayBuffer(16384);
this.buffer = new Uint8Array(this.bufferArea);
this.clear(); // Create and initialize the processor state
@@ -65,7 +65,7 @@ function B5500IOUnit(ioUnitID, cc) {
/**************************************/
B5500IOUnit.timeSlice = 5000; // Standard run() timeslice, about 5ms (we hope)
B5500IOUnit.timeSlice = 5000; // Standard run() timeslice, about 5ms (we hope)
B5500IOUnit.memCycles = 6; // assume 6 us memory cycle time (the other option was 4 usec)
B5500IOUnit.BICtoANSI = [ // Index by 6-bit BIC to get 8-bit ANSI code
@@ -87,7 +87,7 @@ B5500IOUnit.BICtoBCLANSI = [ // Index by 6-bit BIC to get 8-bit BCL-a
0x51,0x52,0x2A,0x2D,0x7C,0x29,0x3B,0x7B, // 28-2F, @50-57
0x2B,0x41,0x42,0x43,0x44,0x45,0x46,0x47, // 30-37, @60-67
0x48,0x49,0x5B,0x26,0x2E,0x28,0x3C,0x7E]; // 38-3F, @70-77
B5500IOUnit.ANSItoBIC = [ // Index by 8-bit ANSI to get 6-bit BIC (upcased, invalid=>"?")
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 00-0F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 10-1F
@@ -105,7 +105,7 @@ B5500IOUnit.ANSItoBIC = [ // Index by 8-bit ANSI to get 6-bit BIC
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // D0-DF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // E0-EF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C]; // F0-FF
B5500IOUnit.BCLANSItoBIC = [ // Index by 8-bit BCL-as-ANSI to get 6-bit BIC (upcased, invalid=>"?")
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 00-0F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 10-1F
@@ -131,16 +131,16 @@ B5500IOUnit.prototype.clear = function() {
this.W = 0; // Memory buffer register
this.D = 0; // I/O descriptor (control) register
this.clearD(); // clear the D-register exploded fields
this.CC = 0; // Character counter (3 bits)
this.IB = 0; // Input buffer register (6 bits+parity)
this.IB = 0; // Input buffer register (6 bits+parity)
this.IR = 0; // Tape read register (6 bits+parity)
this.OB = 0; // Output buffer register (6 bits+parity)
this.WB = 0; // Tape write register (6 bits+parity)
this.LP = 0; // Longitudinal parity register (6 bits+parity)
this.SC = 0; // Sequence counter (4 bits)
this.SC = 0; // Sequence counter (4 bits)
this.PC = 0; // Pulse counter register (6 bits, 1MHz rate)
this.AOFF = 0; // Address overflow FF
this.EXNF = 0; // W-contents FF (0=has address, 1=has descriptor)
this.HOLF = 0; // Hold-over FF (for alpha vs. binary card read)
@@ -150,21 +150,21 @@ B5500IOUnit.prototype.clear = function() {
this.MAOF = 0; // Memory access obtained FF
this.OBCF = 0; // (unknown)
this.STRF = 0; // Strobe FF
this.BKWF = 0; // Tape control FF
this.FWDF = 0; // Tape control FF
this.IM1F = 0; // Tape control FF
this.IMFF = 0; // Tape control FF
this.PUCF = 0; // Tape control FF
this.RCNF = 0; // Tape control FF
this.SHOF = 0; // Tape control FF
this.SKFF = 0; // Tape control FF
this.VRCF = 0; // Tape control FF
this.BKWF = 0; // Tape control FF
this.FWDF = 0; // Tape control FF
this.IM1F = 0; // Tape control FF
this.IMFF = 0; // Tape control FF
this.PUCF = 0; // Tape control FF
this.RCNF = 0; // Tape control FF
this.SHOF = 0; // Tape control FF
this.SKFF = 0; // Tape control FF
this.VRCF = 0; // Tape control FF
this.IMCF = 0; // (unknown)
this.RECF = 0; // (unknown)
this.REMF = 1; // Remote FF (0=local, 1=remote and available)
this.busy = 0; // I/O Unit is busy
this.busyUnit = 0; // Peripheral unit index currently assigned to the I/O Unit
@@ -173,7 +173,7 @@ B5500IOUnit.prototype.clear = function() {
this.totalCycles = 0; // Total cycles executed on this I/O Unit
this.ioUnitTime = 0; // Total I/O Unit running time, based on cycles executed
this.ioUnitSlack = 0; // Total I/O Unit throttling delay, milliseconds
if (this.forkHandle) {
clearTimeout(this.forkHandle);
}
@@ -182,7 +182,7 @@ B5500IOUnit.prototype.clear = function() {
/**************************************/
B5500IOUnit.prototype.clearD = function() {
/* Clears the D-register and the exploded field variables used internally */
this.D = 0;
this.Dunit = 0; // Unit designate field (5 bits)
this.DwordCount = 0; // Word count field (10 bits)
@@ -211,7 +211,7 @@ B5500IOUnit.prototype.fetch = function(addr) {
this.cc.fetch(acc);
this.W = acc.word;
this.cycleCount += B5500IOUnit.memCycles;
this.cycleCount += B5500IOUnit.memCycles;
if (acc.MAED) {
this.D26F = 1; // set memory address error
return 1;
@@ -233,7 +233,7 @@ B5500IOUnit.prototype.store = function(addr) {
acc.word = this.W;
this.cc.store(acc);
this.cycleCount += B5500IOUnit.memCycles;
this.cycleCount += B5500IOUnit.memCycles;
if (acc.MAED) {
this.D26F = 1; // set memory address error
return 1;
@@ -245,9 +245,9 @@ B5500IOUnit.prototype.store = function(addr) {
/**************************************/
B5500IOUnit.prototype.fetchBuffer = function(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
with the final transfer address+1. If this.D23F, updates this.wordCount
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
with the final transfer address+1. If this.D23F, updates this.wordCount
with any remaining count.
Returns the number of characters fetched into the buffer */
var addr = this.Daddress; // local copy of memory address
@@ -259,7 +259,7 @@ B5500IOUnit.prototype.fetchBuffer = function(mode, words) {
var s; // character shift counter
var table = (mode ? B5500IOUnit.BICtoANSI : B5500IOUnit.BICtoBCLANSI);
var w; // local copy of this.W
do { // loop through the words
if (words <= 0) {
done = true;
@@ -270,7 +270,7 @@ B5500IOUnit.prototype.fetchBuffer = function(mode, words) {
this.D26F = 1; // address overflow: set invalid address error
done = true;
} else if (!this.fetch(addr)) { // fetch the next word from memory
w = this.W; // fill the buffer with this word's characters
w = this.W; // fill the buffer with this word's characters
for (s=0; s<8; s++) {
c = (w - (w %= 0x40000000000))/0x40000000000;
buf[count++] = table[c];
@@ -284,7 +284,7 @@ B5500IOUnit.prototype.fetchBuffer = function(mode, words) {
}
}
} while (!done);
this.Daddress = addr;
if (this.D23F) {
this.DwordCount = words & 0x1FF;
@@ -295,10 +295,10 @@ B5500IOUnit.prototype.fetchBuffer = function(mode, words) {
/**************************************/
B5500IOUnit.prototype.fetchBufferWithGM = function(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
by a group-mark code in memory. At exit, updates this.Daddress with the
final transfer address+1. If this.D23F, updates this.wordCount
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
by a group-mark code in memory. At exit, updates this.Daddress with the
final transfer address+1. If this.D23F, updates this.wordCount
with any remaining count.
Returns the number of characters fetched into the buffer */
var addr = this.Daddress; // local copy of memory address
@@ -310,7 +310,7 @@ B5500IOUnit.prototype.fetchBufferWithGM = function(mode, words) {
var s; // character shift counter
var table = (mode ? B5500IOUnit.BICtoANSI : B5500IOUnit.BICtoBCLANSI);
var w; // local copy of this.W
do { // loop through the words
if (words <= 0) {
done = true;
@@ -321,11 +321,11 @@ B5500IOUnit.prototype.fetchBufferWithGM = function(mode, words) {
this.D26F = 1; // address overflow: set invalid address error
done = true;
} else if (!this.fetch(addr)) { // fetch the next word from memory
w = this.W; // fill the buffer with this word's characters
w = this.W; // fill the buffer with this word's characters
for (s=0; s<8; s++) {
c = (w - (w %= 0x40000000000))/0x40000000000;
if (c == 0x1F) {
done = true; // group-mark detected
if (c == 0x1F) {
done = true; // group-mark detected
break;
} else {
buf[count++] = table[c];
@@ -340,7 +340,7 @@ B5500IOUnit.prototype.fetchBufferWithGM = function(mode, words) {
}
}
} while (!done);
this.Daddress = addr;
if (this.D23F) {
this.DwordCount = words & 0x1FF;
@@ -352,9 +352,9 @@ B5500IOUnit.prototype.fetchBufferWithGM = function(mode, words) {
B5500IOUnit.prototype.storeBuffer = function(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;
"mode": 0=BCLANSI, 1=ANSI; "words": maximum number of words to transfer.
At exit, updates this.Daddress with the final transfer address+1.
"chars": the number of characters to store, starting at "offset" in the buffer;
"mode": 0=BCLANSI, 1=ANSI; "words": maximum number of words to transfer.
At exit, updates this.Daddress with the final transfer address+1.
If this.D23F, updates this.wordCount with any remaining count.
Returns the number of characters stored into memory from the buffer */
var addr = this.Daddress; // local copy of memory address
@@ -367,7 +367,7 @@ B5500IOUnit.prototype.storeBuffer = function(chars, offset, mode, words) {
var s = 0; // character shift counter
var table = (mode ? B5500IOUnit.ANSItoBIC : B5500IOUnit.BCLANSItoBIC);
var w = 0; // local copy of this.W
while (!done) { // loop through the words
if (count >= chars) {
done = true;
@@ -412,7 +412,7 @@ B5500IOUnit.prototype.storeBuffer = function(chars, offset, mode, words) {
addr++;
}
}
this.Daddress = addr;
if (this.D23F) {
this.DwordCount = words & 0x1FF;
@@ -424,11 +424,11 @@ B5500IOUnit.prototype.storeBuffer = function(chars, offset, mode, words) {
B5500IOUnit.prototype.storeBufferWithGM = function(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;
"mode": 0=BCLANSI, 1=ANSI; "words": maximum number of words to transfer.
The final character stored from the buffer is followed in memory by a group-mark,
assuming the word count is not exhausted. At exit, updates this.Daddress with the
final transfer address+1.
"chars": the number of characters to store, starting at "offset" in the buffer;
"mode": 0=BCLANSI, 1=ANSI; "words": maximum number of words to transfer.
The final character stored from the buffer is followed in memory by a group-mark,
assuming the word count is not exhausted. At exit, updates this.Daddress with the
final transfer address+1.
If this.D23F, updates this.wordCount with any remaining count.
Returns the number of characters stored into memory from the buffer, plus one
for the group-mark */
@@ -442,7 +442,7 @@ B5500IOUnit.prototype.storeBufferWithGM = function(chars, offset, mode, words) {
var s = 0; // character shift counter
var table = (mode ? B5500IOUnit.ANSItoBIC : B5500IOUnit.BCLANSItoBIC);
var w = 0; // local copy of this.W
while (!done) { // loop through the words
if (count >= chars) {
done = true;
@@ -472,7 +472,7 @@ B5500IOUnit.prototype.storeBufferWithGM = function(chars, offset, mode, words) {
}
}
} // while !done
w += 0x1F*power; // set group mark in register
s++;
count++;
@@ -491,7 +491,7 @@ B5500IOUnit.prototype.storeBufferWithGM = function(chars, offset, mode, words) {
addr++;
}
}
this.Daddress = addr;
if (this.D23F) {
this.DwordCount = words & 0x1FF;
@@ -503,8 +503,8 @@ B5500IOUnit.prototype.storeBufferWithGM = function(chars, offset, mode, words) {
B5500IOUnit.prototype.finish = function () {
/* 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 */
this.W = this.D =
this.W = this.D =
this.Dunit * 0x10000000000 +
this.DwordCount * 0x40000000 +
this.D18F * 0x20000000 +
@@ -520,7 +520,7 @@ B5500IOUnit.prototype.finish = function () {
this.D31F * 0x10000 +
this.D32F * 0x8000 +
this.Daddress;
switch(this.ioUnitID) {
case "1":
this.store(0x0C);
@@ -539,9 +539,9 @@ B5500IOUnit.prototype.finish = function () {
this.cc.CCI08F = 1; // set I/O Finished #4
break;
}
this.busy = 0; // zero so CC won't think I/O unit is busy
this.busyUnit = 0;
this.busyUnit = 0;
this.cc.signalInterrupt();
};
@@ -549,7 +549,7 @@ B5500IOUnit.prototype.finish = function () {
B5500IOUnit.prototype.makeFinish = function(f) {
/* Utility function to create a closure for I/O finish handlers */
var that = this;
return function(mask, length) {return f.call(that, mask, length)};
};
@@ -559,7 +559,7 @@ B5500IOUnit.prototype.finishGeneric = function(errorMask, length) {
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 */
if (errorMask & 0x01) {this.D32F = 1}
if (errorMask & 0x02) {this.D31F = 1}
if (errorMask & 0x04) {this.D30F = 1}
@@ -574,7 +574,7 @@ B5500IOUnit.prototype.finishGeneric = function(errorMask, length) {
/**************************************/
B5500IOUnit.prototype.finishSPORead = function(errorMask, length) {
/* Handles I/O finish for a SPO keyboard input operation */
this.storeBufferWithGM(length, 0, 1, 0x7FFF);
this.finishGeneric(errorMask, length);
};
@@ -584,7 +584,7 @@ B5500IOUnit.prototype.finishDiskRead = function(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);
if (segWords < memWords) {
memWords = segWords;
}
@@ -599,14 +599,14 @@ B5500IOUnit.prototype.initiateDiskIO = function(u) {
check and interrogate operations are determined from their respective IOD bits. If
it's a read data operation, we request the specified number of segments from the disk
and will sort out word count issues in finishDiskRead(). If it's a write data operation,
we truncate or pad the data from memory as appropriate and request a write of the
we truncate or pad the data from memory as appropriate and request a write of the
specified number of segments */
var c; // address char
var memWords; // number of memory words to transfer
var p = 1; // address digit power
var w; // current memory word value
var x; // temp variable
var segAddr = 0; // disk segment address
var segs = this.LP; // I/O size in segments
var segWords = segs*30; // I/O size in words
@@ -640,7 +640,7 @@ B5500IOUnit.prototype.initiateDiskIO = function(u) {
this.fetchBuffer(this.D21F, segWords);
} else { // transfer size is limited by word count
x = this.fetchBuffer(this.D21F, memWords);
c = (this.D21F ? 0x00 : 0x2B); // pad "0" if binary, " " if alpha (as BCL)
c = (this.D21F ? 0x30 : 0x2B); // pad "0" if binary, "#" if alpha (for BCL " ")
while (x < segChars) { // pad remainder of buffer up to seg count
this.buffer[x++] = c;
}
@@ -660,7 +660,7 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
var x; // temp number variable
this.forkHandle = null; // clear the setTimeout() handle
x = this.D; // explode the D-register into its fields
this.Dunit = this.cc.fieldIsolate(x, 3, 5);
this.DwordCount = this.cc.fieldIsolate(x, 8, 10);
@@ -685,13 +685,13 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
u = this.cc.unit[index];
switch(this.Dunit) {
// disk designates
case 6:
case 6:
case 12:
this.initiateDiskIO(u);
break;
// printer designates
case 22:
case 22:
case 26:
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
break;
@@ -722,19 +722,19 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
break;
// magnetic tape designates
case 1: case 3: case 5: case 7: case 9: case 11: case 13: case 15:
case 1: case 3: case 5: case 7: case 9: case 11: case 13: case 15:
case 17: case 19: case 21: case 23: case 25: case 27: case 29: case 31:
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
break;
// drum designates
case 4:
case 4:
case 8:
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
break;
// paper tape designates
case 18:
case 18:
case 20:
this.D30F = 1; this.finish(); // >>> temp until implemented <<<
break;
@@ -754,12 +754,12 @@ B5500IOUnit.prototype.initiate = function() {
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
processor. This routine merely fetches the IOD from memory and then schedules forkIO()
to run asynchronously. Then we exit back through CC and into P1, thus allowing the
to run asynchronously. Then we exit back through CC and into P1, thus allowing the
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
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;
this.EXNF = 0;
@@ -773,7 +773,7 @@ B5500IOUnit.prototype.initiate = function() {
this.finish();
} else {
this.D31F = 0; // reset the IOD-fetch error condition
this.D = this.W;
this.D = this.W;
this.forkHandle = setTimeout(function() {that.forkIO()}, 0);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -241,31 +241,34 @@ window.onload = function() {
}
/**************************************/
function stringToANSI(text, bytes, bx) {
function stringToANSI(text, bytes, bx, asBinary) {
/* Translates the characters in a string to upper case, and then to ANSI
byte-array format. "text" is the input string, "bytes" is the Uint8Array
output buffer, and "bx" is the offset into that output buffer */
output buffer, and "bx" is the offset into that output buffer. If "asBinary" is
truthy, the translation is binary, otherwise it is done as BCLANSI */
var len = text.length;
var table1 = (asBinary ? BICtoANSI : BICtoBCLANSI);
var utxt = text.toUpperCase();
var x;
bx = bx || 0;
for (x=0; x<len; x++) {
bytes[bx++] = utxt.charCodeAt(x) & 0xFF;
bytes[bx++] = table1[ANSItoBIC[utxt.charCodeAt(x) & 0xFF]];
}
}
/**************************************/
function wordsToANSI(words, wx, wLength, bytes, bx) {
function wordsToANSI(words, wx, wLength, bytes, bx, asBinary) {
/* Translates an array of B5500 words to ANSI byte-array format.
"words" = the array of words
"wx" = the starting index in "words"
"wLength" = the number of words to translate: if this is negative, then binary
translation is done; otherwise B5500 BCLANSI translation is done
"wLength" = the number of words to translate
"bytes" = a Uint8Array array
"bx" = the starting index in "bytes" to store the translated data */
"bx" = the starting index in "bytes" to store the translated data
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var c;
var table = (wLength < 0 ? BICtoANSI : BICtoBCLANSI);
var table = (asBinary ? BICtoANSI : BICtoBCLANSI);
var w;
var x;
var y;
@@ -287,17 +290,18 @@ window.onload = function() {
}
/**************************************/
function ANSItoWords(bytes, bx, bLength, words, wx) {
function ANSItoWords(bytes, bx, bLength, words, wx, asBinary) {
/* Translates a portion of an ANSI byte array to a sequence of B5500 words.
"bytes" = the Uint8Array byte array
"bx" = 0-relative offset into "bytes"
"bLength" = number of bytes to translate: if this is negative, then binary
translation is done; otherwise B5500 BCLANSI translation is done
"bLength" = number of bytes to translate
"words" = the word array
"wx" = 0-relative offset into "words" to store the translated data */
"wx" = 0-relative offset into "words" to store the translated data
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var cx = 0;
var w = 0;
var table = (bLength < 0 ? ANSItoBIC : BCLANSItoBIC);
var table = (asBinary ? ANSItoBIC : BCLANSItoBIC);
var x;
wx = wx || 0;
@@ -443,7 +447,7 @@ window.onload = function() {
/**************************************/
function writeDiskWords(eu, addr, words, wx, wLength) {
/* Translates the B5500 words in "words" starting at "wx" for "wLength" words
to ANSI and writes the block one segment at a time to the "eu", starting at
to BCLANSI and writes the block one segment at a time to the "eu", starting at
segment "addr" */
var segment = new Uint8Array(240);
@@ -456,7 +460,7 @@ window.onload = function() {
}
wordsToANSI(words, wx, wLength, segment, 0);
for (wx=wLength*8; wx<240; wx++) {
segment[wx] = 0x30; // fill partial seg with ASCII "0" => BCL "0" => @00
segment[wx] = 0x26; // fill partial seg with ASCII "&" => BCL " " => BIC @60
}
eu.put(segment, addr);
}
@@ -1049,9 +1053,9 @@ window.onload = function() {
nameParts = tapeDir[fileNr].split("/");
mfid = "0" + padToLength(nameParts[0] || " ", 7);
fid = "0" + padToLength(nameParts[1] || " ", 7);
stringToANSI(mfid, buf, 0);
stringToANSI(fid, buf, 8);
ANSItoWords(buf, 0, -16, names, 0);
stringToANSI(mfid, buf, 0, true);
stringToANSI(fid, buf, 8, true);
ANSItoWords(buf, 0, 16, names, 0, true);
mfid = names[0];
fid = names[1];
loadAsMCP = $$("AsMCP_" + fileNr).checked;
@@ -1830,8 +1834,9 @@ window.onload = function() {
function dumpDisk() {
/* Dumps the initial and directory portions of the disk */
var txn = disk.transaction("EU0");
var endKey = directoryTop+100;
var eu = txn.objectStore("EU0");
var range = IDBKeyRange.upperBound(directoryTop+20);
var range = IDBKeyRange.upperBound(endKey);
var req = eu.openCursor(range);
var lastKey = -1;
@@ -1847,6 +1852,9 @@ window.onload = function() {
lastKey = cursor.key;
cursor.continue();
} else {
if (endKey > lastKey) {
spout("----- " + (endKey-lastKey) + " unallocated segments thru " + endKey + " -----");
}
spout("===== END OF DISK DUMP =====");
}
};
@@ -1879,7 +1887,7 @@ window.onload = function() {
$$("ColdstartBtn").disabled = false;
$$("FileSelector").disabled = false;
// dumpDisk(); // <<<<<<<<<<<<<< DEBUG <<<<<<<<<<<<<<<<<
dumpDisk(); // <<<<<<<<<<<<<< DEBUG <<<<<<<<<<<<<<<<<
disk.transaction("CONFIG").objectStore("CONFIG").get(0).onsuccess = function(ev) {
config = ev.target.result;

View File

@@ -12,7 +12,7 @@
* addressable unit to the B5500. This module manages the Electronic Units (EU)
* and Storage Units (SU) that make up the physical disk storage facility.
*
* Physical storage in this implementation is provided by a W3C IndexedDB
* Physical storage in this implementation is provided by a W3C IndexedDB
* database local to the browser in which the emulator is running. This database
* must have been previously initialized; see tools/B5500ColdLoader.html.
*
@@ -24,9 +24,9 @@
*
* Within an EU, segments are represented in the database as 240-byte Uint8Array
* objects, each with a database key corresponding to its numeric segment address.
* The segments are an EU are not pre-allocated, but are created as they are
* The segments are an EU are not pre-allocated, but are created as they are
* written to by IDB put() methods. When reading, any unallocated segments are
* returned with their bytes set to binary zero, which will be translated to
* returned with their bytes set to binary zero, which will be translated to
* BIC "?" by the IOU for both binary and alpha modes.
*
* At present, disk write lockout is not supported. When there are two DFCUs in
@@ -43,9 +43,9 @@
* and assumes the IOU does any necessary translation.
*
* The starting disk segment address for an I/O is passed in the "control"
* parameter to each of the I/O methods. This is an an alphanumeric value in
* parameter to each of the I/O methods. This is an an alphanumeric value in
* the B5500 memory and I/O Unit. The I/O unit translates this value to binary
* for the "control" parameter. The low-order six decimal digits of the value
* for the "control" parameter. The low-order six decimal digits of the value
* comprise the segment address within the EU. The seventh decimal digit is the
* EU number. Any other portion of the value is ignored.
*
@@ -54,12 +54,12 @@
* error reporting for the read check is deferred until the next I/O operation
* (typically an interrogate) against the unit. Therefore, the error mask is
* cleared at the end of each disk I/O operation (except for read check) instead
* of at the beginning, and new errors are OR-ed with any errors persisting from
* of at the beginning, and new errors are OR-ed with any errors persisting from
* the prior operation.
*
* This module attempts to simulate actual disk activity times by delaying the
* finish() call by an amount of time computed from the numbers of sectors
* requested and the Model I SU's average 96KC transfer rate, plus a random
* requested and the Model I SU's average 96KC transfer rate, plus a random
* distribution across its 40ms max rotational latency time.
************************************************************************
* 2013-01-19 P.Kimpel
@@ -76,7 +76,7 @@ function B5500DiskUnit(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();
}
@@ -94,14 +94,14 @@ B5500DiskUnit.prototype.clear = function() {
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.startStamp = null; // I/O starting timestamp
this.startStamp = null; // I/O starting timestamp
this.config = null; // copy of CONFIG store contents
this.disk = null; // the IDB database object
this.openDatabase(); // attempt to open the IDB database
};
@@ -121,13 +121,13 @@ B5500DiskUnit.prototype.copySegment = function(seg, buffer, offset) {
/* Copies the bytes from a single segment Uint8Array object to "buffer" starting
at "offset" for 240 bytes. If "seg" is undefined, copies zero bytes instead */
var x;
if (seg) {
for (x=0; x<240; x++) {
buffer[offset+x] = seg[x];
}
} else {
for (x=offset+239; x>=0; x--) {
for (x=offset+239; x>=offset; x--) {
buffer[x] = 0;
}
}
@@ -162,10 +162,10 @@ B5500DiskUnit.prototype.openDatabase = function() {
that.disk.onerror = function(ev) {
alert("Database for \"" + this.mnemonic + "\" open error: " + ev.target.result.error);
};
that.disk.transaction("CONFIG").objectStore("CONFIG").get(0).onsuccess = function(ev) {
that.config = ev.target.result;
that.statusChange(1); // report the DFCU as ready to Central Control
that.statusChange(1); // report the DFCU as ready to Central Control
// Set up the generic error handler
that.disk.onerror = function(ev) {
that.genericIDBError(ev);
@@ -192,7 +192,7 @@ B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
var euNumber = (control % 10000000 - segAddr)/1000000;
var euName = this.euPrefix + euNumber;
var endAddr = segAddr+segs-1; // ending seg address
euSize = this.config[euName];
if (!euSize) { // EU does not exist
finish(this.errorMask | 0x20, 0); // set D27F for EU not ready
@@ -207,16 +207,13 @@ B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
length = segs*240; // recompute length and ending seg address
endAddr = euSize-1;
}
finishTime = new Date().getTime() +
finishTime = new Date().getTime() +
(Math.random()*this.maxLatency + segs*240/this.charXferRate)*1000;
// No length specified, so just finish the I/O
if (segs < 1) {
finish(this.errorMask, 0);
if (segs < 1) { // No length specified, so just finish the I/O
finish(this.errorMask, 0);
this.errorMask = 0;
// A single-segment read
} else if (segs < 2) {
} else if (segs < 2) { // A single-segment read
req = this.disk.transaction(euName).objectStore(euName).get(segAddr);
req.onsuccess = function(ev) {
that.copySegment(ev.target.result, buffer, 0);
@@ -224,13 +221,11 @@ B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
finish(that.errorMask, length);
that.errorMask = 0;
}, finishTime - new Date().getTime());
};
// A multi-segment read
} else {
}
} else { // A multi-segment read
range = window.IDBKeyRange.bound(segAddr, endAddr);
txn = this.disk.transaction(euName);
req = txn.objectStore(euName).openCursor(range);
req.onsuccess = function(ev) {
var cursor = ev.target.result;
@@ -289,7 +284,7 @@ B5500DiskUnit.prototype.write = function(finish, buffer, length, mode, control)
var euNumber = (control % 10000000 - segAddr)/1000000;
var euName = this.euPrefix + euNumber;
var endAddr = segAddr+segs-1; // ending seg address
euSize = this.config[euName];
if (!euSize) { // EU does not exist
finish(this.errorMask | 0x20, 0); // set D27F for EU not ready
@@ -304,16 +299,16 @@ B5500DiskUnit.prototype.write = function(finish, buffer, length, mode, control)
length = segs*240; // recompute length and ending seg address
endAddr = euSize-1;
}
finishTime = new Date().getTime() +
finishTime = new Date().getTime() +
(Math.random()*this.maxLatency + segs*240/this.charXferRate)*1000;
// No length specified, so just finish the I/O
if (segs < 1) {
finish(this.errorMask, 0);
if (segs < 1) {
finish(this.errorMask, 0);
this.errorMask = 0;
// Do the write
} else {
} else {
txn = this.disk.transaction(euName, "readwrite")
txn.oncomplete = function(ev) {
setTimeout(function() {
@@ -333,21 +328,21 @@ B5500DiskUnit.prototype.write = function(finish, buffer, length, mode, control)
/**************************************/
B5500DiskUnit.prototype.erase = function(finish, length) {
/* Initiates an erase operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DiskUnit.prototype.rewind = function(finish) {
/* Initiates a rewind operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DiskUnit.prototype.readCheck = function(finish, length, control) {
/* Initiates a read check operation on the unit. "length" is in characters;
segment address is in "control". "mode" is ignored. This is essentially a
/* Initiates a read check operation on the unit. "length" is in characters;
segment address is in "control". "mode" is ignored. This is essentially a
read without any data transfer to memory. Note that the errorMask is NOT
zeroed at the end of the I/O -- it will be reported with the next I/O */
var euSize; // max seg size for EU
@@ -363,7 +358,7 @@ B5500DiskUnit.prototype.readCheck = function(finish, length, control) {
var euNumber = (control % 10000000 - segAddr)/1000000;
var euName = this.euPrefix + euNumber;
var endAddr = segAddr+segs-1; // ending seg address
this.errorMask = 0; // clear any prior error mask
euSize = this.config[euName];
if (!euSize) { // EU does not exist
@@ -379,19 +374,16 @@ B5500DiskUnit.prototype.readCheck = function(finish, length, control) {
length = segs*240; // recompute length and ending seg address
endAddr = euSize-1;
}
finishTime = new Date().getTime() +
finishTime = new Date().getTime() +
(Math.random()*this.maxLatency + segs*240/this.charXferRate)*1000;
// No length specified, so just finish the I/O
if (segs < 1) {
finish(this.errorMask, 0);
if (segs < 1) { // No length specified, so just finish the I/O
finish(this.errorMask, 0);
// DO NOT clear the error mask -- will return it on the next interrogate
// A multi-segment read
} else {
} else { // A multi-segment read
range = window.IDBKeyRange.bound(segAddr, endAddr);
txn = this.disk.transacation(euName);
req = txn.objectStore(euName).openCursor(range);
req.onsuccess = function(ev) {
var cursor = ev.target.result;
@@ -421,7 +413,7 @@ B5500DiskUnit.prototype.readInterrogate = function(finish, control) {
var euNumber = (control % 10000000 - segAddr)/1000000;
var euName = this.euPrefix + euNumber;
var that = this;
this.finish = finish; // for global error handler
euSize = this.config[euName];
if (!euSize) { // EU does not exist
@@ -445,16 +437,16 @@ B5500DiskUnit.prototype.writeInterrogate = function (finish, control) {
read check operation. This implementation assumes completion will be delayed
by a random amount of time based on rotational latency for the EU to search for
the address */
/* Note: until disk write lockout is implemented, this operation is identical
to readInterrogate() */
var euSize; // max seg size for EU
var segAddr = control % 1000000; // starting seg address
var euNumber = (control % 10000000 - segAddr)/1000000;
var euName = this.euPrefix + euNumber;
var that = this;
this.finish = finish; // for global error handler
euSize = this.config[euName];
if (!euSize) { // EU does not exist

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
f<!DOCTYPE html>
<head>
<title>B5500 Processor Syllable Debugger</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
@@ -941,7 +941,7 @@ function initialize() {
cc.P1.R = 0x005; // PRT at @500 (R has addr div 64)
cc.P1.C = 0x10; // execute from address @20
cc.P1.access(0x30); // P = [C]
cc.P1.loadPviaC();
cc.P1.T = cc.fieldIsolate(cc.P1.P, 0, 12);
cc.P1.TROF = 1;
cc.P1.L = 1; // point to the next instruction