New improved PDP-10 processor flag handling
This commit is contained in:
parent
87e17a695c
commit
ffb7fa1221
6 changed files with 287 additions and 263 deletions
|
|
@ -251,7 +251,7 @@ PDP10.opILDB = function(op, acc)
|
|||
* We can implement this as a simple combination of opIBP() and opLDB(), but taking care that we only call
|
||||
* opIBP() on phase 1.
|
||||
*/
|
||||
if (this.regPS < 0) {
|
||||
if (this.regBP < 0) {
|
||||
//noinspection JSUnresolvedFunction
|
||||
PDP10.opIBP.call(this, op, acc);
|
||||
}
|
||||
|
|
@ -286,14 +286,14 @@ PDP10.opLDB = function(op, acc)
|
|||
* is with regEA containing the address of the bits to be loaded.
|
||||
*/
|
||||
var w = this.readWord(this.regEA);
|
||||
if (this.regPS < 0) {
|
||||
this.regPS = w;
|
||||
if (this.regBP < 0) {
|
||||
this.regBP = w;
|
||||
this.regRA = this.regEA | PDP10.OPCODE.I_BIT;
|
||||
this.advancePC(-1);
|
||||
return;
|
||||
}
|
||||
var p = (this.regPS / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
|
||||
var s = (this.regPS >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
|
||||
var p = (this.regBP / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
|
||||
var s = (this.regBP >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
|
||||
if (p + s <= 32) {
|
||||
/*
|
||||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
|
|
@ -310,7 +310,7 @@ PDP10.opLDB = function(op, acc)
|
|||
w = Math.trunc(w / Math.pow(2, p)) % Math.pow(2, s);
|
||||
}
|
||||
this.writeWord(acc, w);
|
||||
this.regPS = -1;
|
||||
this.regBP = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -341,7 +341,7 @@ PDP10.opIDPB = function(op, acc)
|
|||
* We can implement this as a simple combination of opIBP() and opDDB(), but taking care that we only call
|
||||
* opIBP() on phase 1.
|
||||
*/
|
||||
if (this.regPS < 0) {
|
||||
if (this.regBP < 0) {
|
||||
//noinspection JSUnresolvedFunction
|
||||
PDP10.opIBP.call(this, op, acc);
|
||||
}
|
||||
|
|
@ -376,14 +376,14 @@ PDP10.opDPB = function(op, acc)
|
|||
* is with regEA containing the address of the bits to be stored.
|
||||
*/
|
||||
var w = this.readWord(this.regEA);
|
||||
if (this.regPS < 0) {
|
||||
this.regPS = w;
|
||||
if (this.regBP < 0) {
|
||||
this.regBP = w;
|
||||
this.regRA = this.regEA | PDP10.OPCODE.I_BIT;
|
||||
this.advancePC(-1);
|
||||
return;
|
||||
}
|
||||
var p = (this.regPS / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
|
||||
var s = (this.regPS >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
|
||||
var p = (this.regBP / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
|
||||
var s = (this.regBP >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
|
||||
/*
|
||||
* Regarding the SPECIAL CONSIDERATIONS above, even if the P ("shift") and/or S ("mask") values are
|
||||
* over-large, we "mask" the resulting byte value (b) to 36 bits, so that when we re-assemble the final
|
||||
|
|
@ -392,7 +392,7 @@ PDP10.opDPB = function(op, acc)
|
|||
var b = ((this.readWord(acc) % Math.pow(2, s)) * Math.pow(2, p)) % PDP10.WORD_LIMIT;
|
||||
w = (w - (w % Math.pow(2, p + s))) + b + (w % Math.pow(2, p));
|
||||
this.writeWord(this.regEA, w);
|
||||
this.regPS = -1;
|
||||
this.regBP = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1436,14 +1436,14 @@ PDP10.opASH = function(op, acc)
|
|||
* If all those bits in the original value (w) were 0s, then adding bitsShifted to it could NOT
|
||||
* produce a value > MAX_POS36.
|
||||
*/
|
||||
if (w + bitsShifted > PDP10.MAX_POS36) this.fOverflow = true;
|
||||
if (w + bitsShifted > PDP10.MAX_POS36) this.regPS |= PDP10.PSFLAG.OVFL;
|
||||
} else {
|
||||
/*
|
||||
* Since w was negative, overflow occurs ONLY if any of the bits we shifted out were 0s.
|
||||
* If all those bits in the original value (w) were 1s, subtracting bitsShifted from it could NOT
|
||||
* produce a value <= MAX_POS36.
|
||||
*/
|
||||
if (w - bitsShifted <= PDP10.MAX_POS36) this.fOverflow = true;
|
||||
if (w - bitsShifted <= PDP10.MAX_POS36) this.regPS |= PDP10.PSFLAG.OVFL;
|
||||
}
|
||||
} else {
|
||||
if (s <= -35) {
|
||||
|
|
@ -1848,7 +1848,7 @@ PDP10.opPUSH = function(op, acc)
|
|||
p += 0o000001000001;
|
||||
this.writeWord(p & PDP10.HALF_MASK, this.readWord(this.regEA));
|
||||
if (p >= PDP10.WORD_LIMIT) p -= PDP10.WORD_LIMIT;
|
||||
if (!((p / PDP10.HALF_SHIFT)|0)) this.fPDOverflow = true;
|
||||
if (!((p / PDP10.HALF_SHIFT)|0)) this.regPS |= PDP10.PSFLAG.PD_OVFL;
|
||||
} else {
|
||||
/*
|
||||
* This is the SIMH behavior, which appears to increment each half of AC independently.
|
||||
|
|
@ -1858,7 +1858,7 @@ PDP10.opPUSH = function(op, acc)
|
|||
p = (p + 0o000001000000) - (p & PDP10.HALF_MASK) + addr;
|
||||
if (p >= PDP10.WORD_LIMIT) {
|
||||
p -= PDP10.WORD_LIMIT;
|
||||
this.fPDOverflow = true;
|
||||
this.regPS |= PDP10.PSFLAG.PD_OVFL;
|
||||
}
|
||||
}
|
||||
this.writeWord(acc, p);
|
||||
|
|
@ -1888,7 +1888,7 @@ PDP10.opPOP = function(op, acc)
|
|||
if (this.regEA == acc) p = src; // this avoids re-reading the accumulator if the write just overwrote it
|
||||
p -= 0o000001000001;
|
||||
if (p < 0) p += PDP10.WORD_LIMIT;
|
||||
if (((p / PDP10.HALF_SHIFT)|0) == PDP10.HALF_MASK) this.fPDOverflow = true;
|
||||
if (((p / PDP10.HALF_SHIFT)|0) == PDP10.HALF_MASK) this.regPS |= PDP10.PSFLAG.PD_OVFL;
|
||||
this.writeWord(acc, p);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -178,15 +178,14 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
this.regPC = this.lastPC = this.addrReset;
|
||||
|
||||
/*
|
||||
* This next internal reg is used only with byte instructions, to record an active byte
|
||||
* pointer state (regPS).
|
||||
* This next internal reg is used only with byte instructions, to record an active byte pointer.
|
||||
*/
|
||||
this.regPS = -1;
|
||||
this.regBP = -1;
|
||||
|
||||
/*
|
||||
* Assorted processor flags
|
||||
*/
|
||||
this.fOverflow = this.fCarry0 = this.fCarry1 = this.fNoDivide = this.fPDOverflow = false;
|
||||
this.regPS = 0;
|
||||
|
||||
/*
|
||||
* This is queried and displayed by the Panel when it's not displaying its own ADDRESS register
|
||||
|
|
@ -291,13 +290,9 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
this.regRA,
|
||||
this.regOP,
|
||||
this.regPC,
|
||||
this.regBP,
|
||||
this.regPS,
|
||||
this.opFlags,
|
||||
this.fOverflow,
|
||||
this.fCarry0,
|
||||
this.fCarry1,
|
||||
this.fNoDivide,
|
||||
this.fPDOverflow,
|
||||
this.lastPC,
|
||||
this.addrLast,
|
||||
this.addrReset
|
||||
|
|
@ -327,13 +322,9 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
this.regRA,
|
||||
this.regOP,
|
||||
this.regPC,
|
||||
this.regBP,
|
||||
this.regPS,
|
||||
this.opFlags,
|
||||
this.fOverflow,
|
||||
this.fCarry0,
|
||||
this.fCarry1,
|
||||
this.fNoDivide,
|
||||
this.fPDOverflow,
|
||||
this.lastPC,
|
||||
this.addrLast,
|
||||
this.addrReset
|
||||
|
|
@ -349,6 +340,19 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* getPS()
|
||||
*
|
||||
* Gets the processor state flags in the format required by various program control operations.
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @return {number}
|
||||
*/
|
||||
getPS()
|
||||
{
|
||||
return this.regPS & PDP10.HALF_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* readFlags()
|
||||
*
|
||||
|
|
@ -360,8 +364,8 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
readFlags()
|
||||
{
|
||||
var flags = 0;
|
||||
if (this.fOverflow) flags |= PDP10.RFLAG.OVFL;
|
||||
if (this.fPDOverflow) flags |= PDP10.RFLAG.PDOVFL;
|
||||
if (this.regPS & PDP10.PSFLAG.OVFL) flags |= PDP10.RFLAG.OVFL;
|
||||
if (this.regPS & PDP10.PSFLAG.PD_OVFL) flags |= PDP10.RFLAG.PD_OVFL;
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
|
@ -375,8 +379,8 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
writeFlags(w)
|
||||
{
|
||||
if (w & PDP10.WFLAG.OVFL_CL) this.fOverflow = false;
|
||||
if (w & PDP10.WFLAG.PDOVFL_CL) this.fPDOverflow = false;
|
||||
if (w & PDP10.WFLAG.OVFL_CL) this.regPS &= ~PDP10.PSFLAG.OVFL;
|
||||
if (w & PDP10.WFLAG.PD_OVFL_CL) this.regPS &= ~PDP10.PSFLAG.PD_OVFL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -507,7 +511,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
if (src != PDP10.MIN_NEG36) {
|
||||
src = PDP10.TWO_POW36 - src;
|
||||
} else {
|
||||
this.fOverflow = this.fCarry1 = true;
|
||||
this.regPS |= (PDP10.PSFLAG.OVFL | PDP10.PSFLAG.CARRY1);
|
||||
}
|
||||
}
|
||||
return src;
|
||||
|
|
@ -525,7 +529,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
negate(src)
|
||||
{
|
||||
if (!src) {
|
||||
this.fCarry0 = this.fCarry1 = true;
|
||||
this.regPS |= (PDP10.PSFLAG.CARRY0 | PDP10.PSFLAG.CARRY1);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
|
|
@ -533,7 +537,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
* the MIN_NEG36 case anyway, and since subtraction in that case doesn't alter src, we skip the subtraction.
|
||||
*/
|
||||
if (src == PDP10.MIN_NEG36) {
|
||||
this.fOverflow = this.fCarry1 = true;
|
||||
this.regPS |= (PDP10.PSFLAG.OVFL | PDP10.PSFLAG.CARRY1);
|
||||
} else {
|
||||
src = PDP10.TWO_POW36 - src;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
copyAddr(dbgAddr, dbgCopy)
|
||||
{
|
||||
dbgAddr.addr = dbgCopy.addr;
|
||||
dbgAddr.fPhysical = dbgCopy.fPhysical;
|
||||
dbgAddr.fTemporary = dbgCopy.fTemporary;
|
||||
dbgAddr.nBase = dbgCopy.nBase;
|
||||
return dbgAddr;
|
||||
|
|
@ -277,7 +278,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
*/
|
||||
packAddr(dbgAddr)
|
||||
{
|
||||
return [dbgAddr.addr, dbgAddr.fPhysical, dbgAddr.nBase, dbgAddr.fTemporary, dbgAddr.sCmd];
|
||||
return [dbgAddr.addr, dbgAddr.fPhysical, dbgAddr.fTemporary, dbgAddr.nBase, dbgAddr.sCmd];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -863,30 +864,31 @@ class DebuggerPDP10 extends Debugger {
|
|||
getRegValue(iReg)
|
||||
{
|
||||
var value;
|
||||
var cpu = this.cpu;
|
||||
switch(iReg) {
|
||||
case DebuggerPDP10.REGS.PC:
|
||||
value = this.cpu.getPC();
|
||||
value = cpu.getPC();
|
||||
break;
|
||||
case DebuggerPDP10.REGS.RA:
|
||||
value = this.cpu.regRA;
|
||||
value = cpu.regRA;
|
||||
break;
|
||||
case DebuggerPDP10.REGS.EA:
|
||||
value = this.cpu.regEA;
|
||||
value = cpu.regEA;
|
||||
break;
|
||||
case DebuggerPDP10.REGS.C0:
|
||||
value = this.cpu.fCarry0? 1 : 0;
|
||||
value = (cpu.regPS & PDP10.PSFLAG.CARRY0)? 1 : 0;
|
||||
break;
|
||||
case DebuggerPDP10.REGS.C1:
|
||||
value = this.cpu.fCarry1? 1 : 0;
|
||||
value = (cpu.regPS & PDP10.PSFLAG.CARRY1)? 1 : 0;
|
||||
break;
|
||||
case DebuggerPDP10.REGS.OV:
|
||||
value = this.cpu.fOverflow? 1 : 0;
|
||||
value = (cpu.regPS & PDP10.PSFLAG.OVFL)? 1 : 0;
|
||||
break;
|
||||
case DebuggerPDP10.REGS.ND:
|
||||
value = this.cpu.fNoDivide? 1 : 0;
|
||||
value = (cpu.regPS & PDP10.PSFLAG.NO_DIVIDE)? 1 : 0;
|
||||
break;
|
||||
case DebuggerPDP10.REGS.PD:
|
||||
value = this.cpu.fPDOverflow? 1 : 0;
|
||||
value = (cpu.regPS & PDP10.PSFLAG.PD_OVFL)? 1 : 0;
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
|
|
|
|||
|
|
@ -190,7 +190,27 @@ var PDP10 = {
|
|||
IRQ_MASK: 0x0003,
|
||||
DEBUGGER: 0x0004, // set if the Debugger wants to perform checks
|
||||
WAIT: 0x0008, // WAIT operation in progress
|
||||
PRESERVE: 0x000F, // OPFLAG bits to preserve prior to the next instruction
|
||||
PRESERVE: 0x000F // OPFLAG bits to preserve prior to the next instruction
|
||||
},
|
||||
|
||||
/*
|
||||
* Flags returned by getPS() for various program control operations.
|
||||
*/
|
||||
PSFLAG: {
|
||||
OVFL: 0o400000, // Overflow
|
||||
CARRY0: 0o200000, // Carry 0
|
||||
CARRY1: 0o100000, // Carry 1
|
||||
FP_OVFL: 0o040000, // Floating-Point Overflow
|
||||
BYTE_INT: 0o020000, // Byte Interrupt
|
||||
USER_MODE: 0o010000, // Processor is in User Mode
|
||||
USER_IO: 0o004000, // User I/O
|
||||
FP_UNFL: 0o000100, // Floating-Point Underflow
|
||||
NO_DIVIDE: 0o000040, // No Divide
|
||||
/*
|
||||
* Only the low 18 bits (above) are returned by getPS(); the following (bits 18 to 31)
|
||||
* are defined for internal use only.
|
||||
*/
|
||||
PD_OVFL: 0o1000000 // Pushdown Overflow
|
||||
},
|
||||
|
||||
/*
|
||||
|
|
@ -201,15 +221,15 @@ var PDP10 = {
|
|||
OVFL: 0o000010, // Overflow
|
||||
OVFL_IE: 0o000020, // Overflow Interrupt Enabled
|
||||
TRAP_OFF: 0o000040, // Trap Offset
|
||||
FPOVFL: 0o000100, // Floating-Point Overflow
|
||||
FPOVFL_IE: 0o000200, // Floating-Point Overflow Interrupt Enabled
|
||||
FP_OVFL: 0o000100, // Floating-Point Overflow
|
||||
FP_OVFL_IE: 0o000200, // Floating-Point Overflow Interrupt Enabled
|
||||
CLOCK: 0o001000, // Clock Flag
|
||||
CLOCK_IE: 0o002000, // Clock Interrupt Enabled
|
||||
NXM: 0o010000, // Non-Existent Memory
|
||||
PRM: 0o020000, // Memory Protection
|
||||
ADB: 0o040000, // Address Break
|
||||
UIO: 0o100000, // User In-Out
|
||||
PDOVFL: 0o200000 // Pushdown Overflow (TODO: Verify this is correct; the May 1968 doc may have a typo)
|
||||
PD_OVFL: 0o200000 // Pushdown Overflow (TODO: Verify this is correct; the May 1968 doc may have a typo)
|
||||
},
|
||||
|
||||
/*
|
||||
|
|
@ -222,9 +242,9 @@ var PDP10 = {
|
|||
OVFL_CL: 0o000010, // Clear Overflow
|
||||
OVFL_IE: 0o000020, // Enable Overflow Interrupt
|
||||
OVFL_ID: 0o000040, // Disable Overflow Interrupt
|
||||
FPOVFL_CL: 0o000100, // Clear Floating-Point Overflow
|
||||
FPOVFL_IE: 0o000200, // Enable Floating-Point Overflow Interrupt
|
||||
FPOVFL_ID: 0o000400, // Disable Floating-Point Overflow Interrupt
|
||||
FP_OVFL_CL: 0o000100, // Clear Floating-Point Overflow
|
||||
FP_OVFL_IE: 0o000200, // Enable Floating-Point Overflow Interrupt
|
||||
FP_OVFL_ID: 0o000400, // Disable Floating-Point Overflow Interrupt
|
||||
CLOCK_CL: 0o001000, // Clear Clock Flag
|
||||
CLOCK_IE: 0o002000, // Enable Clock Interrupt
|
||||
CLOCK_ID: 0o004000, // Disable Clock Interrupt
|
||||
|
|
@ -232,7 +252,7 @@ var PDP10 = {
|
|||
PRM_CL: 0o020000, // Clear Memory Protection
|
||||
ADB_CL: 0o040000, // Clear Address Break
|
||||
UIO_CL: 0o200000, // Clear All In-Out Devices
|
||||
PDOVFL_CL: 0o400000 // Clear Pushdown Overflow
|
||||
PD_OVFL_CL: 0o400000 // Clear Pushdown Overflow
|
||||
},
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue