Fixed RTI on older PDP-11s (ie, 11/20); the old RTI behaves like the new RTT, which did not exist on older machines
This commit is contained in:
parent
d533ae69aa
commit
0607d65b70
8 changed files with 163 additions and 140 deletions
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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.
|
||||
*
|
||||
|
|
@ -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
|
||||
|
|
@ -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()).
|
||||
*
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -1127,7 +1127,7 @@ if (DEBUGGER) {
|
|||
case "PC":
|
||||
iReg = 7;
|
||||
break;
|
||||
case "SW":
|
||||
case "SR":
|
||||
iReg = 21;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue