diff --git a/devices/pdp11/README.md b/devices/pdp11/README.md index 8e050c349..ebfdca74b 100644 --- a/devices/pdp11/README.md +++ b/devices/pdp11/README.md @@ -7,11 +7,15 @@ permalink: /devices/pdp11/ PDP-11 Device Configurations ---------------------------- -[PDP-11 Machines](/devices/pdp11/machine/) powered by [PDPjs](/modules/pdp11/) rely on a variety of devices and resources, including: +[PDP-11 Machines](/devices/pdp11/machine/) powered by [PDPjs](/modules/pdp11/) rely on a variety of devices, including: + +- [Serial Interface for Display Terminals (DL11)](dl11/) +- [High-Speed Paper Tape Reader/Punch (PC11)](pc11/) + +Machines are built from a variety of device configuration files, including: * [Machines](machine/) * [Panels](panel/) -* [ROM Images](rom/) Our collection of sample machines includes a [PDP-11/70 with Front Panel](/devices/pdp11/machine/1170/panel/) and [PDP-11/70 with VT100 Terminal](/devices/pdp11/machine/1170/vt100/). diff --git a/devices/pdp11/dl11/README.md b/devices/pdp11/dl11/README.md new file mode 100644 index 000000000..1d0e0a92b --- /dev/null +++ b/devices/pdp11/dl11/README.md @@ -0,0 +1,10 @@ +--- +layout: page +title: DL11 Serial Interface for Display Terminals +permalink: /devices/pdp11/dl11/ +--- + +DL11 Serial Interface for Display Terminals +------------------------------------------- + +PDPjs implements the DL11 component in [serialport.js](/modules/pdp11/lib/serialport.js). diff --git a/devices/pdp11/pc11/README.md b/devices/pdp11/pc11/README.md new file mode 100644 index 000000000..9842a1e89 --- /dev/null +++ b/devices/pdp11/pc11/README.md @@ -0,0 +1,10 @@ +--- +layout: page +title: PC11 High-Speed Paper Tape Reader/Punch +permalink: /devices/pdp11/pc11/ +--- + +PC11 High-Speed Paper Tape Reader/Punch +--------------------------------------- + +PDPjs implements the PC11 component in [pc11.js](/modules/pdp11/lib/pc11.js). diff --git a/modules/pdp11/lib/cpuops.js b/modules/pdp11/lib/cpuops.js index c2c739862..14cfb8f48 100644 --- a/modules/pdp11/lib/cpuops.js +++ b/modules/pdp11/lib/cpuops.js @@ -52,7 +52,7 @@ if (NODE) { * * For example, opADD() passes the helper function fnADD() to the appropriate update method. This * allows the update method to perform the entire read/modify/write operation, because the modify - * step is performed internally via the fnXXX() helper function. + * step is performed internally, via the fnXXX() helper function. */ /** @@ -1117,7 +1117,24 @@ PDP11.opHALT = function(opCode) this.regErr |= PDP11.CPUERR.BADHALT; this.trap(PDP11.TRAP.BUS_ERROR, PDP11.REASON.HALT); } else { - this.stopCPU(); + if (!this.dbg) { + /* + * This will leave the PC exactly where it's supposed to be: at the address of the HALT + 2. + */ + this.stopCPU(); + } else { + /* + * When the Debugger is present, this call will rewind PC by 2 so that the HALT instruction is + * displayed, making it clear why the processor stopped; the user could also use the "dh" command + * to dump the Debugger's instruction history buffer to see why it stopped, assuming the history + * buffer is enabled, but that's more work. + * + * Because rewinding is not normal CPU behavior, attempting to Run again (or use the Debugger's + * "g" command) will cause an immediate HALT again; the work-around is simple: either set the PC to + * a new address (eg, "r pc=pc+2") or single-step the HALT instruction ("t"). + */ + this.dbg.stopInstruction(); + } } this.nStepCycles -= 7; }; diff --git a/modules/pdp11/lib/debugger.js b/modules/pdp11/lib/debugger.js index 7c0499d18..3929605c6 100644 --- a/modules/pdp11/lib/debugger.js +++ b/modules/pdp11/lib/debugger.js @@ -997,10 +997,16 @@ if (DEBUGGER) { var sComment = "history"; var nSequence = nPrev--; + + /* + * TODO: Need to some UI to control whether cycle counts are displayed as part of the history. + * It's currently disabled in checkInstruction(), so it's disable here, too. + * if (DEBUG && dbgAddr.cycleCount != null) { sComment = "cycles"; nSequence = dbgAddr.cycleCount; } + */ var sInstruction = this.getInstruction(dbgAddrNew, sComment, nSequence); @@ -1623,7 +1629,7 @@ if (DEBUGGER) { if (opCode != null) { var dbgAddr = this.aOpcodeHistory[this.iOpcodeHistory]; this.setAddr(dbgAddr, cpu.getPC()); - if (DEBUG) dbgAddr.cycleCount = cpu.getCycles(); + // if (DEBUG) dbgAddr.cycleCount = cpu.getCycles(); if (++this.iOpcodeHistory == this.aOpcodeHistory.length) this.iOpcodeHistory = 0; } } diff --git a/modules/pdp11/lib/defines.js b/modules/pdp11/lib/defines.js index 7446f09b7..565913861 100644 --- a/modules/pdp11/lib/defines.js +++ b/modules/pdp11/lib/defines.js @@ -425,8 +425,10 @@ var PDP11 = { LKS: 0o177546, // KW11-L Clock Status - PRS: 0o177550, // PC11/PR11 Reader Status Register - PRB: 0o177552, // PC11/PR11 Reader Buffer Register + PRS: 0o177550, // PC11 (and PR11) Reader Status Register + PRB: 0o177552, // PC11 (and PR11) Reader Buffer Register + PPS: 0o177554, // PC11 Punch Status Register + PPB: 0o177556, // PC11 Punch Buffer Register RCSR: 0o177560, // Display Terminal: Receiver Status Register RBUF: 0o177562, // Display Terminal: Receiver Data Buffer Register @@ -511,6 +513,9 @@ var PDP11 = { PSW: 0o177776 // 777776 17777776 0x3FFFFE Processor Status Word }, PC11: { // High Speed Reader & Punch (PR11 is a Reader-only unit) + PRI: 4, // NOTE: reader has precedence over punch + RVEC: 0o70, // reader vector + PVEC: 0o74, // punch vector PRS: { RE: 0x0001, // Reader Enable (W/O) RIE: 0x0040, // Reader Interrupt Enable (allows the DONE and ERROR bits to trigger an interrupt) @@ -518,6 +523,7 @@ var PDP11 = { BUSY: 0x0800, // Busy (R/O) ERROR: 0x8000, // Error (R/O) CLEAR: 0x08C0, // bits cleared on INIT + RMASK: 0xFFFE, // bits readable (TODO: All I know for sure is that bit 0 is NOT readable; see PC11.readPRS()) WMASK: 0x0041 // bits writable }, PRB: { diff --git a/modules/pdp11/lib/pc11.js b/modules/pdp11/lib/pc11.js index 0fb6fb506..7f4fd1b0a 100644 --- a/modules/pdp11/lib/pc11.js +++ b/modules/pdp11/lib/pc11.js @@ -206,6 +206,8 @@ PC11.prototype.initBus = function(cmp, bus, cpu, dbg) this.cpu = cpu; this.dbg = dbg; + var pc11 = this; + this.configMount = this.cmp.getMachineParm('autoMount') || this.configMount; if (this.configMount) { @@ -223,6 +225,12 @@ PC11.prototype.initBus = function(cmp, bus, cpu, dbg) } } + this.triggerReaderInterrupt = this.cpu.addTrigger(PDP11.PC11.RVEC, PDP11.PC11.PRI); + + this.timerReaderAdvance = this.cpu.addTimer(function readyReader() { + pc11.advanceReader(); + }); + bus.addIOTable(this, PC11.UNIBUS_IOTABLE); this.addTape("None", PC11.LOADSTATE.NONE, true); @@ -623,16 +631,57 @@ PC11.prototype.restore = function(data) return true; }; +/** + * advanceReader() + * + * If the reader is enabled (RE is set) and there is no exceptional condition (ie, ERROR is set), + * and if the buffer register is empty (DONE is clear), then if we have more data in our internal buffer, + * store it in the buffer register, and optionally trigger an interrupt if device interrupts are enabled. + * + * @this {PC11} + */ +PC11.prototype.advanceReader = function() +{ + if ((this.prs & (PDP11.PC11.PRS.RE | PDP11.PC11.PRS.ERROR)) == PDP11.PC11.PRS.RE) { + if (!(this.prs & PDP11.PC11.PRS.DONE)) { + if (this.iTapeData < this.aTapeData.length) { + this.prb = this.aTapeData[this.iTapeData++]; + this.prs |= PDP11.PC11.PRS.DONE; + this.prs &= ~PDP11.PC11.PRS.BUSY; + if (this.prs & PDP11.PC11.PRS.RIE) { + this.cpu.setTrigger(this.triggerReaderInterrupt); + } + /* + * The PC11, by virtue of its "high speed", is supposed to deliver characters at 300 CPS, + * so for now, that's what we're going to deliver (ie, 1000ms / 300). + * + * TODO: Review this code. If we don't set the fReset parameter to true, the timer will eventually + * fire while the "Absolute Loader" tape is still reading bytes from, say, the "BASIC (Single User)" + * tape, causing an EXTRA advance to occur and causing a byte to be skipped. Passing true ensures + * that the timer cannot fire for AT LEAST 3ms after each advance. But again, I need to understand + * the reader's actual behavior. + */ + this.cpu.setTimer(this.timerReaderAdvance, 1000/300, true); + } + } + } +}; + /** * readPRS(addr) * + * NOTE: We use the PRS RMASK to honor the "write-only" behavior of bit 0, the reader enable bit (RE), because + * DEC's tiny Bootstrap Loader (/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.lst) repeatedly enables the reader using + * the INC instruction, which causes the PRS to be read, incremented, and written, so if bit 0 isn't always read + * as zero, the INC instruction would clear RE instead of setting it. + * * @this {PC11} * @param {number} addr (eg, PDP11.UNIBUS.PRS or 177550) * @return {number} */ PC11.prototype.readPRS = function(addr) { - return this.prs; + return this.prs & PDP11.PC11.PRS.RMASK; // RMASK honors the "write-only" nature of the RE bit by returning zero on reads }; /** @@ -648,14 +697,16 @@ PC11.prototype.writePRS = function(data, addr) if (this.prs & PDP11.PC11.PRS.ERROR) { data &= ~PDP11.PC11.PRS.RE; // if (this.prs & PDP11.PC11.PRS.RIE) { - // TODO: Generate an interrupt + // TODO: Generate an interrupt (error condition) // } } else { this.prs &= ~PDP11.PC11.PRS.DONE; this.prs |= PDP11.PC11.PRS.BUSY; + this.prb = 0; } } this.prs = (this.prs & ~PDP11.PC11.PRS.WMASK) | (data & PDP11.PC11.PRS.WMASK); + this.advanceReader(); }; /** @@ -667,6 +718,12 @@ PC11.prototype.writePRS = function(data, addr) */ PC11.prototype.readPRB = function(addr) { + /* + * I'm guessing that the DONE and BUSY bits always remain more-or-less inverses of each other. They definitely + * start out that way when writePRS() sets the reader enable (RE) bit, and so that's how we treat them elsewhere, too. + */ + this.prs &= ~PDP11.PC11.PRS.DONE; + this.prs |= PDP11.PC11.PRS.BUSY; return this.prb; }; diff --git a/modules/pdp11/lib/serialport.js b/modules/pdp11/lib/serialport.js index d92c7e882..0af5b5653 100644 --- a/modules/pdp11/lib/serialport.js +++ b/modules/pdp11/lib/serialport.js @@ -475,10 +475,6 @@ SerialPortPDP11.prototype.receiveData = function(data) return true; // for now, return true regardless, since we're buffering everything anyway }; -SerialPortPDP11.prototype.advanceRBUF = function() -{ -}; - /** * transmitByte(b) * diff --git a/versions/c1pjs/1.30.1/common.xsl b/versions/c1pjs/1.30.1/common.xsl index dfdcbfbd4..addc25474 100644 --- a/versions/c1pjs/1.30.1/common.xsl +++ b/versions/c1pjs/1.30.1/common.xsl @@ -31,7 +31,7 @@