From 15fc6c5a0b19aa67d9e5eecbce833016f216cbc3 Mon Sep 17 00:00:00 2001 From: "paul.kimpel@digm.com" Date: Mon, 27 May 2013 04:08:34 +0000 Subject: [PATCH] 1. Finalize and release emulator version 0.05. 2. Fix (we hope) the nasty problem that was causing Invalid Address out of COM5 after large compiles -- bug in MSCW/MSFF tracing in Processor.exitSubroutine(). 3. Implement ability to do a hardware load without initiating P1 in CentralControl (used by SyllableDebugger). 4. De-anonymize object prototype method functions in Processor as an aid when using JS debuggers. 5. Rework storeForInterrupt() and initiate() in Processor. 6. Replace bitmask "AND"s with power-of-two "MOD"s in many places in Processor. 7. Replace many bit(), fieldIsolate(), fieldInsert() calls with mod/div expressions in Processor. 8. Fix a problem existing normalization when an Integer Overflow occurs in Integer Store syllables. 9. Fix missing and superfluous break statements in Processor.run() switch statements. 10. Fix incorrect C-register restoration in Character Mode RCA syllable. 11. Correct test for continuity bit in Processor PRL syllable coding. 12. Correct missing "this." in Processor BRT syllable coding. 13. Change way that delayTime and Processor.procSlack is computed in Processor.run(). 14. Correct BCL translation bug and directory EOF detection in B5500ColdLoader. 15. Attempt to initialize SYSTEM/LOG in B5500ColdLoader (not working yet). 16. Implement new retro-B5500-Logo.png. 17. Implement Hardware Load button in SyllableDebugger. 18. Release tools/B5500DiskDirList.html utility. 19. Release tools/B5500DiskFileList.html utility with PBD file special formattring. 20. Restrict directory complement to EU0 in B5500ColdLoader.html. 21. Miscellaneous improvements to comments and cosmetics. --- SYMBOL/DCMCP.esp_m | 166 +++++++ emulator/B5500CentralControl.js | 49 +- emulator/B5500IOUnit.js | 4 +- emulator/B5500Processor.js | 366 +++++++-------- tools/B5500DiskDirList.html | 605 ++++++++++++++++++++++++ tools/B5500DiskFileList.html | 772 +++++++++++++++++++++++++++++++ tools/INCL2OMIT.alg_m | 2 + webUI/B5500ColdLoader.html | 75 ++- webUI/B5500Console.css | 4 + webUI/B5500Console.html | 18 +- webUI/B5500DiskUnit.js | 2 +- webUI/B5500SPOUnit.js | 2 +- webUI/B5500SyllableDebugger.html | 17 +- webUI/Burroughs-Meatball.png | Bin 0 -> 1387 bytes webUI/retro-B5500-Logo.png | Bin 0 -> 744 bytes 15 files changed, 1852 insertions(+), 230 deletions(-) create mode 100644 tools/B5500DiskDirList.html create mode 100644 tools/B5500DiskFileList.html create mode 100644 webUI/Burroughs-Meatball.png create mode 100644 webUI/retro-B5500-Logo.png diff --git a/SYMBOL/DCMCP.esp_m b/SYMBOL/DCMCP.esp_m index a62baa8..f5feb91 100644 --- a/SYMBOL/DCMCP.esp_m +++ b/SYMBOL/DCMCP.esp_m @@ -22886,3 +22886,169 @@ BEGIN REAL RCW=+0,MSCW=-2; 38001000 FPB[FNUM ]:=MFID:=FID; %126-38013030 FPB[FNUM+1]:=FID :=USERCODE[P1MIX]; %126-38013040 END; %126-38013050 + IF NFLAG(FIX[14]~FLAG(FILEHEADER(MFID 38013100 + $ SET OMIT = NOT SHAREDISK 38013199 + ,FID&FIB[5][1:45:1],FIB[8].[20:5] 38013300 + ,FIB[8].[25:23],BLEN,RLEN,STATE)))<6 THEN 38013400 + BEGIN P(DEL); 38013500 + TOG:= 1; 38013510 + $ SET OMIT = NOT SHAREDISK 38013519 + GO TO EXIT; 38013600 + END; 38013700 + IF FIB[8].[20:28]!0 THEN FPB[FNUM+2].[18:30]~DATE ELSE 38013900 + BEGIN% OLD FILE,VERIFY LABEL EQUATION DATE IF ANY 38014000 + HEADER := FIB[14];% 38014100 + STREAM(H:=HEADER[3].[30:18],B:=[T2]); 38014200 + BEGIN SI:=LOC H; DS:=8 DEC; END;% 38014300 + AGN: IF CDATE NEQ 0 AND CDATE NEQ HEADER[3].[30:18] THEN38014400 + BEGIN% WRITE DATE CHECK MESSAGE 38014500 + DOLITTLE(FALSE, 38014600 + VWY&VOF[36:42:6]&VOK[30:42:6], 38014610 + "#DAT CK"," =00000"&T2[18:18:30],MFID); 38014620 + IF TERMSET(P1MIX) THEN 38014700 + BEGIN 38014800 + FORGETSPACE(DIRECTORYSEARCH(MFID,FID, 38014900 + $ SET OMIT = NOT SHAREDISK 38014949 + FIB[5].[13:3]+10)); 38015000 + GO TO INITIATE; 38015100 + END;% 38015200 + IF P(NT6,DUP)=VOK OR P(XCH)=VOF THEN CDATE~0; 38015400 + GO AGN 38015500 + END;% VERIFICATION 38015600 + FPB[FNUM+2].[18:30]:=T2;% BCL DATE 38015700 + END OLD FILES;% 38015800 + STARTIMING(FNUM,18);% 38015900 + FPB:=PRT[P1MIX,3]; % STARTIMING MOVES THE FPB 38015950 + END;% 38016000 + HEADER~FIB[14];% 38020000 + KIND~4; U~18;% 38021000 + MODE~0;% 38022000 + IF NOT COBOL THEN UNLABELED~1;% 38023000 + CNTCTL~BLEN{1023;% 38024000 + $ SET OMIT = NOT SHAREDISK 38024004 + IF COBOL>0 AND (FIB[13].[22:1] OR TYPE=10 OR TYPE=26) THEN 38024100 + BEGIN COBOL:=3; %IF COBOL-IO OR COBOL-RANDOM 38024200 + BLEN := BLEN + RLEN; % THEN CHANGE BUFFSIZE TO 38024300 + END; % BUFFSIZE + RECSIZE 38024400 + GETBUFFERS((IF CNTCTL THEN BLEN% 38025000 + ELSE ((BLEN+29) DIV 30)|30)+1,% 38026000 + NBUFS,U,ALPHA);% 38027000 + IF COBOL = 3 THEN %IF COBOL-IO OR COBOL-RANDOM 38027100 + BEGIN COBOL := 1; % THEN CHANGE BUFFSIZE TO 38027200 + BLEN := BLEN - RLEN; % BUFFSIZE - RECSIZE 38027300 + END; % (SEE ABOVE 38027400 + FIB[16]~M[ALPHA]&CNTCTL[23:47:1]&10[24:47:1]% 38028000 + &((BLEN+29) DIV 30)[27:42:6]% 38029000 + &(IF CNTCTL THEN BLEN ELSE 1023)[8:38:10]% 38030000 + &TINU[18][3:3:5] OR M OR IOMASK;% 38031000 + FIB[16].[2:1]:=(HEADER.[31:2] AND (IO+1))!0; 38032000 + FIB[5].[1:1]:= NOT FIB[16].[2:1]; 38033000 + IF FIB[5].[1:1] THEN 38034000 + FOR MASK:=10 STEP 1 UNTIL 29 DO HEADER[MASK]:=0; 38035000 + FIB[19]~(IF DIREC THEN BLEN-RLEN+1 ELSE 1) 38036000 + INX FIB[16]&0[27:27:6]; 38037000 + IF STATE.[46:2]!0 THEN FIB[19].[8:10]~RLEN;% 38038000 + FS[P1MIX,(T2:=(FNUM DIV ETRLNG)).[40:4]]~(*P(DUP)) OR 38039000 + (TWO(0&T2[43:44:4])|((NOT HEADER).[31:2])); 38040000 + T2~IF COBOL THEN 0 ELSE FIB[19].[33:15]-FIB[16].[33:15]; 38041000 + FIB[10].[3:15]:=M[ALPHA]-2; %HEAD OF BUFFER RING 38041100 + FOR MASK~0 STEP 1 UNTIL NBUFS-1 DO% 38042000 + M[ALPHA+MASK]~(P(DUP,LOD)+T2)% 38043000 + &P(FLAG(FIB[19-ABS(3|COBOL)]),XCH)[CTC]; 38044000 + FIB[16]:=FIB[16] OR M; 38045000 + FIB[5].[45:1]~0; 38045100 + IF P([FIB[14]],LOD).[FF]=2 THEN FIB[5].[11:2]~1;%INPUT ONLY.38045105 + IF HEADER[4].[10:1] AND NOT IO THEN 38045110 + FILEMESS(-"CODE ","FILE ",MFID,FID,0,0,0); 38045120 + $ SET OMIT = NOT(PACKETS) 38045149 + IF PSEUDOMIX[P1MIX]!0 THEN 38045150 + IF NOT FIB[5].[41:1] THEN 38045155 + FILEMESSAGE((IF IO THEN " IN " ELSE "OUT") 38045160 + &TINU[U][6:30:18], IF ACCESS=0 THEN " SER " 38045200 + ELSE IF ACCESS=1 THEN IF TYPE=26 THEN " PRO " 38045300 + ELSE " RDM " ELSE " UPD ", 38045310 + MFID,FID,0,0,0,64); 38045400 + $ POP OMIT 38045501 + END DISKSETUP;% 38046000 + P(RCW,MSCW,STF); 38047000 + RCW:=RCW&P(XCH)[CTC]; 38048000 + DISKSETUP; 38049000 + IF COBOL<0 THEN % ADJUST UPPER BOUND FOR COBOL 68 38049200 + BEGIN MASK ~ (IF IO AND NOT FIB[13].[22:1] 38049300 + THEN HEADER[7] 38049400 + ELSE (((HEADER[9] | HEADER[1]) DIV 38049500 + HEADER[0].[42:6]) | HEADER[0].[30:12]) - 1);38049600 + IF FIB[3]=0 OR FIB[3]>MASK THEN FIB[3]~MASK; %LESSOR OF 2 EVILS38049700 + END; 38049800 + IF P(TYPE,DUP)=10 OR P(XCH)=26 THEN 38050000 + BEGIN 38051000 + IF COBOL<1 THEN % ALGOL OR COBOL 68 38052000 + FOR MASK ~ 0 STEP 1 UNTIL NBUFS-1 DO 38053000 + IF COBOL THEN M[M[ALPHA+MASK] INX NOT 2] ~ NOT 0 38053500 + ELSE M[ALPHA+MASK]~P(DUP,LOD)&1[27:47:1]; 38054000 + FIB[6]~FIB[7]~0;% 38055000 + FIB[17]~IF IO THEN 0 ELSE BLEN;% 38056000 + END ELSE 38057000 + BEGIN 38058000 + T2~(MFID~FIB[16).[33:15];% 38059000 + FIV7~FIB[7]; 38060000 + IF COBOL THEN% 38061000 + BEGIN IF COBOL>0 THEN 38062000 + IF NOT (FIB7=0 OR FIB[13].[22:1]) THEN 38062500 + BEGIN FIB7 ~ FIB7 - 1; 38063000 + OPTIONAL ~ NBUFS - 1; 38063500 + END ELSE OPTIONAL ~ NBUFS - 2 38064000 + ELSE BEGIN % COBOL 68 38064200 + OPTIONAL ~ NBUFS - 1; 38064400 + IF DIREC THEN FIB7 ~ FIB[7] ~ FIB[3]; 38064600 + END; 38065000 + FID~FIB[16];% 38066000 + MASK~0;% 38067000 + END ELSE% 38068000 + BEGIN OPTIONAL~NBUFS-1;% 38069000 + MASK~(FID~FIB[19]).[33:15]-T2;% 38070000 + END;% 38071000 + IF (STATE.[46:2]!0 AND NOT COBOL) OR IO THEN 38072000 + IF M[ALPHA].]2:1] THEN 38073000 + FOR T1~0 STEP 1 UNTIL OPTIONAL DO% 38074000 + BEGIN IF (M[T2]:= 38074500 + DISKADDRESS(FPB[FNUM], FPB[FNUM+1], FPB[FNUM+3], 38075000 + FORMS:=((HEADER[0].[30:12]|T1)&DIREC[1:47:1])+FIB7,38075500 + HEADER, IO&(NOT HEADER[4])[46:47:1])) > 1 THEN 38076000 + BEGIN 38076500 + IF (USERCODE[P1MIX] EQV MCP)!NOT 0 THEN 38077000 + IF P(M[MFID],DUP).[3:6]=0 AND 38077500 + P(XCH)>> 4) + 0x30 // @64-75: P1 syllable-dependent - : (p2 = this.P2) ? + : (p2 = this.P2) ? // Yes, Virginia, this should actually be an assignment... ( p2.I & 0x01 ? 0x20 // @40: P2 memory parity error : p2.I & 0x02 ? 0x21 // @41: P2 invalid address error : p2.I & 0x04 ? 0x22 // @42: P2 stack overflow @@ -690,7 +689,7 @@ B5500CentralControl.prototype.halt = function() { }; /**************************************/ -B5500CentralControl.prototype.loadComplete = function loadComplete() { +B5500CentralControl.prototype.loadComplete = function loadComplete(dontStart) { /* Monitors an initial load I/O operation for complete status. When complete, initiates P1 */ var completed = false; // true if some I/O Unit finished @@ -711,21 +710,25 @@ B5500CentralControl.prototype.loadComplete = function loadComplete() { completed = true; this.CCI11F = 0; this.AD4F = 0; - //} else { // Nothing finished yet (or there was an error) - // this.loadTimer = setTimeout(this.boundLoadComplete, 1000); } if (completed) { this.loadTimer = null; this.LOFF = 0; this.P1.preset(0x10); // start execution at C=@20 - this.P1.start(); // let'er rip + if (!dontStart) { + this.P1.start(); // let'er rip + } } }; /**************************************/ -B5500CentralControl.prototype.load = function() { - /* Initiates a Load operation to start the system */ +B5500CentralControl.prototype.load = function(dontStart) { + /* Initiates a Load operation to start the system. If "dontStart" is truthy, then + only the MCP bootstrap is loaded into memory -- P1 is not started */ + var boundLoadComplete = (function(that, dontStart) { + return function() {return that.loadComplete(dontStart)} + })(this, dontStart); if (this.P1 && !this.P1.busy) { this.clear(); @@ -734,18 +737,18 @@ B5500CentralControl.prototype.load = function() { this.LOFF = 1; if (this.IO1 && this.IO1.REMF && !this.AD1F) { this.AD1F = 1; - this.IO1.initiateLoad(this.cardLoadSelect, this.boundLoadComplete); + this.IO1.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else if (this.IO2 && this.IO2.REMF && !this.AD2F) { this.AD2F = 1; - this.IO2.initiateLoad(this.cardLoadSelect, this.boundLoadComplete); + this.IO2.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else if (this.IO3 && this.IO3.REMF && !this.AD3F) { this.AD3F = 1; - this.IO3.initiateLoad(this.cardLoadSelect, this.boundLoadComplete); + this.IO3.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else if (this.IO4 && this.IO4.REMF && !this.AD4F) { this.AD4F = 1; - this.IO4.initiateLoad(this.cardLoadSelect, this.boundLoadComplete); + this.IO4.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else { - this.CCI04F = 1; // set I/O busy interrupt + this.CCI04F = 1; // set I/O busy interrupt } } }; @@ -777,7 +780,7 @@ B5500CentralControl.prototype.loadTest = function(buf, loadAddr) { } if (!this.poweredUp) { - throw "cc.loadTest: Cannot load with system powered off" + throw "cc.loadTest: Cannot load with system powered off"; } else { while (bytes > 6) { word = data.getUint8(x)* 0x10000000000 + @@ -876,23 +879,23 @@ B5500CentralControl.prototype.configureSystem = function() { default: return function() {}; break; - }; + } } // ***** !! inhibit for now ***** // this.DD = new B5500DistributionAndDisplay(this); // Configure the processors - if (cfg.PA) {this.PA = new B5500Processor("A", this)}; - if (cfg.PB) {this.PB = new B5500Processor("B", this)}; + if (cfg.PA) {this.PA = new B5500Processor("A", this)} + if (cfg.PB) {this.PB = new B5500Processor("B", this)} // Determine P1/P2 this.PB1L = (cfg.PB1L ? 1 : 0); // Configure the I/O Units - if (cfg.IO1) {this.IO1 = new B5500IOUnit("1", this)}; - if (cfg.IO2) {this.IO2 = new B5500IOUnit("2", this)}; - if (cfg.IO3) {this.IO3 = new B5500IOUnit("3", this)}; - if (cfg.IO4) {this.IO4 = new B5500IOUnit("4", this)}; + if (cfg.IO1) {this.IO1 = new B5500IOUnit("1", this)} + if (cfg.IO2) {this.IO2 = new B5500IOUnit("2", this)} + if (cfg.IO3) {this.IO3 = new B5500IOUnit("3", this)} + if (cfg.IO4) {this.IO4 = new B5500IOUnit("4", this)} // Configure memory for (x=0; x<8; x++) { diff --git a/emulator/B5500IOUnit.js b/emulator/B5500IOUnit.js index 60ab67c..6555dcf 100644 --- a/emulator/B5500IOUnit.js +++ b/emulator/B5500IOUnit.js @@ -644,7 +644,7 @@ B5500IOUnit.prototype.initiateDiskIO = function(u) { } else { this.Daddress++; // bump memory address past the seg address word w = this.W; // convert address word to binary - for (x=0; x<7; x++) { + for (x=0; x<7; x++) { // 7 decimal digits: 1 for EU, 6 for EU-relative address c = w % 0x40; // get low-order six bits of word segAddr += (c % 0x10)*p; // isolate the numeric portion and accumulate w = (w-c)/0x40; // shift word right six bits @@ -716,7 +716,6 @@ B5500IOUnit.prototype.initiatePrinterIO = function(u) { /**************************************/ B5500IOUnit.prototype.forkIO = function forkIO() { /* Asynchronously initiates an I/O operation on this I/O Unit for a peripheral device */ - var addr; // memory address var chars; // I/O memory transfer length var index; // unit index var u; // peripheral unit object @@ -746,6 +745,7 @@ B5500IOUnit.prototype.forkIO = function forkIO() { } else { this.cc.setUnitBusy(index, 1); u = this.cc.unit[index]; + switch(this.Dunit) { // disk designates case 6: diff --git a/emulator/B5500Processor.js b/emulator/B5500Processor.js index 016ba87..364f49d 100644 --- a/emulator/B5500Processor.js +++ b/emulator/B5500Processor.js @@ -66,7 +66,7 @@ B5500Processor.collation = [ // index by BIC to get collation value 51, 52, 14, 15, 44, 16, 17, 18]; // @70: Y Z , % ! = ] " /**************************************/ -B5500Processor.prototype.clear = function() { +B5500Processor.prototype.clear = function clear() { /* Initializes (and if necessary, creates) the processor state */ this.A = 0; // Top-of-stack register A @@ -112,13 +112,14 @@ B5500Processor.prototype.clear = function() { this.cycleCount = 0; // Current cycle count for this.run() this.cycleLimit = 0; // Cycle limit for this.run() this.totalCycles = 0; // Total cycles executed on this processor - this.procTime = 0; // Total processor running time, based on cycles executed - this.procSlack = 0; // Total processor throttling delay, milliseconds + this.procStart = 0; // Javascript time that the processor started running, µs + this.procTime = 0; // Total processor running time, based on cycles executed, µs + this.procSlack = 0; // Total processor throttling delay, µs this.busy = 0; // Processor is running, not idle or halted }; /**************************************/ -B5500Processor.prototype.accessError = function() { +B5500Processor.prototype.accessError = function accessError() { /* Common error handling routine for all memory acccesses */ if (this.accessor.MAED) { @@ -135,7 +136,7 @@ B5500Processor.prototype.accessError = function() { }; /**************************************/ -B5500Processor.prototype.loadAviaS = function() { +B5500Processor.prototype.loadAviaS = function loadAviaS() { /* Load the A register from the address in S */ var acc = this.accessor; // get a local reference to the accessor object @@ -153,7 +154,7 @@ B5500Processor.prototype.loadAviaS = function() { }; /**************************************/ -B5500Processor.prototype.loadBviaS = function() { +B5500Processor.prototype.loadBviaS = function loadBviaS() { /* Load the B register from the address in S */ var acc = this.accessor; // get a local reference to the accessor object @@ -171,7 +172,7 @@ B5500Processor.prototype.loadBviaS = function() { }; /**************************************/ -B5500Processor.prototype.loadAviaM = function() { +B5500Processor.prototype.loadAviaM = function loadAviaM() { /* Load the A register from the address in M */ var acc = this.accessor; // get a local reference to the accessor object @@ -189,7 +190,7 @@ B5500Processor.prototype.loadAviaM = function() { }; /**************************************/ -B5500Processor.prototype.loadBviaM = function() { +B5500Processor.prototype.loadBviaM = function loadBviaM() { /* Load the B register from the address in M */ var acc = this.accessor; // get a local reference to the accessor object @@ -207,7 +208,7 @@ B5500Processor.prototype.loadBviaM = function() { }; /**************************************/ -B5500Processor.prototype.loadMviaM = function() { +B5500Processor.prototype.loadMviaM = function loadMviaM() { /* Load the M register from bits [18:15] of the word addressed by M */ var acc = this.accessor; // get a local reference to the accessor object @@ -219,12 +220,12 @@ B5500Processor.prototype.loadMviaM = function() { if (acc.MAED || acc.MPED) { this.accessError(); } else { - this.M = ((acc.word % 0x40000000) >>> 15) & 0x7FFF; + this.M = (acc.word % 0x40000000) >>> 15; } }; /**************************************/ -B5500Processor.prototype.loadPviaC = function() { +B5500Processor.prototype.loadPviaC = function loadPviaC() { /* Load the P register from the address in C */ var acc = this.accessor; // get a local reference to the accessor object @@ -242,7 +243,7 @@ B5500Processor.prototype.loadPviaC = function() { }; /**************************************/ -B5500Processor.prototype.storeAviaS = function() { +B5500Processor.prototype.storeAviaS = function storeAviaS() { /* Store the A register at the address in S */ var acc = this.accessor; // get a local reference to the accessor object @@ -258,7 +259,7 @@ B5500Processor.prototype.storeAviaS = function() { }; /**************************************/ -B5500Processor.prototype.storeBviaS = function() { +B5500Processor.prototype.storeBviaS = function storeBviaS() { /* Store the B register at the address in S */ var acc = this.accessor; // get a local reference to the accessor object @@ -274,7 +275,7 @@ B5500Processor.prototype.storeBviaS = function() { }; /**************************************/ -B5500Processor.prototype.storeAviaM = function() { +B5500Processor.prototype.storeAviaM = function storeAviaM() { /* Store the A register at the address in M */ var acc = this.accessor; // get a local reference to the accessor object @@ -290,7 +291,7 @@ B5500Processor.prototype.storeAviaM = function() { }; /**************************************/ -B5500Processor.prototype.storeBviaM = function() { +B5500Processor.prototype.storeBviaM = function storeBviaM() { /* Store the B register at the address in M */ var acc = this.accessor; // get a local reference to the accessor object @@ -306,7 +307,7 @@ B5500Processor.prototype.storeBviaM = function() { }; /**************************************/ -B5500Processor.prototype.adjustAEmpty = function() { +B5500Processor.prototype.adjustAEmpty = function adjustAEmpty() { /* Adjusts the A register so that it is empty, pushing the prior contents of A into B and B into memory, as necessary. */ @@ -328,7 +329,7 @@ B5500Processor.prototype.adjustAEmpty = function() { }; /**************************************/ -B5500Processor.prototype.adjustAFull = function() { +B5500Processor.prototype.adjustAFull = function adjustAFull() { /* Adjusts the A register so that it is full, popping the contents of B or [S] into A, as necessary. */ @@ -346,7 +347,7 @@ B5500Processor.prototype.adjustAFull = function() { }; /**************************************/ -B5500Processor.prototype.adjustBEmpty = function() { +B5500Processor.prototype.adjustBEmpty = function adjustBEmpty() { /* Adjusts the B register so that it is empty, pushing the prior contents of B into memory, as necessary. */ @@ -355,16 +356,16 @@ B5500Processor.prototype.adjustBEmpty = function() { this.I |= 0x04; // set I03F: stack overflow this.cc.signalInterrupt(); } else { - this.BROF = 0; this.S++; this.storeBviaS(); // [S] = B + this.BROF = 0; } // else we're done -- B is already empty } }; /**************************************/ -B5500Processor.prototype.adjustBFull = function() { +B5500Processor.prototype.adjustBFull = function adjustBFull() { /* Adjusts the B register so that it is full, popping the contents of [S] into B, as necessary. */ @@ -376,7 +377,7 @@ B5500Processor.prototype.adjustBFull = function() { }; /**************************************/ -B5500Processor.prototype.adjustABEmpty = function() { +B5500Processor.prototype.adjustABEmpty = function adjustABEmpty() { /* Adjusts the A and B registers so that both are empty, pushing the prior contents into memory, as necessary. */ @@ -403,7 +404,7 @@ B5500Processor.prototype.adjustABEmpty = function() { }; /**************************************/ -B5500Processor.prototype.adjustABFull = function() { +B5500Processor.prototype.adjustABFull = function adjustABFull() { /* Ensures both TOS registers are occupied, pushing up from memory as required */ if (this.AROF) { @@ -430,7 +431,7 @@ B5500Processor.prototype.adjustABFull = function() { }; /**************************************/ -B5500Processor.prototype.exchangeTOS = function() { +B5500Processor.prototype.exchangeTOS = function exchangeTOS() { /* Exchanges the two top-of-stack values */ var temp; @@ -463,7 +464,7 @@ B5500Processor.prototype.exchangeTOS = function() { }; /**************************************/ -B5500Processor.prototype.jumpSyllables = function(count) { +B5500Processor.prototype.jumpSyllables = function jumpSyllables(count) { /* Adjusts the C and L registers by "count" syllables (which may be negative). Forces a fetch to reload the P register after C and L are adjusted. On entry, C and L are assumed to be pointing to the next instruction @@ -477,14 +478,13 @@ B5500Processor.prototype.jumpSyllables = function(count) { }; /**************************************/ -B5500Processor.prototype.jumpWords = function(count) { +B5500Processor.prototype.jumpWords = function jumpWords(count) { /* Adjusts the C register by "count" words (which may be negative). L is set to zero. Forces a fetch to reload the P register after C and L are adjusted. On entry, C is assumed to be pointing to the CURRENT instruction word, i.e., Inhibit Fetch and Inhibit Count for Fetch have both been asserted. Any adjustment to C to account for the emulator's automatic C/L increment at SECL is the responsibility of the caller */ - var addr; this.C += count; this.L = 0; @@ -492,7 +492,7 @@ B5500Processor.prototype.jumpWords = function(count) { }; /**************************************/ -B5500Processor.prototype.jumpOutOfLoop = function(count) { +B5500Processor.prototype.jumpOutOfLoop = function jumpOutOfLoop(count) { /* Terminates the current character-mode loop by restoring the prior LCW (or RCW) from the stack to X. If "count" is not zero, adjusts C & L forward by that number of syllables and reloads P to branch to the jump-out location, @@ -512,7 +512,7 @@ B5500Processor.prototype.jumpOutOfLoop = function(count) { }; /**************************************/ -B5500Processor.prototype.streamAdjustSourceChar = function() { +B5500Processor.prototype.streamAdjustSourceChar = function streamAdjustSourceChar() { /* Adjusts the character-mode source pointer to the next character boundary, as necessary. If the adjustment crosses a word boundary, AROF is reset to force reloading later at the new source address */ @@ -530,7 +530,7 @@ B5500Processor.prototype.streamAdjustSourceChar = function() { }; /**************************************/ -B5500Processor.prototype.streamAdjustDestChar = function() { +B5500Processor.prototype.streamAdjustDestChar = function streamAdjustDestChar() { /* Adjusts the character-mode destination pointer to the next character boundary, as necessary. If the adjustment crosses a word boundary and BROF is set, B is stored at S before S is incremented and BROF is reset @@ -552,7 +552,7 @@ B5500Processor.prototype.streamAdjustDestChar = function() { }; /**************************************/ -B5500Processor.prototype.compareSourceWithDest = function(count) { +B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest(count) { /* Compares source characters to destination characters according to the processor collating sequence. "count" is the number of source characters to process. @@ -676,7 +676,7 @@ B5500Processor.prototype.compareSourceWithDest = function(count) { }; /**************************************/ -B5500Processor.prototype.fieldArithmetic = function(count, adding) { +B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, adding) { /* Handles the Field Add (FAD) or Field Subtract (FSU) syllables. "count" indicates the length of the fields to be operated upon. "adding" will be false if this call is for FSU, otherwise it's for FAD */ @@ -728,11 +728,11 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) { bBit = this.K*6; // B-bit number yd = (this.cc.fieldIsolate(this.A, aBit, 2) == 2 ? 2 : 0); // source sign zd = (this.cc.fieldIsolate(this.B, bBit, 2) == 2 ? 2 : 0); // dest sign - compl = (yd == zd ? !adding : adding ); // determine if complement needed + compl = (yd == zd ? !adding : adding); // determine if complement needed resultNegative = !( // determine sign of result (zd == 0 && !compl) || (zd == 0 && Q03F && !TFFF) || - (zd != 0 && compl && Q03F && TFFF ) || + (zd != 0 && compl && Q03F && TFFF) || (compl && !Q03F)); if (compl) { this.Q |= 0x42; // set Q07F and Q02F (for display only) @@ -821,7 +821,7 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) { }; /**************************************/ -B5500Processor.prototype.streamBitsToDest = function(count, mask) { +B5500Processor.prototype.streamBitsToDest = function streamBitsToDest(count, mask) { /* Streams a pattern of bits to the destination specified by S, K, and V, as supplied by the 48-bit "mask" argument. Partial words are filled from the low-order bits of the mask. Implements the guts of Character-Mode @@ -866,7 +866,7 @@ B5500Processor.prototype.streamBitsToDest = function(count, mask) { }; /**************************************/ -B5500Processor.prototype.streamProgramToDest = function(count) { +B5500Processor.prototype.streamProgramToDest = function streamProgramToDest(count) { /* Implements the TRP (Transfer Program Characters) character-mode syllable */ var bBit; // B register bit nr var bw; // current B register value @@ -889,7 +889,7 @@ B5500Processor.prototype.streamProgramToDest = function(count) { bw = this.B; do { c = this.cc.fieldIsolate(pw, pBit, 6); - bw = this.cc.fieldInsert(bw, bBit, 6, c) + bw = this.cc.fieldInsert(bw, bBit, 6, c); count--; if (bBit < 42) { bBit += 6; @@ -926,7 +926,7 @@ B5500Processor.prototype.streamProgramToDest = function(count) { }; /**************************************/ -B5500Processor.prototype.streamSourceToDest = function(count, transform) { +B5500Processor.prototype.streamSourceToDest = function streamSourceToDest(count, transform) { /* General driver for character-mode character transfers from source to destination, such as TRS or TRZ. "count" is the number of source characters to transfer. @@ -988,7 +988,7 @@ B5500Processor.prototype.streamSourceToDest = function(count, transform) { }; /**************************************/ -B5500Processor.prototype.streamToDest = function(count, transform) { +B5500Processor.prototype.streamToDest = function streamToDest(count, transform) { /* General driver for character-mode character operations on the destination from a non-A register source, such as TBN. "count" is the number of characters to transfer. @@ -1029,7 +1029,7 @@ B5500Processor.prototype.streamToDest = function(count, transform) { }; /**************************************/ -B5500Processor.prototype.streamInputConvert = function(count) { +B5500Processor.prototype.streamInputConvert = function streamInputConvert(count) { /* Converts a signed-numeric character field at the source M & G address from decimal to binary, storing the resulting word at the S address and then incrementing S. Normally, decimal to binary conversion shouldn't be this @@ -1113,7 +1113,7 @@ B5500Processor.prototype.streamInputConvert = function(count) { }; /**************************************/ -B5500Processor.prototype.streamOutputConvert = function(count) { +B5500Processor.prototype.streamOutputConvert = function streamOutputConvert(count) { /* Converts the binary word addressed by M (after word-boundary adjustment) to decimal BIC at the destination address of S & K. The maximum number of digits to convert is 8. If the binary value can be represented in "count" @@ -1185,7 +1185,7 @@ B5500Processor.prototype.streamOutputConvert = function(count) { }; /**************************************/ -B5500Processor.prototype.storeForInterrupt = function(forTest) { +B5500Processor.prototype.storeForInterrupt = function storeForInterrupt(forTest) { /* Implements the 3011=SFI operator and the parts of 3411=SFT that are common to it. "forTest" implies use from SFT */ var forced = this.Q & 0x40; // Q07F: Hardware-induced SFI syllable @@ -1200,31 +1200,33 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) { if (this.CWMF) { temp = this.S; // if CM, get the correct TOS address from X this.S = (this.X % 0x40000000) >>> 15; - this.X = this.cc.fieldInsert(this.X, 18, 15, temp); - if (this.AROF || forTest) { + this.X = this.X % 0x8000 + + temp * 0x8000 + + (this.X - this.X % 0x40000000); + if (saveAROF || forTest) { this.S++; this.storeAviaS(); // [S] = A } - if (this.BROF || forTest) { + if (saveBROF || forTest) { this.S++; this.storeBviaS(); // [S] = B } - this.B = this.X + // store CM loop-control word + this.B = this.X + // store CM Interrupt Loop-Control Word (ILCW) saveAROF * 0x200000000000 + 0xC00000000000; this.S++; this.storeBviaS(); // [S] = B } else { - if (this.BROF || forTest) { + if (saveBROF || forTest) { this.S++; this.storeBviaS(); // [S] = B } - if (this.AROF || forTest) { + if (saveAROF || forTest) { this.S++; this.storeAviaS(); // [S] = A } } - this.B = this.M + // store interrupt control word (ICW) + this.B = this.M + // store Interrupt Control Word (ICW) this.N * 0x8000 + this.VARF * 0x1000000 + this.SALF * 0x40000000 + @@ -1234,7 +1236,7 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) { this.S++; this.storeBviaS(); // [S] = B - this.B = this.C + // store interrupt return control word (IRCW) + this.B = this.C + // store Interrupt Return Control Word (IRCW) this.F * 0x8000 + this.K * 0x40000000 + this.G * 0x200000000 + @@ -1251,20 +1253,20 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) { this.F = this.S; this.S = temp; this.loadBviaS(); // B = [S]: get last RCW - this.S = ((this.B % 0x40000000) >>> 15) & 0x7FFF; + this.S = (this.B % 0x40000000) >>> 15; this.loadBviaS(); // B = [S]: get last MSCW - this.R = this.cc.fieldIsolate(this.B, 6, 9); + this.R = (this.B % 0x40000000000 - this.B % 0x200000000)/0x200000000; // B.[6:9] this.S = this.F; } - this.B = this.S + // store the initiate control word (INCW) + this.B = this.S + // build the Initiate Control Word (INCW) this.CWMF * 0x8000 + + (this.TM & 0x1F) * 0x10000 + + this.Z * 0x400000 + + this.Y * 0x10000000 + + (this.Q & 0x1FF) * 0x400000000 + 0xC00000000000; if (forTest) { - this.B += (this.TM & 0x1F) * 0x10000 + - this.Z * 0x400000 + - this.Y * 0x10000000 + - (this.Q & 0x1FF) * 0x400000000; this.TM = 0; this.MROF = 0; this.MWOF = 0; @@ -1300,7 +1302,7 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) { this.CWMF = 0; if (this === this.cc.P1) { this.loadBviaM(); // B = [M]: load DD for test - this.C = this.B % 0x7FFF; + this.C = this.B % 0x8000; this.L = 0; this.PROF = 0; // require fetch at SECL this.G = 0; @@ -1324,7 +1326,7 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) { }; /**************************************/ -B5500Processor.prototype.preset = function(runAddr) { +B5500Processor.prototype.preset = function preset(runAddr) { /* Presets the processor registers for a load condition at C=runAddr */ this.C = runAddr; // starting execution address @@ -1338,68 +1340,74 @@ B5500Processor.prototype.preset = function(runAddr) { }; /**************************************/ -B5500Processor.prototype.start = function() { +B5500Processor.prototype.start = function start() { /* Initiates the processor by scheduling it on the Javascript thread */ this.busy = 1; - this.procTime = new Date().getTime()*1000; + this.procTime = this.procStart = new Date().getTime()*1000; this.scheduler = setTimeout(this.boundSchedule, 0); }; /**************************************/ -B5500Processor.prototype.initiate = function(forTest) { +B5500Processor.prototype.initiate = function initiate(forTest) { /* Initiates the processor from interrupt control words stored in the stack. Assumes the INCW is in A. "forTest" implies use from IFT */ + var aw = this.A; // local copy of A + var bw; // local copy of B var saveAROF = 0; var saveBROF = 0; var temp; - // restore the Initiate Control Word or Initiate Test Control Word - this.S = this.A % 0x8000; - this.CWMF = (this.A % 0x10000) >>> 15; + // restore the Initiate Control Word (INCW) or Initiate Test Control Word + this.S = aw % 0x8000; + this.CWMF = (aw % 0x10000) >>> 15; if (forTest) { - this.TM = Math.floor(this.A / 0x10000) % 0x20; - this.Z = Math.floor(this.A / 0x400000) % 0x40; - this.Y = Math.floor(this.A / 0x10000000) % 0x40; - this.Q = Math.floor(this.A / 0x400000000) % 0x200; - this.TM |= Math.floor(this.A / 0x200000) % 0x02 * 32; // CCCF - this.TM |= Math.floor(this.A / 0x80000000000) % 0x02 * 64; // MWOF - this.TM |= Math.floor(this.A / 0x400000000000) % 0x02 * 128; // MROF + this.TM = (aw % 0x100000 - aw % 0x10000)/0x10000 + + (aw % 0x200000 - aw % 0x100000)/0x100000 * 16 + // NCSF + (aw % 0x400000 - aw % 0x200000)/0x200000 * 32 + // CCCF + (aw % 0x100000000000 - aw % 0x80000000000)/0x80000000000 * 64 + // MWOF + (aw % 0x400000000000 - aw % 0x200000000000)/0x200000000000 * 128; // MROF + this.Z = (aw % 0x10000000 - aw % 0x400000)/0x400000; + this.Y = (aw % 0x400000000 - aw % 0x10000000)/0x10000000; + this.Q = (aw % 0x80000000000 - aw % 0x400000000)/0x400000000; // Emulator doesn't support J register, so can't set that from TM } - // restore the Interrupt Return Control Word + // restore the Interrupt Return Control Word (IRCW) this.loadBviaS(); // B = [S] this.S--; - this.C = this.B % 0x8000; - this.F = Math.floor(this.B / 0x8000) % 0x8000; - this.K = Math.floor(this.B / 0x40000000) % 0x08; - this.G = Math.floor(this.B / 0x200000000) % 0x08; - this.L = Math.floor(this.B / 0x1000000000) % 0x04; - this.V = Math.floor(this.B / 0x4000000000) % 0x08; - this.H = Math.floor(this.B / 0x20000000000) % 0x08; + bw = this.B; + this.C = bw % 0x8000; + this.F = (bw % 0x40000000) >>> 15; + this.K = (bw % 0x200000000 - bw % 0x40000000)/0x40000000; + this.G = (bw % 0x1000000000 - bw % 0x200000000)/0x200000000; + this.L = (bw % 0x4000000000 - bw % 0x1000000000)/0x1000000000; + this.V = (bw % 0x20000000000 - bw % 0x4000000000)/0x4000000000; + this.H = (bw % 0x100000000000 - bw % 0x20000000000)/0x20000000000; this.loadPviaC(); // load program word to P if (this.CWMF || forTest) { - saveBROF = Math.floor(this.B / 0x200000000000) % 0x02; + saveBROF = (bw % 0x400000000000 - bw % 0x200000000000)/0x200000000000; } - // restore the Interrupt Control Word + // restore the Interrupt Control Word (ICW) this.loadBviaS(); // B = [S] this.S--; - this.VARF = Math.floor(this.B / 0x1000000) % 0x02; - this.SALF = Math.floor(this.B / 0x40000000) % 0x02; - this.MSFF = Math.floor(this.B / 0x80000000) % 0x02; - this.R = (Math.floor(this.B / 0x200000000) % 0x200); + bw = this.B; + this.VARF = (bw % 0x2000000 - bw % 0x1000000)/0x1000000; + this.SALF = (bw % 0x80000000 - bw % 0x40000000)/0x40000000; + this.MSFF = (bw % 0x100000000 - bw % 0x80000000)/0x80000000; + this.R = (bw % 0x40000000000 - bw % 0x200000000)/0x200000000; if (this.CWMF || forTest) { - this.M = this.B % 0x8000; - this.N = Math.floor(this.B / 0x8000) % 0x10; + this.M = bw % 0x8000; + this.N = (bw % 0x80000 - bw % 0x8000)/0x8000; - // restore the CM Interrupt Loop Control Word + // restore the CM Interrupt Loop Control Word (ILCW) this.loadBviaS(); // B = [S] this.S--; - this.X = this.B % 0x8000000000; - saveAROF = Math.floor(this.B / 0x400000000000) % 0x02; + bw = this.B; + this.X = bw % 0x8000000000; + saveAROF = (bw % 0x400000000000 - bw % 0x200000000000)/0x200000000000; // restore the B register if (saveBROF || forTest) { @@ -1421,7 +1429,7 @@ B5500Processor.prototype.initiate = function(forTest) { this.S = (this.X % 0x40000000) >>> 15; this.X = this.X % 0x8000 + temp * 0x8000 + - Math.floor(this.X / 0x40000000) * 0x40000000; + (this.X - this.X % 0x40000000); } } else { // don't restore A or B for word mode -- will pop up as necessary this.AROF = 0; @@ -1446,7 +1454,7 @@ B5500Processor.prototype.initiate = function(forTest) { }; /**************************************/ -B5500Processor.prototype.initiateAsP2 = function() { +B5500Processor.prototype.initiateAsP2 = function initiateAsP2() { /* Called from Central Control to initiate the processor as P2. Fetches the INCW from @10 and calls initiate() */ @@ -1458,12 +1466,11 @@ B5500Processor.prototype.initiateAsP2 = function() { this.NCSF = 0; // make sure P2 is in control state // Now start scheduling P2 on the Javascript thread - this.procTime = new Date().getTime()*1000; - this.scheduler = setTimeout(this.boundSchedule, 0); + this.start(); }; /**************************************/ -B5500Processor.prototype.singlePrecisionCompare = function() { +B5500Processor.prototype.singlePrecisionCompare = function singlePrecisionCompare() { /* Algebraically compares the B register to the A register. Function returns -1 if BA. Exits with AROF=0, BROF=1, and A and B as is */ var ea; // signed exponent of A @@ -1531,7 +1538,7 @@ B5500Processor.prototype.singlePrecisionCompare = function() { }; /**************************************/ -B5500Processor.prototype.singlePrecisionAdd = function(adding) { +B5500Processor.prototype.singlePrecisionAdd = function singlePrecisionAdd(adding) { /* Adds the contents of the A register to the B register, leaving the result in B and invalidating A. If "adding" is not true, the sign of A is complemented to accomplish subtraction instead of addition */ @@ -1669,7 +1676,7 @@ B5500Processor.prototype.singlePrecisionAdd = function(adding) { }; /**************************************/ -B5500Processor.prototype.singlePrecisionMultiply = function() { +B5500Processor.prototype.singlePrecisionMultiply = function singlePrecisionMultiply() { /* Multiplies the contents of the A register to the B register, leaving the result in B and invalidating A. A double-precision mantissa is developed and then normalized and rounded */ @@ -1765,7 +1772,7 @@ B5500Processor.prototype.singlePrecisionMultiply = function() { this.A = 0; // required by specs due to the way rounding addition worked if (xx >= 0x4000000000) { // if high-order bit of remaining extension is 1 - this.Q |= 0x01 // set Q01F (for display purposes only) + this.Q |= 0x01; // set Q01F (for display purposes only) if (mb < 0x7FFFFFFFFF) { // if the rounding would not cause overflow this.cycleCount++; mb++; // round up the result @@ -1799,7 +1806,7 @@ B5500Processor.prototype.singlePrecisionMultiply = function() { }; /**************************************/ -B5500Processor.prototype.singlePrecisionDivide = function() { +B5500Processor.prototype.singlePrecisionDivide = function singlePrecisionDivide() { /* Divides the contents of the A register into the B register, leaving the result in B and invalidating A. A 14-octade mantissa is developed and then normalized and rounded */ @@ -1875,7 +1882,7 @@ B5500Processor.prototype.singlePrecisionDivide = function() { // Round the result (it's already normalized) this.A = 0; // required by specs due to the way rounding addition worked if (q >= 4) { // if high-order bit of last quotient digit is 1 - this.Q |= 0x01 // set Q01F (for display purposes only) + this.Q |= 0x01; // set Q01F (for display purposes only) if (xx < 0x7FFFFFFFFF) { // if the rounding would not cause overflow xx++; // round up the result } @@ -1904,7 +1911,7 @@ B5500Processor.prototype.singlePrecisionDivide = function() { }; /**************************************/ -B5500Processor.prototype.integerDivide = function() { +B5500Processor.prototype.integerDivide = function integerDivide() { /* Divides the contents of the A register into the B register, leaving the integerized result in B and invalidating A. If the result cannot be expressed as an integer, the Integer-Overflow interrupt is set */ @@ -2003,7 +2010,7 @@ B5500Processor.prototype.integerDivide = function() { }; /**************************************/ -B5500Processor.prototype.remainderDivide = function() { +B5500Processor.prototype.remainderDivide = function remainderDivide() { /* Divides the contents of the A register into the B register, leaving the remainder result in B and invalidating A. The sign of the result is the sign of the dividend (B register value). If the quotient cannot be expressed as an @@ -2112,7 +2119,7 @@ B5500Processor.prototype.remainderDivide = function() { }; /**************************************/ -B5500Processor.prototype.doublePrecisionAdd = function(adding) { +B5500Processor.prototype.doublePrecisionAdd = function doublePrecisionAdd(adding) { /* Adds the double-precision contents of the A and B registers to the double- precision contents of the top two words in the memory stack, leaving the result in A and B. If "adding" is not true, the sign of A is complemented to accomplish @@ -2301,7 +2308,7 @@ B5500Processor.prototype.doublePrecisionAdd = function(adding) { }; /**************************************/ -B5500Processor.prototype.computeRelativeAddr = function(offset, cEnabled) { +B5500Processor.prototype.computeRelativeAddr = function computeRelativeAddr(offset, cEnabled) { /* Computes an absolute memory address from the relative "offset" parameter and leaves it in the M register. See Table 6-1 in the B5500 Reference Manual. "cEnable" determines whether C-relative addressing is permitted. @@ -2309,42 +2316,42 @@ B5500Processor.prototype.computeRelativeAddr = function(offset, cEnabled) { if (this.SALF) { this.cycleCount += 2; // approximate the timing - switch (offset >>> 7) { + switch ((offset % 0x400) >>> 7) { case 0: case 1: case 2: case 3: - this.M = this.R*64 + (offset & 0x1FF); + this.M = this.R*64 + (offset % 0x200); break; case 4: case 5: if (this.MSFF) { this.M = this.R*64 + 7; this.loadMviaM(); // M = [M].[18:15] - this.M += (offset & 0xFF); + this.M += (offset % 0x100); } else { - this.M = this.F + (offset & 0xFF); + this.M = this.F + (offset % 0x100); } break; case 6: if (cEnabled) { - this.M = (this.L ? this.C : this.C-1) + (offset & 0x7F); // adjust C for fetch + this.M = (this.L ? this.C : this.C-1) + (offset % 0x80); // adjust C for fetch } else { - this.M = this.R*64 + (offset & 0x7F); + this.M = this.R*64 + (offset % 0x80); } break; case 7: if (this.MSFF) { this.M = this.R*64 + 7; this.loadMviaM(); // M = [M].[18:15] - this.M -= (offset & 0x7F); + this.M -= (offset % 0x80); } else { - this.M = this.F - (offset & 0x7F); + this.M = this.F - (offset % 0x80); } break; } // switch } else { - this.M = this.R*64 + (offset & 0x3FF); + this.M = this.R*64 + (offset % 0x400); } // Reset variant-mode R-relative addressing, if enabled @@ -2355,7 +2362,7 @@ B5500Processor.prototype.computeRelativeAddr = function(offset, cEnabled) { }; /**************************************/ -B5500Processor.prototype.presenceTest = function(word) { +B5500Processor.prototype.presenceTest = function presenceTest(word) { /* Tests and returns the presence bit [2:1] of the "word" parameter. If 0, the p-bit interrupt is set; otherwise no further action */ @@ -2371,7 +2378,7 @@ B5500Processor.prototype.presenceTest = function(word) { }; /**************************************/ -B5500Processor.prototype.indexDescriptor = function() { +B5500Processor.prototype.indexDescriptor = function indexDescriptor() { /* Indexes a descriptor and, if successful leaves the indexed value in the A register. Returns 1 if an interrupt is set and the syllable is to be exited */ @@ -2411,7 +2418,7 @@ B5500Processor.prototype.indexDescriptor = function() { xe = 0; // kill the loop interrupted = 1; if (this.NCSF) { - this.I = (this.I & 0x0F) | 0xC0; // set I07/8: int-overflow + this.I = (this.I & 0x0F) | 0xC0; // set I07/8: integer overflow this.cc.signalInterrupt(); } } @@ -2426,7 +2433,7 @@ B5500Processor.prototype.indexDescriptor = function() { this.I = (this.I & 0x0F) | 0x90; // set I05/8: invalid-index this.cc.signalInterrupt(); } - } else if (xm % 0x0400 >= this.cc.fieldIsolate(aw, 8, 10)) { + } else if (xm % 0x0400 >= (aw % 0x10000000000 - aw % 0x40000000)/0x40000000) { interrupted = 1; // oops... index out of bounds if (this.NCSF) { this.I = (this.I & 0x0F) | 0x90; // set I05/8: invalid-index @@ -2442,7 +2449,7 @@ B5500Processor.prototype.indexDescriptor = function() { }; /**************************************/ -B5500Processor.prototype.integerStore = function(conditional, destructive) { +B5500Processor.prototype.integerStore = function integerStore(conditional, destructive) { /* Store the value in the B register at the address in the A register (relative or descriptor) and marks the A register empty. "conditional" indicates that integerization is conditional on the type of word in A, and if a descriptor, @@ -2492,7 +2499,7 @@ B5500Processor.prototype.integerStore = function(conditional, destructive) { if (bs ? bo > 4 : bo >= 4) { bm++; // round the B mantissa } - } else if (be > 0) { // B exponent is positive + } else { // B exponent is positive and not zero do { this.cycleCount++; if (bm < 0x1000000000) { @@ -2500,10 +2507,10 @@ B5500Processor.prototype.integerStore = function(conditional, destructive) { } else { // oops... integer overflow normalizing the mantisa doStore = 0; if (this.NCSF) { - this.I = (this.I & 0x0F) | 0xC0; // set I07/8: int-overflow + this.I = (this.I & 0x0F) | 0xC0; // set I07/8: integer overflow this.cc.signalInterrupt(); - break; // kill the loop } + break; // kill the loop } } while (--be > 0); } @@ -2511,20 +2518,19 @@ B5500Processor.prototype.integerStore = function(conditional, destructive) { this.B = bs*0x400000000000 + bm; } } - } if (doStore) { this.storeBviaM(); this.AROF = 0; if (destructive) { - this.BROF = 0 + this.BROF = 0; } } }; /**************************************/ -B5500Processor.prototype.buildMSCW = function() { +B5500Processor.prototype.buildMSCW = function buildMSCW() { /* Return a Mark Stack Control Word from current processor state */ return this.F * 0x8000 + @@ -2535,7 +2541,7 @@ B5500Processor.prototype.buildMSCW = function() { }; /**************************************/ -B5500Processor.prototype.applyMSCW = function(word) { +B5500Processor.prototype.applyMSCW = function applyMSCW(word) { /* Set processor state from fields of the Mark Stack Control Word in the "word" parameter */ var f; @@ -2552,7 +2558,7 @@ B5500Processor.prototype.applyMSCW = function(word) { }; /**************************************/ -B5500Processor.prototype.buildRCW = function(descriptorCall) { +B5500Processor.prototype.buildRCW = function buildRCW(descriptorCall) { /* Return a Return Control Word from the current processor state */ return this.C + @@ -2566,7 +2572,7 @@ B5500Processor.prototype.buildRCW = function(descriptorCall) { }; /**************************************/ -B5500Processor.prototype.applyRCW = function(word, inline) { +B5500Processor.prototype.applyRCW = function applyRCW(word, inline) { /* Set processor state from fields of the Return Control Word in the "word" parameter. If "inline" is truthy, C & L are NOT restored from the RCW. Returns the state of the OPDC/DESC bit [2:1] */ @@ -2597,7 +2603,7 @@ B5500Processor.prototype.applyRCW = function(word, inline) { }; /**************************************/ -B5500Processor.prototype.enterCharModeInline = function() { +B5500Processor.prototype.enterCharModeInline = function enterCharModeInline() { /* Implements the 4441=CMN syllable */ var bw; // local copy of B reg @@ -2632,17 +2638,19 @@ B5500Processor.prototype.enterCharModeInline = function() { }; /**************************************/ -B5500Processor.prototype.enterSubroutine = function(descriptorCall) { +B5500Processor.prototype.enterSubroutine = function enterSubroutine(descriptorCall) { /* Enters a subroutine via the present Program Descriptor in A as part of an OPDC or DESC syllable. Also handles accidental entry */ var aw = this.A; // local copy of word in A reg - var arg = this.cc.bit(aw, 5); // descriptor argument bit - var mode = this.cc.bit(aw, 4); // descriptor mode bit (1=char mode) + var arg = (aw % 0x100000000000 - aw % 0x40000000000)/0x40000000000; // aw.[4:2] + var mode = arg >>> 1; // descriptor mode bit (aw.[4:1], 1=char mode) + + arg &= 0x01; // descriptor argument bit (aw.[5:1]) if (arg && !this.MSFF) { - ; // just leave the Program Descriptor on TOS + // just leave the Program Descriptor on TOS } else if (mode && !arg) { - ; // ditto + // ditto } else { // Now we are really going to enter the subroutine this.adjustBEmpty(); @@ -2668,7 +2676,7 @@ B5500Processor.prototype.enterSubroutine = function(descriptorCall) { if (arg) { this.F = this.S; } else { - this.F = this.cc.fieldIsolate(aw, 18, 15); + this.F = (aw % 0x40000000) >>> 15; // aw.[18:15] } this.AROF = 0; this.BROF = 0; @@ -2684,7 +2692,7 @@ B5500Processor.prototype.enterSubroutine = function(descriptorCall) { }; /**************************************/ -B5500Processor.prototype.exitSubroutine = function(inline) { +B5500Processor.prototype.exitSubroutine = function exitSubroutine(inline) { /* Exits a subroutine by restoring the processor state from RCW and MSCW words in the stack. "inline" indicates the C & L registers are NOT restored from the RCW. The RCW is assumed to be in the B register, pointing to the MSCW. @@ -2718,7 +2726,7 @@ B5500Processor.prototype.exitSubroutine = function(inline) { do { this.S = (this.B % 0x40000000) >>> 15; this.loadBviaS(); // B = [S], fetch prior MSCW - } while (((this.B - this.B % 0x40000000)/0x40000000) % 4 == 3); // MSFF & SALF + } while ((this.B % 0x100000000 - this.B % 0x80000000)/0x80000000 == 1); // MSFF this.S = this.R*64 + 7; this.storeBviaS(); // [S] = B, store last MSCW at [R]+7 } @@ -2729,7 +2737,7 @@ B5500Processor.prototype.exitSubroutine = function(inline) { }; /**************************************/ -B5500Processor.prototype.operandCall = function() { +B5500Processor.prototype.operandCall = function operandCall() { /* OPDC, the moral equivalent of "load accumulator" on lesser machines. Assumes the syllable has already loaded a word into A. See Figures 6-1, 6-3, and 6-4 in the B5500 Reference Manual */ @@ -2738,11 +2746,11 @@ B5500Processor.prototype.operandCall = function() { if (aw >= 0x800000000000) { // It's not a simple operand - switch (this.cc.fieldIsolate(aw, 1, 3)) { + switch ((aw % 0x800000000000 - aw % 0x100000000000)/0x100000000000) { // aw.[1:3] case 2: case 3: // Present data descriptor - if (this.cc.fieldIsolate(aw, 8, 10)) { + if ((aw % 0x10000000000 - aw % 0x40000000)/0x40000000) { // aw.[8:10] interrupted = this.indexDescriptor(); // else descriptor is already indexed (word count 0) } @@ -2781,7 +2789,7 @@ B5500Processor.prototype.operandCall = function() { }; /**************************************/ -B5500Processor.prototype.descriptorCall = function() { +B5500Processor.prototype.descriptorCall = function descriptorCall() { /* DESC, the moral equivalent of "load address" on lesser machines. Assumes the syllable has already loaded a word into A, and that the address of that word is in M. @@ -2794,11 +2802,11 @@ B5500Processor.prototype.descriptorCall = function() { this.A = this.M + 0xA00000000000; } else { // It's not a simple operand - switch (this.cc.fieldIsolate(aw, 1, 3)) { + switch ((aw % 0x800000000000 - aw % 0x100000000000)/0x100000000000) { // aw.[1:3] case 2: case 3: // Present data descriptor - if (this.cc.fieldIsolate(aw, 8, 10)) { + if ((aw % 0x10000000000 - aw % 0x40000000)/0x40000000) { // aw.[8:10] interrupted = this.indexDescriptor(); this.A = this.cc.fieldInsert(this.A, 8, 10, 0); // set word count to zero // else descriptor is already indexed (word count 0) @@ -2830,7 +2838,7 @@ B5500Processor.prototype.descriptorCall = function() { }; /**************************************/ -B5500Processor.prototype.run = function() { +B5500Processor.prototype.run = function run() { /* Instruction execution driver for the B5500 processor. This function is an artifact of the emulator design and does not represent any physical process or state of the processor. This routine assumes the registers are @@ -2866,7 +2874,7 @@ B5500Processor.prototype.run = function() { } this.S = this.F; this.loadBviaS(); // B = [S], fetch the RCW - this.exitSubroutine(variant & 0x01);// exit vs. exit inline + this.exitSubroutine(variant & 0x01);// 0=exit, 1=exit inline this.AROF = this.BROF = 0; this.X = this.M = this.N = 0; this.CWMF = 0; @@ -3006,6 +3014,7 @@ B5500Processor.prototype.run = function() { default: // Anything else is a no-op break; } // end switch for XX11 ops + break; case 0x0A: // XX12: TBN=Transfer blank for numeric this.MSFF = 1; // initialize true-false FF @@ -3077,7 +3086,6 @@ B5500Processor.prototype.run = function() { this.S = t1 >>> 3; this.K = t1 & 0x07; break; - break; case 0x12: // XX22: SES=Set source address this.cycleCount += variant; @@ -3292,14 +3300,15 @@ B5500Processor.prototype.run = function() { this.S = this.F - variant; this.loadBviaS(); // B = [S] this.S = t1; - this.C = this.B % 0x8000; if (this.B >= 0x800000000000) { // if it's a descriptor, - this.L = 0; // force L to zero and if (this.presenceTest(this.B)) {// if present, initiate a fetch to P + this.C = this.B % 0x8000; // get the word address, + this.L = 0; // force L to zero and this.PROF = 0; // require fetch at SECL } } else { - t1 = this.cc.fieldIsolate(this.B, 10, 2); + this.C = this.B % 0x8000; + t1 = (this.B % 0x4000000000 - this.B % 0x1000000000)/0x1000000000; if (t1 < 3) { // if not a descriptor, increment the address this.L = t1+1; } else { @@ -3309,7 +3318,7 @@ B5500Processor.prototype.run = function() { this.PROF = 0; // require fetch at SECL } this.B = this.A; // restore B - this.BROF = this.AROF + this.BROF = this.AROF; this.AROF = 0; // invalidate A break; @@ -3332,7 +3341,7 @@ B5500Processor.prototype.run = function() { this.X = this.cc.fieldIsolate(this.B, 9, 39); // store prior LCW (less control bits) in X } this.B = this.A; // restore B - this.BROF = this.AROF + this.BROF = this.AROF; this.AROF = 0; // invalidate A break; @@ -3379,11 +3388,9 @@ B5500Processor.prototype.run = function() { this.AROF = this.BROF; t2 = this.S; // save S (not the way the hardware did it) this.S = this.F - variant; // compute store address - this.B = this.cc.fieldInsert( // insert F (as saved in t2) - this.cc.fieldInsert( // insert L - this.cc.fieldInsert(this.B, 33, 15, this.C), // insert C - 10, 2, this.L), - 18, 15, t2) % 0x800000000000; // reset flag bit + this.B = this.C + + this.F * 0x8000 + + this.L * 0x1000000000; this.storeBviaS(); // [S] = B this.S = t2; // restore S this.B = this.A; // restore B from A @@ -3539,9 +3546,9 @@ B5500Processor.prototype.run = function() { this.adjustAEmpty(); this.computeRelativeAddr(opcode >>> 2, 1); this.loadAviaM(); - if (this.A >= 0x800000000000) { // a small optimization for the - this.operandCall(); // common case when TOS is an operand - } + if (this.A >= 0x800000000000) { // if it's a control word, + this.operandCall(); // evaluate it + } // otherwise, just leave it in A break; case 3: // DESC: Descriptor (name) Call @@ -3631,9 +3638,9 @@ B5500Processor.prototype.run = function() { t2 = 0; } if (t2) { - this.loadAviaM(); + this.loadAviaM(); // fetch IOD if (this.NCSF) { - if (this.A % 0x200000 < 0x100000) { + if (this.A % 0x10000000 < 0x8000000) { // test continuity bit, [20:1] this.I = (this.I & 0x0F) | 0x50; // set I07/5: program release } else { this.I = (this.I & 0x0F) | 0x60; // set I07/6: continuity bit @@ -3816,16 +3823,12 @@ B5500Processor.prototype.run = function() { case 0x10: // 2015: MOP=reset flag bit (make operand) this.adjustAFull(); - if (this.A >= 0x800000000000) { - this.A %= 0x800000000000; - } + this.A %= 0x800000000000; break; case 0x20: // 4015: MDS=set flag bit (make descriptor) this.adjustAFull(); - if (this.A < 0x800000000000) { - this.A += 0x800000000000; - } + this.A = this.A % 0x800000000000 + 0x800000000000; // set [0:1] break; } break; @@ -3911,8 +3914,8 @@ B5500Processor.prototype.run = function() { case 0x0C: // 1425: FTC=F field to core field this.adjustABFull(); - t1 = (this.A % 0x40000000 - this.A % 0x8000)/0x8000; - this.B -= this.B % 0x8000 - t1 + t1 = (this.A % 0x40000000) >>> 15; + this.B -= this.B % 0x8000 - t1; this.AROF = 0; break; @@ -3932,7 +3935,7 @@ B5500Processor.prototype.run = function() { this.adjustABFull(); t1 = (this.A % 0x40000000 - this.A % 0x8000); t2 = (this.B % 0x40000000 - this.B % 0x8000); - this.B -= t2 - t1 + this.B -= t2 - t1; this.AROF = 0; break; @@ -3950,7 +3953,7 @@ B5500Processor.prototype.run = function() { case 0x2C: // 5425: CTC=core field to C field this.adjustABFull(); - this.B -= this.B % 0x8000 - this.A % 0x8000 + this.B -= this.B % 0x8000 - this.A % 0x8000; this.AROF = 0; break; @@ -4189,10 +4192,10 @@ B5500Processor.prototype.run = function() { case 0x1D: // XX35: exit & return ops switch (variant) { case 0x01: // 0135: BRT=branch return - adjustAEmpty(); + this.adjustAEmpty(); if (!this.BROF) { this.Q |= 0x04; // Q03F: not used, except for display purposes - adjustBFull(); + this.adjustBFull(); } if (this.presenceTest(this.B)) { this.S = (this.B % 0x40000000) >>> 15; @@ -4234,6 +4237,7 @@ B5500Processor.prototype.run = function() { case 0x0A: // 1235: RTS=return special this.adjustAFull(); + // Note that RTS assumes the RCW is pointed to by S, not F this.loadBviaS(); // B = [S], fetch the RCW switch (this.exitSubroutine(0)) { case 0: @@ -4257,14 +4261,14 @@ B5500Processor.prototype.run = function() { case 0x01: // 0141: INX=index this.adjustABFull(); t1 = this.A % 0x8000; - this.M = (t1 + this.B % 0x8000) & 0x7FFF; + this.M = (t1 + this.B % 0x8000) % 0x8000; this.A += this.M - t1; this.BROF = 0; break; case 0x02: // 0241: COC=construct operand call this.exchangeTOS(); - this.A = this.cc.bitSet(this.A, 0); + this.A = this.A % 0x800000000000 + 0x800000000000; // set [0:1] this.operandCall(); break; @@ -4285,7 +4289,7 @@ B5500Processor.prototype.run = function() { case 0x0A: // 1241: CDC=construct descriptor call this.exchangeTOS(); - this.A = this.cc.bitSet(this.A, 0); + this.A = this.A % 0x800000000000 + 0x800000000000; // set [0:1] this.descriptorCall(); break; @@ -4299,7 +4303,7 @@ B5500Processor.prototype.run = function() { this.B -= this.B % 0x8000 - this.S; break; case 2: // set F from B.[18:15] - this.F = (this.B % 0x40000000 - this.B % 0x8000)/0x8000; + this.F = (this.B % 0x40000000) >>> 15; this.SALF = 1; this.BROF = 0; break; @@ -4555,17 +4559,17 @@ B5500Processor.prototype.schedule = function schedule() { this.run(); // execute syllables for the timeslice - this.totalCycles += this.cycleCount + this.totalCycles += this.cycleCount; this.procTime += this.cycleCount; if (this.busy) { - delayTime = this.procTime/1000 - new Date().getTime(); + delayTime = this.procTime - new Date().getTime()*1000; this.procSlack += delayTime; - this.scheduler = setTimeout(this.boundSchedule, (delayTime < 0 ? 1 : delayTime)); + this.scheduler = setTimeout(this.boundSchedule, (delayTime > 0 ? delayTime/1000 : 1)); } }; /**************************************/ -B5500Processor.prototype.step = function() { +B5500Processor.prototype.step = function step() { /* Single-steps the processor. Normally this will cause one instruction to be executed, but note that in case of an interrupt, one or two injected instructions (e.g., SFI followed by ITI or char-mode CRF followed by lots of @@ -4576,6 +4580,6 @@ B5500Processor.prototype.step = function() { this.run(); - this.totalCycles += this.cycleCount + this.totalCycles += this.cycleCount; this.procTime += this.cycleCount; }; diff --git a/tools/B5500DiskDirList.html b/tools/B5500DiskDirList.html new file mode 100644 index 0000000..b201944 --- /dev/null +++ b/tools/B5500DiskDirList.html @@ -0,0 +1,605 @@ + + +B5500 Disk Directory List Utility + + + + + + + + + + + + +
+
+ retro-B5500 Logo +  Disk Directory List Utility +
+
+ + + + + +
MFID + FID + REC + BLK + RPB + SPB + LCD + LCT + LAD + CRD + FCL + FTY + CNT + SPR + MXR + Row Addresses +
+ +
+
+ +
+
+ + + \ No newline at end of file diff --git a/tools/B5500DiskFileList.html b/tools/B5500DiskFileList.html new file mode 100644 index 0000000..742a83a --- /dev/null +++ b/tools/B5500DiskFileList.html @@ -0,0 +1,772 @@ + + +B5500 Disk File List Utility + + + + + + + + + + + + +
+
+ retro-B5500 Logo +  Disk File List Utility +
+
+ + + + + +
File Name + REC + BLK + RPB + SPB + LCD + LCT + LAD + CRD + FCL + FTY + CNT + SPR + MXR +
+ +
+
+ +
+
+ + + \ No newline at end of file diff --git a/tools/INCL2OMIT.alg_m b/tools/INCL2OMIT.alg_m index e53351f..8b9d386 100644 --- a/tools/INCL2OMIT.alg_m +++ b/tools/INCL2OMIT.alg_m @@ -180,6 +180,7 @@ WHILE NOT READ(SOURCE, 15, REC) DO 00900900 00903200 SCANNER; 00903300 IF TOKEN ^= 48"01""$" THEN 00903400 + BEGIN 00903402 IF POPCOUNT > 0 THEN 00903405 BEGIN 00903410 REPLACE PREC BY " " FOR 72, THISSEQNR-1 FOR 8 DIGITS, " " FOR 10; 00903415 @@ -191,6 +192,7 @@ WHILE NOT READ(SOURCE, 15, REC) DO 00900900 END WHILE; 00903445 WRITE(PATCH, 15, PREC); 00903450 END; 00903455 + END 00903456 ELSE 00903460 BEGIN 00903500 SCANNER; 00903600 diff --git a/webUI/B5500ColdLoader.html b/webUI/B5500ColdLoader.html index dca71d9..d17aa98 100644 --- a/webUI/B5500ColdLoader.html +++ b/webUI/B5500ColdLoader.html @@ -1,6 +1,6 @@ -B5500 Coldstart Disk Subsystem Loader +B5500 Disk Subsystem Coldstart Loader @@ -8,13 +8,13 @@