From f4bbcecb17fab97fd477ef79363f74a0dd92e260 Mon Sep 17 00:00:00 2001 From: paul Date: Sun, 17 Jun 2012 16:50:12 +0000 Subject: [PATCH] Commit DCMCP transcription and emulator WIP as of 2012-06-17. --- SYMBOL/DCMCP.esp_m | 107 +++++++++++++++++++ emulator/B5500CentralControl.js | 4 +- emulator/B5500DistributionAndDisplay.js | 134 +++++++++++++----------- emulator/B5500Processor.js | 33 +++--- 4 files changed, 199 insertions(+), 79 deletions(-) diff --git a/SYMBOL/DCMCP.esp_m b/SYMBOL/DCMCP.esp_m index 74da4f5..ca38769 100644 --- a/SYMBOL/DCMCP.esp_m +++ b/SYMBOL/DCMCP.esp_m @@ -3804,3 +3804,110 @@ BEGIN 04668400 END ELSE 04673350 GO XIO; 04673400 END; 04673450 + RESULT.[27:1] ~ 1; MODE ~ 32; 04673500 +XIO: END DOIONOW; 04673550 + % 04673600 + U ~ SAVEU ~ OIOD.[3:4]; 04673650 + % SAVE OFF ORIGINAL UNIT FOR DS-ING. 04673700 + OLDU ~ UNIT[U]; 04673750 + % SAVE OFF ORIGINAL UNIT TABLE ENTRY 04673800 + MIX ~ RDCTABLE[U].[8:6]; 04673850 + MODE ~ 16; 04673900 + % SET MODE TO FLAG PARITY, MODE WILL BE SET TO ZERO IF CHANGE OK 04673950 + LABELA ~ M[(TOPIOD~PRNTABLE[U].[15:15])-2] & @05000[CTF]; 04674000 + FIB ~ M[TOPIOD-3]; 04674050 + PBT ~ FIB[4].[8:4]=7; 04674100 + FNUM ~ FIB[4].[13.11]; 04674150 + BSIZE ~ IF PBT THEN 90 ELSE FIB[18].[3:15]; 04674200 + NUMRECS ~ IF PBT THEN 5 ELSE BSIZE DIV FIB[18].[33:15]; 04674225 + REEL ~ FIB[13].[28:10]+1; 04674250 + ALFA ~ (NOT FIB[13]).[24:1]; 04674300 + LABELED ~ (NOT FIB[4]).[2:1]; 04674350 + NUMBUFFS ~ FIB[13].[10:9]; 04674400 + TANK ~ [M[TOPIOD]] & NUMBUFFS[8:38:10]; 04674450 + HALT; 04674500 + % STOP NORMAL STATE PROCESSING. 04674550 + IF RC THEN 04674600 + IF TANK[0].[24:1] THEN 04674650 + BEGIN 04674700 + STREAM(T~T2~SPACE(5)); 04674750 + DS ~ 40 LIT"#REEL SWITCH NOT POSSIBLE ON INPUT FILE~"; 04674800 + SPOUTER(T2,UNITNO,1); 04674850 + GO EXIT; 04674900 + END; 04674950 + STREAM(A~TINU[U], T~T2~SPACE(5)); 04675000 + BEGIN 04675050 + DS ~ 34 LIT"#REEL SWITCH TO BE ATTEMPTED FROM "; 04675100 + SI ~ LOC A; SI ~ SI+5; DS ~ 3 CHR; DS ~ LIT"~"; 04675150 + END; 04675200 + SPOUTER(T2,UNITNO,1); 04675250 + IF PBT THEN 04675300 + BEGIN 04675350 + LABELA.[8:10] ~ 8; % PRINTER LABELS ARE 15 WORDS 04675400 + LABELA[1] ~ MULTITABLE[U].[3:45]; 04675450 + LABELA[2] ~ LABELTABLE[U].[3:45]; 04675500 + END; 04675550 + IF RC THEN GO L1; 04675600 + FIRSTREC ~ GETSPACE(BSIZE+4,0,1)+4; 04675650 + SECREC ~ GETSPACE(BSIZE+4,0,1)+4; 04675700 + % GETSPACE ON TWO BUFFERS FOR BACKWARD READ. 04675750 + IF ALFA THEN 04675800 + BEGIN 04675850 + IOD ~ @340000000 & OIOD[3:3:5] & [T2][CTC]; 04675900 + DOIONOW; DOIONOW; 04675950 + IOD ~ OIOD & 1[24:47:1] & FIRSTREC[CTC]; 04676000 + DOIONOW; 04676050 + IF RESULT.[27:2]!0 THEN GO ERROROUT; 04676100 + IOD ~ IOD & SECREC[CTC]; 04676150 + DOIONOW; 04676200 + IF RESULT.[27:2]!0 THEN GO ERROROUT; 04676250 + IOD ~ @340000000 & OIOD[3:3:5] & [T2][CTC]; 04676300 + DOIONOW; DOIONOW; 04676350 + GO L1; 04676400 + END; 04676450 + IOD ~ OIOD & (SECREC+BSIZE-1)[CTC] & 5[22:45:3]; 04676500 + DOIONOW; 04676550 + % BUILD BACKWARD DESCRIPTOR AND EXECUTE FIRST BACKWARD READ. 04676600 + IF RESULT.[27:2]!0 THEN GO ERROROUT; 04676650 + IF (TEMP ~ M[IOD INX 1])!BSIZE THEN 04676700 + % VARIABLE LENGTH BLOCK. 04676750 + SECRECIO ~ ((IOD INX 1)-TEMP) & TEMP[8:38:10]; 04676800 + IOD ~ IOD & (FIRSTREC+BSIZE-1)[CTC]; 04676850 + DOIONOW; 04676900 + % NEXT BACKWARD READ. 04676950 + IF RESULT.[27:2]!0 THEN GO ERROROUT; 04677000 + IF (TEMP ~ M[IOD INX 1])!BSIZE THEN 04677050 + % VARIABLE LENGTH BLOCK. 04677100 + FIRSTRECIO ~ ((IOD INX 1)-TEMP) & TEMP[8:38:10]; 04677150 +L1: 04677200 + FOR I ~ 0 STEP 1 UNTIL NUMBUFFS-1 DO 04677250 + IF (NOT TANK[I]).[19:1] THEN HOLDCT ~ HOLDCT+1; 04677300 + % SCAN FOR THE NUMBER OF FILLED BUFFERS. 04677350 + FIB[6] ~ FIB[6]-((RC=0)|2)-HOLDCT; 04677400 + LOGICLRC ~ FIB[7] MOD NUMRECS; 04677450 + % DETERMINE THE NUMBER OF LOGICAL RECORDS WRITTEN. 04677500 + FIB[7] ~ FIB[6] | NUMRECS; 04677550 + % LOAD FIB WITH RECORD COUNT FOR TRAILER LABEL. 04677600 + IF HOLDCT=NUMBUFFS THEN 04677650 + BEGIN 04677700 + NOPROCESSTOG ~ NOPROCESSTOG-1; 04677750 + NORMALPROCESS ~ 1; 04677800 + END; 04677850 + % IF THERE ARE NO UNFILLED BUFFERS THEN ALLOW NORMAL STATE 04677900 + % PROCESSING TO CONTINUE. 04677950 + % FLAG THE RELEASE OF NORMAL STATE. 04678000 + % THE CHANCE OF UNFILLED BUFFERS IS VERY REMOTE, BUT JUST IN CASE 04678050 + P1MIX ~ MIX; 04678100 + % LOAD P1MIX FOR CONSOLE MESSAGES. 04678150 + TEMP ~ U; 04678200 + % SAVE OFF CURRENT UNIT IN CASE DS CALLED AT THIS POINT. 04678250 +RETRY: 04678300 + IF TERMSET(MIX) THEN 04678350 + BEGIN 04678400 + U ~ (-1); 04678450 + GO ERROROUT; 04678500 + END; 04678550 + TEMP ~ U; 04678600 + TM ~ @ 1737000000000000; 04678650 + % TAPE MARK. 04678700 + IOD ~ NFLAG([TM]) & OIOD[3:3:5]; 04678750 diff --git a/emulator/B5500CentralControl.js b/emulator/B5500CentralControl.js index ec9a256..c668d8d 100644 --- a/emulator/B5500CentralControl.js +++ b/emulator/B5500CentralControl.js @@ -40,10 +40,10 @@ function B5500CentralControl() { this.timer = null; // Reference to the RTC setTimeout id. this.loadTimer = null; // Reference to the load setTimeout id. - this.clear(); // Create and initialize the Central Control state - this.tock.that = this; // Establish contexts for when called from setTimeout(). this.loadComplete.that = this; + + this.clear(); // Create and initialize the Central Control state } /**************************************/ diff --git a/emulator/B5500DistributionAndDisplay.js b/emulator/B5500DistributionAndDisplay.js index 57f9f48..87dc82f 100644 --- a/emulator/B5500DistributionAndDisplay.js +++ b/emulator/B5500DistributionAndDisplay.js @@ -19,8 +19,8 @@ function B5500DDLamp(x, y) { this.state = 0; // current lamp state, 0=off - this.element = // visible DOM element - document.createElement("div"); + // visible DOM element + this.element = document.createElement("div"); this.element.className = "ddLamp"; this.element.style.left = String(x) + "px"; this.element.style.top = String(y) + "px"; @@ -47,21 +47,47 @@ B5500DDLamp.prototype.set = function(v) { /*********************************************************************** * Panel Register * ***********************************************************************/ -B5500DDRegister(bits, x, y, rows, deltax, deltay) { - /* Constructor for the register objects used within D&D. +B5500DDRegister(bits, x, y, rows, caption) { + /* Constructor for the register objects used within D&D: + bits: number of bits in register + x: horizontal coordinate of upper-left corner [hSpacing increments] + y: vertical coordinate of upper-left corner [vSpacing increments] + rows: number of rows used to display the bit lamps */ var cols = Math.floor((bits+rows-1)/rows); var height = rows*this.vSpacing; var width = cols*this.hSpacing; + var b; + var cx = Math.floor((x-0.25)*this.hSpacing); + var cy = Math.floor((y-0.25)*this.vSpacing); + var lamp; this.bits = bits; // number of bits in the register - this.left = x; // horizontal offset relative to container - this.top = y; // vertical offset relative to container - this.element = // visible DOM element - document.createElement("div"); + this.left = cx; // horizontal offset relative to container + this.top = cy; // vertical offset relative to container + this.caption = caption; // panel caption + this.lamps = new Array(bits+1); // bit lamps + + // visible DOM element + this.element = document.createElement("div"); this.element.className = "ddRegister"; - this.element.style.left = String(x) + "px"; - this.element.style.top = String(y) + "px"; + this.element.style.left = String(cx) + "px"; + this.element.style.top = String(cy) + "px"; + this.element.style.width = width; + this.element.style.height = height; + + cx = (x+cols)*this.hSpacing; + for (b=1; b<=bits; b++) { + if ((b-1)%rows == 0) { + cy = (y+rows-1)*this.vSpacing; + cx -= this.xSpacing; + } else { + cy -= this.vSpacing; + } + lamp = new B5500DDLamp(cx, cy); + this.lamps[b] = lamp; + this.element.appendChild(lamp); + } } /**************************************/ @@ -79,12 +105,14 @@ function B5500DistributionAndDisplay() { /* Global system modules */ - this.nextTimeStamp = 0; // Next actual Date.getTime() expected + this.nextRefresh = 0; // Next actual Date.getTime() expected this.timer = null; // Reference to the RTC setTimeout id. - this.clear(); // Create and initialize the Central Control state + this.panels = {}; // D&D panel object collection - this.tock.that = this; // Establish contexts for when called from setTimeout(). + this.updateDisplay.that = this; // Establish contexts for when called from setTimeout(). + + this.clear(); // Create and initialize the Central Control state } /**************************************/ @@ -102,52 +130,38 @@ B5500DistributionAndDisplay.prototype.clear = function() { this.nextTimeStamp = new Date().getTime() + this.rtcTick; this.timer = setTimeout(this.tock, this.rtcTick); - - this.IAR = 0; // Interrupt address register - this.TM = 0; // Real-time clock (6 bits, 60 ticks per second) - - this.CCI03F = 0; // Time interval interrupt - this.CCI04F = 0; // I/O busy interrupt - this.CCI05F = 0; // Keyboard request interrupt - this.CCI06F = 0; // Printer 1 finished interrupt - this.CCI07F = 0; // Printer 2 finished interrupt - this.CCI08F = 0; // I/O unit 1 finished interrupt (RD in @14) - this.CCI09F = 0; // I/O unit 2 finished interrupt (RD in @15) - this.CCI10F = 0; // I/O unit 3 finished interrupt (RD in @16) - this.CCI11F = 0; // I/O unit 4 finished interrupt (RD in @17) - this.CCI12F = 0; // P2 busy interrupt - this.CCI13F = 0; // Remote inquiry request interrupt - this.CCI14F = 0; // Special interrupt #1 (not used) - this.CCI15F = 0; // Disk file #1 read check finished - this.CCI16F = 0; // Disk file #2 read check finished - - this.MCYF = 0; // Memory cycle FFs (one bit per M0..M7) - this.PAXF = 0; // PA memory exchange select (M0..M7) - this.PBXF = 0; // PB memory exchange select (M0..M7) - this.I1XF = 0; // I/O unit 1 exchange select (M0..M7) - this.I2XF = 0; // I/O unit 2 exchange select (M0..M7) - this.I3XF = 0; // I/O unit 3 exchange select (M0..M7) - this.I4XF = 0; // I/O unit 4 exchange select (M0..M7) - - this.AD1F = 0; // I/O unit 1 busy - this.AD2F = 0; // I/O unit 2 busy - this.AD3F = 0; // I/O unit 3 busy - this.AD4F = 0; // I/O unit 4 busy - - this.LOFF = 0; // Load button pressed on console - this.CTMF = 0; // Commence timing FF - this.P2BF = 0; // Processor 2 busy FF - this.HP2F = 1; // Halt processor 2 FF - - if (this.PA) { - this.PA.clear(); - } - if (this.PB) { - this.PB.clear(); - } - this.P1 = (this.PB1L ? this.PB : this.PA); - this.P2 = (this.PB1L ? this.PA : this.PB); - if (!this.P2) { - this.P2BF = 1; // mark non-existent P2 as busy } } + +/**************************************/ +B5500DistributionAndDisplay.prototype.openProcessorPanel(p, caption) { + /* Creates a D&D panel window for a processor */ + var x; + var panel = this.panels[caption]; + + if (panel) { + win = panel.window; + } else { + win = window.open("B5500ProcessorPanel.html", "P"+caption, + "resizable=yes,scrollbars=yes"); + panel = {module:p, window:win, caption:caption}; + this.panels[caption] = panel; + } + + win.appendChild(new B5500DDRegister(39, 1, 1, 3, "X REG")); +} + +/**************************************/ +B5500DistributionAndDisplay.prototype.updateDisplay = function updateDisplay() { + /* Schedules itself to update the display on a periodic basis. */ + var delayTime; + var that = updateDisplay.that; + var thisTime = new Date().getTime(); + + // Schedule ourself for the next refresh period + that.nextRefresh += that.refreshPeriod; + delayTime = that.nextRefresh - thisTime; + that.timer = setTimeout(that.updateDisplay, (delayTime < 0 ? 0 : delayTime); + + +} \ No newline at end of file diff --git a/emulator/B5500Processor.js b/emulator/B5500Processor.js index fafe273..6a4e632 100644 --- a/emulator/B5500Processor.js +++ b/emulator/B5500Processor.js @@ -22,9 +22,9 @@ function B5500Processor() { MPED: 0, // Truthy if memory parity error MAED: 0}; // Truthy if memory address/inhibit error - this.clear(); // Create and initialize the processor state - this.schedule.that = this; // Establish context for when called from setTimeout() + + this.clear(); // Create and initialize the processor state } /**************************************/ @@ -61,7 +61,7 @@ B5500Processor.prototype.clear = function() { this.P = 0; // Current program instruction word register this.PROF = 0; // P contents valid this.Q = 0; // Misc. FFs (bits 1-9 only: Q07F=hardware-induced interrupt, Q09F=enable parallel adder for R-relative addressing) - this.R = 0; // PRT base address (low-order 6 bits are always zero in word mode) + this.R = 0; // High-order 9 bits of PRT base address (TALLY in char mode) this.S = 0; // Top-of-stack memory address (DI.w in CM) this.SALF = 0; // Program/subroutine state FF (1=subroutine) this.T = 0; // Current program syllable register @@ -174,12 +174,12 @@ B5500Processor.prototype.adjustAEmpty = function() { if (this.AROF} { if (this.BROF) { - if (this.S < this.R || !this.NCSF) { - this.S++; - this.access(0x0B); // [S] = B - } else { + if ((this.S >>> 6) == this.R || !this.NCSF) { this.I |= 0x04; // set I03F: stack overflow cc.signalInterrupt(); + } else { + this.S++; + this.access(0x0B); // [S] = B } } this.B = this.A; @@ -213,12 +213,12 @@ B5500Processor.prototype.adjustBEmpty = function() { contents of B into memory, as necessary. */ if (this.BROF) { - if (this.S < this.R || !this.NCSF) { - this.S++; - this.access(0x0B); // [S] = B - } else { + if ((this.S >>> 6) = this.R || !this.NCSF) { this.I |= 0x04; // set I03F: stack overflow cc.signalInterrupt(); + } else { + this.S++; + this.access(0x0B); // [S] = B } // else we're done -- B is already empty } @@ -278,7 +278,7 @@ B5500Processor.storeForInterrupt = function(forTest) { this.VARF * 0x1000000 + this.SALF * 0x40000000 + this.MSFF * 0x80000000 + - (this.CWMF ? this.R : this.R >>> 6) * 0x200000000 + + this.R * 0x200000000 + 0xC00000000000; this.access(0x0B); // [S] = B @@ -300,7 +300,7 @@ B5500Processor.storeForInterrupt = function(forTest) { this.access(0x03); // B = [S]: get last RCW this.S = ((this.B % 0x40000000) >>> 15) & 0x7FFF; this.access(0x03); // B = [S]: get last MSCW - this.R = (Math.Floor(this.B / 0x200000000) % 0x200) << 6; + this.R = Math.Floor(this.B / 0x200000000) % 0x200; this.S = this.F; } @@ -317,7 +317,7 @@ B5500Processor.storeForInterrupt = function(forTest) { this.MWOF = 0; } - this.M = this.R + 0x08; // store initiate word at R+@10 + this.M = (this.R << 6) + 0x08; // store initiate word at R+@10 this.access(0x0D); // [M] = B this.M = 0; @@ -413,8 +413,7 @@ B5500Processor.initiate = function(forTest) { this.VARF = Math.floor(this.B / 0x1000000) % 0x02; this.SALF = Math.floor(this.B / 0x40000000) % 0x02; this.MSFF = Math.floor(this.B / 0x80000000) % 0x02; - temp = (Math.floor(this.B / 0x200000000) % 0x200); - this.R = (this.CWMF ? temp & 0x3F : temp << 6); + this.R = (Math.floor(this.B / 0x200000000) % 0x200); if (this.CWMF || forTest) { this.M = this.B % 0x8000; @@ -759,7 +758,7 @@ B5500Processor.prototype.run = function() { case 0x10: // 1011: COM=Communicate if (this.NCSF) { // no-op in control state this.adjustAFull(); - this.M = this.R + 0x09; // address = R+@11 + this.M = (this.R << 6) + 0x09; // address = R+@11 this.access(0x0C); // [M] = A this.AROF = 0; this.I = (this.I & 0x0F) | 0x40; // set I07