Skip to content
This repository was archived by the owner on Dec 24, 2020. It is now read-only.

Commit

Permalink
Fixed RTI on older PDP-11s (ie, 11/20); the old RTI behaves like the …
Browse files Browse the repository at this point in the history
…new RTT, which did not exist on older machines
  • Loading branch information
jeffpar committed Nov 14, 2016
1 parent 397c929 commit a8155cb
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 140 deletions.
11 changes: 8 additions & 3 deletions modules/pdp11/lib/cpuops.js
Original file line number Diff line number Diff line change
Expand Up @@ -1507,7 +1507,12 @@ PDP11.opRTI = function(opCode)
{
this.trapReturn();
/*
* Unlike RTT, RTI enables immediate trace
* Unlike RTT, RTI permits an immediate trace, which we resolve by propagating PSW.TF to OPFLAG.TRAP_TF
* (which, as written, requires that both flags have the same bit value; see defines.js).
*
* NOTE: This trace behavior is NEW for machines that have both RTI and RTT. Early models didn't have RTT; ie,
* the old RTI instruction behaved exactly like the new RTT instruction. This is why the 11/20 jump table below
* for RTI calls opRTT() instead of opRTI().
*/
this.opFlags |= (this.regPSW & PDP11.PSW.TF);
this.nStepCycles -= (10 + 3);
Expand All @@ -1528,7 +1533,7 @@ PDP11.opRTS = function(opCode)
var src = this.popWord();
var reg = opCode & PDP11.OPREG.MASK;
/*
* When the popular "RTS PC" form is used, we might as well eliminate the useless setting of PC to
* When the popular "RTS PC" form is used, we might as well eliminate the useless setting of PC
*/
if (reg == PDP11.REG.PC) {
this.setPC(src);
Expand Down Expand Up @@ -2057,7 +2062,7 @@ PDP11.aOp00Xn_1120 = [
PDP11.aOp000X_1120 = [
PDP11.opHALT, // 0x0000 000000 11/20+ 1.8
PDP11.opWAIT, // 0x0001 000001 11/20+ 1.8
PDP11.opRTI, // 0x0002 000002 11/20+ 4.8
PDP11.opRTT, // 0x0002 000002 11/20+ 4.8 (this is really RTI, but on the 11/20, it behaves like RTT)
PDP11.opBPT, // 0x0003
PDP11.opIOT, // 0x0004 000004 11/20+ 9.3
PDP11.opRESET, // 0x0005 000005 11/20+ 20ms
Expand Down
20 changes: 18 additions & 2 deletions modules/pdp11/lib/cpustate.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,13 @@ CPUStatePDP11.prototype.setMMR3 = function(newMMR3)
CPUStatePDP11.prototype.setReset = function(addr, fReset)
{
this.addrReset = addr;

/*
* If we're going to slam this new address straight into PC, then it seems wise to reset the PSW as well.
*/
this.setPC(addr);
this.setPSW(0);

if (!fReset && this.dbg) {
/*
* TODO: Review the decision to always stop the CPU if the Debugger is loaded. Note that
Expand Down Expand Up @@ -2343,7 +2349,7 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
* nDebugCheck is 1 if we want the Debugger's checkInstruction() to check every instruction,
* -1 if we want it to check just the first instruction, and 0 if there's no need for any checks.
*/
var nDebugCheck = (DEBUGGER && this.dbg && this.dbg.checksEnabled())? 1 : (this.flags.starting? -1 : 0);
var nDebugCheck = (DEBUGGER && this.dbg)? (this.dbg.checksEnabled()? 1 : (this.flags.starting? -1 : 0)) : 0;

/*
* nDebugState is needed only when nDebugCheck is non-zero; it is -1 if this is a single-step, 0 if
Expand All @@ -2367,7 +2373,7 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)

do {
if (DEBUGGER && nDebugCheck) {
if (this.dbg && this.dbg.checkInstruction(this.getPC(), nDebugState)) {
if (this.dbg.checkInstruction(this.getPC(), nDebugState)) {
this.stopCPU();
break;
}
Expand All @@ -2376,6 +2382,7 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
}

if (this.opFlags) {

/*
* If we're in the INTQ or WAIT state, check for any pending interrupts.
*
Expand All @@ -2386,6 +2393,10 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
*/
if ((this.opFlags & (PDP11.OPFLAG.INTQ_MASK | PDP11.OPFLAG.WAIT)) /* && nDebugState >= 0 */) {
if (this.checkInterrupts()) {
if (DEBUGGER && nDebugCheck && this.dbg.checkInstruction(this.getPC(), nDebugState)) {
this.stopCPU();
break;
}
/*
* Since an interrupt was just dispatched, altering the normal flow of time and changing
* the future as we knew it, let's break out immediately if we're single-stepping, so that
Expand All @@ -2396,6 +2407,7 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
if (nDebugState < 0) break;
}
}

/*
* Next, check for any pending traps (which, as noted above, must be done after checkInterrupts()).
*
Expand All @@ -2405,6 +2417,10 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
*/
if (this.opFlags & PDP11.OPFLAG.TRAP_MASK) {
if (this.checkTraps()) {
if (DEBUGGER && nDebugCheck && this.dbg.checkInstruction(this.getPC(), nDebugState)) {
this.stopCPU();
break;
}
if (nDebugState < 0) break;
}
}
Expand Down
20 changes: 10 additions & 10 deletions modules/pdp11/lib/debugger.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ if (DEBUGGER) {
* Register numbers 0-7 are reserved for cpu.regsGen, 8-15 are reserved for cpu.regsAlt, and 16-19 for cpu.regsStack.
*/
DebuggerPDP11.REG_PSW = 20;
DebuggerPDP11.REG_SW = 21;
DebuggerPDP11.REG_SR = 21; // SWITCH register; see Panel's getSR() and setSR()

/*
* Operand type masks; anything that's not covered by OP_SRC or OP_DST must be a OP_OTHER value.
Expand Down Expand Up @@ -1127,7 +1127,7 @@ if (DEBUGGER) {
case "PC":
iReg = 7;
break;
case "SW":
case "SR":
iReg = 21;
break;
default:
Expand Down Expand Up @@ -1156,7 +1156,7 @@ if (DEBUGGER) {
* getRegValue(iReg)
*
* Register numbers 0-7 are reserved for cpu.regsGen, 8-15 are reserved for cpu.regsAlt,
* 16-19 for cpu.regsAltStack, 20 for regPSW, and 21 for regSW.
* 16-19 for cpu.regsAltStack, 20 for regPSW, and 21 for SR (SWITCH register).
*
* @this {DebuggerPDP11}
* @param {number} iReg
Expand All @@ -1178,8 +1178,8 @@ if (DEBUGGER) {
else if (iReg == DebuggerPDP11.REG_PSW) {
value = this.cpu.getPSW();
}
else if (iReg == DebuggerPDP11.REG_SW && this.panel && this.panel.hasSwitches()) {
value = this.panel.getSW();
else if (iReg == DebuggerPDP11.REG_SR && this.panel && this.panel.hasSwitches()) {
value = this.panel.getSR();
}
}
return value;
Expand Down Expand Up @@ -2392,8 +2392,8 @@ if (DEBUGGER) {
else if (iReg == DebuggerPDP11.REG_PSW) {
sReg = "PS=" + this.toStrBase(cpu.getPSW());
}
else if (iReg == DebuggerPDP11.REG_SW && this.panel && this.panel.hasSwitches()) {
sReg = "SW=" + this.toStrBase(this.panel.getSW(), 3);
else if (iReg == DebuggerPDP11.REG_SR && this.panel && this.panel.hasSwitches()) {
sReg = "SR=" + this.toStrBase(this.panel.getSR(), 3);
}
if (sReg) sReg += ' ';
return sReg;
Expand All @@ -2419,7 +2419,7 @@ if (DEBUGGER) {
}
sDump += '\n';
sDump += this.getRegOutput(PDP11.REG.SP) + this.getRegOutput(PDP11.REG.PC);
sDump += this.getRegOutput(DebuggerPDP11.REG_PSW) + this.getRegOutput(DebuggerPDP11.REG_SW);
sDump += this.getRegOutput(DebuggerPDP11.REG_PSW) + this.getRegOutput(DebuggerPDP11.REG_SR);
sDump += this.getFlagOutput('T') + this.getFlagOutput('N') + this.getFlagOutput('Z') + this.getFlagOutput('V') + this.getFlagOutput('C');
return sDump;
};
Expand Down Expand Up @@ -3435,9 +3435,9 @@ if (DEBUGGER) {
case "C":
if (w) cpu.setCF(); else cpu.clearCF();
break;
case "SW":
case "SR":
if (this.panel && this.panel.hasSwitches()) {
this.panel.setSW(w);
this.panel.setSR(w);
break;
}
/* falls through */
Expand Down
89 changes: 45 additions & 44 deletions modules/pdp11/lib/defines.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ var PDP11 = {
MASK: 0x3
},
/*
* Processor Status flag definitions (stored in regPSW)
* Processor Status Word definitions (stored in regPSW)
*/
PSW: {
CF: 0x0001, // bit 0 (000001) Carry Flag
Expand All @@ -185,6 +185,49 @@ var PDP11 = {
CMODE: 14
}
},
/*
* PDP-11 trap vectors
*/
TRAP: {
UNDEFINED: 0x00, // 000 (reserved)
BUS: 0x04, // 004 unaligned address, non-existent memory, illegal instruction, etc
RESERVED: 0x08, // 010 reserved instructions
BPT: 0x0C, // 014 BPT: breakpoint trap (trace)
IOT: 0x10, // 020 IOT: input/output trap
PF: 0x14, // 024 power fail
EMT: 0x18, // 030 EMT: emulator trap
TRAP: 0x1C, // 034 TRAP instruction
PIRQ: 0xA0, // 240 PIRQ: program interrupt request
MMU: 0xA8 // 250 MMU: aborts and traps
},
/*
* PDP-11 trap reasons; the reason may also be a non-negative address indicating a BUS memory error
* (unaligned address or non-existent memory). Any reason >= RED (which includes BUS memory errors) generate
* immediate (thrown) traps, as they are considered ABORTs; the rest generate synchronous traps.
*/
REASON: {
ABORT: -1, // immediate MMU fault
ILLEGAL: -2, // immediate invalid opcode (BUS)
RED: -3, // immediate stack overflow fault (BUS)
YELLOW: -4, // deferred stack overflow fault (BUS)
FAULT: -5, // deferred MMU fault
TRACE: -6, // deferred TF fault (BPT)
HALT: -7, // illegal HALT (BUS)
OPCODE: -8, // opcode-generated trap (eg, BPT, EMT, IOT, TRAP, or RESERVED opcode)
INTERRUPT: -9, // device-generated trap (vector is device-specific)
},
REASONS: [
"UNKNOWN",
"ABORT",
"ILLEGAL",
"RED",
"YELLOW",
"FAULT",
"TRACE",
"HALT",
"OPCODE",
"INTERRUPT"
],
/*
* Assorted common opcodes
*/
Expand All @@ -202,7 +245,7 @@ var PDP11 = {
INTQ_MASK: 0x03,
WAIT: 0x04, // WAIT operation in progress
TRAP: 0x08, // set if last operation was a trap (see trapLast for the vector, and trapReason for the reason)
TRAP_TF: 0x10, // aka PDP11.PSW.TF
TRAP_TF: 0x10, // aka PDP11.PSW.TF (WARNING: do not change this bit, or you will likely break opRTI())
TRAP_SP: 0x20, // set for a deferred BUS trap (due to a "yellow" stack overflow condition)
TRAP_MMU: 0x40,
TRAP_MASK: 0x70,
Expand Down Expand Up @@ -246,48 +289,6 @@ var PDP11 = {
SP: 6,
PC: 7,
},
/*
* PDP-11 trap vectors
*/
TRAP: {
UNDEFINED: 0x00, // 000 (reserved)
BUS: 0x04, // 004 unaligned address, non-existent memory, illegal instruction, etc
RESERVED: 0x08, // 010 reserved instructions
BPT: 0x0C, // 014 BPT: breakpoint trap (trace)
IOT: 0x10, // 020 IOT: input/output trap
PF: 0x14, // 024 power fail
EMT: 0x18, // 030 EMT: emulator trap
TRAP: 0x1C, // 034 TRAP instruction
PIRQ: 0xA0, // 240 PIRQ: program interrupt request
MMU: 0xA8 // 250 MMU: aborts and traps
},
/*
* PDP-11 trap reasons; the reason may also be a non-negative address indicating a BUS memory error
* (unaligned address or non-existent memory). Any reason >= RED (which includes BUS memory errors) generate
* immediate (thrown) traps; the rest generate synchronous traps.
*/
REASON: {
ABORT: -1, // immediate MMU fault
ILLEGAL: -2, // immediate invalid opcode (BUS)
RED: -3, // immediate stack overflow fault (BUS)
YELLOW: -4, // deferred stack overflow fault (BUS)
FAULT: -5, // deferred MMU fault
TRACE: -6, // deferred TF fault (BPT)
HALT: -7, // illegal HALT (BUS)
OPCODE: -8, // opcode-generated trap (eg, BPT, EMT, IOT, TRAP, or RESERVED opcode)
INTERRUPT: -9, // device-generated trap (vector is device-specific)
},
REASONS: [
"ABORT",
"ILLEGAL",
"RED",
"YELLOW",
"FAULT",
"TRACE",
"HALT",
"OPCODE",
"INTERRUPT"
],
/*
* Internal memory access flags
*/
Expand Down
12 changes: 6 additions & 6 deletions modules/pdp11/lib/panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,23 +176,23 @@ PanelPDP11.LED = {
};

/**
* getSW()
* getSR()
*
* @this {PanelPDP11}
* @return {number}
* @return {number} (current SWITCH register)
*/
PanelPDP11.prototype.getSW = function()
PanelPDP11.prototype.getSR = function()
{
return this.regSwitches;
};

/**
* setSW(value)
* setSR(value)
*
* @this {PanelPDP11}
* @param {number} value
* @param {number} value (new SWITCH register)
*/
PanelPDP11.prototype.setSW = function(value)
PanelPDP11.prototype.setSR = function(value)
{
this.setSwitches(value);
};
Expand Down
4 changes: 2 additions & 2 deletions modules/pdp11/lib/serialport.js
Original file line number Diff line number Diff line change
Expand Up @@ -662,12 +662,12 @@ SerialPortPDP11.prototype.readXCSR = function(addr)
SerialPortPDP11.prototype.writeXCSR = function(data, addr)
{
/*
* If the device is READY, and TIE is being set, then request an interrupt.
* If the device is READY, and TIE is being set, then request a hardware interrupt.
*
* Conversely, if TIE is being cleared, remove the request; this satisfies a test in MAINDEC TEST 15,
* which appears to clear, set, and clear the Transmitter Interrupt Enable (TIE) bit in rapid succession,
* with the expectation that NO interrupt will be generated. However, this fix also required a
* complementary change in setTrigger(), to signal an interrupt using INTQ_DELAY rather than INTQ.
* complementary change in setTrigger(), to request hardware interrupts with INTQ_DELAY rather than INTQ.
*/
if (this.xcsr & PDP11.DL11.XCSR.READY) {
if (data & PDP11.DL11.XCSR.TIE) {
Expand Down
Loading

0 comments on commit a8155cb

Please sign in to comment.