Added preliminary PDP-10 opcode decoding
This commit is contained in:
parent
3e30bde786
commit
e3ab5b1ed5
4 changed files with 1302 additions and 904 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -124,6 +124,9 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
this.model = model;
|
||||
this.addrReset = +parmsCPU['addrReset'] || 0;
|
||||
|
||||
this.opDecode = PDP10.opKA10.bind(this);
|
||||
this.opUndefined = PDP10.opUndefined.bind(this);
|
||||
|
||||
/** @type {IRQ|null} */
|
||||
this.irqNext = null; // the head of the active IRQ list, in priority order
|
||||
|
||||
|
|
@ -171,7 +174,8 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
initCPU()
|
||||
{
|
||||
this.regPC = this.pcLast = this.addrReset;
|
||||
this.regEA = 0;
|
||||
this.regPC = this.lastPC = this.addrReset;
|
||||
|
||||
/*
|
||||
* This is queried and displayed by the Panel when it's not displaying its own ADDRESS register
|
||||
|
|
@ -180,7 +184,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*
|
||||
* We initialize it to the current PC.
|
||||
*/
|
||||
this.addrLast = this.regPC;
|
||||
this.lastAddr = this.regPC;
|
||||
|
||||
/*
|
||||
* opFlags contains various conditions that stepCPU() needs to be aware of.
|
||||
|
|
@ -272,9 +276,10 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
{
|
||||
var state = new State(this);
|
||||
state.set(0, [
|
||||
this.regEA,
|
||||
this.regPC,
|
||||
this.pcLast,
|
||||
this.addrLast,
|
||||
this.lastPC,
|
||||
this.lastAddr,
|
||||
this.opFlags
|
||||
]);
|
||||
state.set(1, []);
|
||||
|
|
@ -298,9 +303,10 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
* of what save() does when it collects a bunch of object properties into an array.
|
||||
*/
|
||||
[
|
||||
this.regEA,
|
||||
this.regPC,
|
||||
this.pcLast,
|
||||
this.addrLast,
|
||||
this.lastPC,
|
||||
this.lastAddr,
|
||||
this.opFlags
|
||||
] = data[0];
|
||||
|
||||
|
|
@ -317,17 +323,44 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
/**
|
||||
* getOpcode()
|
||||
*
|
||||
* NOTE: This function is nothing more than a convenience, and we fully expect it to be inlined at runtime.
|
||||
* This fetches the next opcode, decodes the low 23 bits (I,X,Y), sets regEA, and returns the
|
||||
* the high 18 bits for further decoding. While it's true that, in general, only the high 13 bits
|
||||
* are relevant to the operation, it's cleaner to treat the original opcode as two half-words.
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @return {number}
|
||||
*/
|
||||
getOpcode()
|
||||
{
|
||||
var pc = this.pcLast = this.regPC;
|
||||
var pc = this.lastPC = this.regPC;
|
||||
var opCode = this.readWord(pc);
|
||||
this.regPC = (pc + 1) % PDP10.ADDR_LIMIT;
|
||||
return opCode;
|
||||
var e, x, r = opCode, nMaxIndirect = 4;
|
||||
while (true) {
|
||||
/*
|
||||
* Bits 0-22 (I,X,Y) contain what we call a "reference address" (R), which is used to calculate the
|
||||
* "effective address" (E). To determine E from R, we must extract I, X, and Y from R, set E to Y,
|
||||
* then add [X] to E if X is non-zero. If I is zero, then we're done; otherwise, we must set R to [E]
|
||||
* and repeat the process.
|
||||
*/
|
||||
e = r & PDP10.OPCODE.Y_MASK;
|
||||
x = (r >> PDP10.OPCODE.X_SHIFT) & PDP10.OPCODE.X_MASK;
|
||||
if (x) e = (e + this.readWord(x)) & PDP10.ADDR_MASK;
|
||||
if (!(r & PDP10.OPCODE.I_BIT)) break;
|
||||
/*
|
||||
* We allow this process to repeat only a few times, because more than that suggests we're executing
|
||||
* garbage. Also, allowing this to loop endlessly would hang the simulation; if it turns out there is
|
||||
* real-world PDP-10 code that requires a long series of indirections, we should factor this logic out
|
||||
* as a separate operation. Note that would mean passing the full opcode on to the next level of decoding.
|
||||
*/
|
||||
if (--nMaxIndirect < 0) {
|
||||
this.bus.fault(r);
|
||||
break;
|
||||
}
|
||||
r = this.readWord(e);
|
||||
}
|
||||
this.regEA = e;
|
||||
return (opCode / PDP10.ADDR_LIMIT)|0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -367,7 +400,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
getLastAddr()
|
||||
{
|
||||
return this.addrLast;
|
||||
return this.lastAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -378,7 +411,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
getLastPC()
|
||||
{
|
||||
return this.pcLast;
|
||||
return this.lastPC;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -659,7 +692,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
readWordFromPhysical(addr)
|
||||
{
|
||||
return this.bus.getWord(this.addrLast = addr);
|
||||
return this.bus.getWord(this.lastAddr = addr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -673,7 +706,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
writeWordToPhysical(addr, data)
|
||||
{
|
||||
this.bus.setWord(this.addrLast = addr, data);
|
||||
this.bus.setWord(this.lastAddr = addr, data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -775,8 +808,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
this.opFlags &= PDP10.OPFLAG.PRESERVE;
|
||||
|
||||
var opCode = this.getOpcode();
|
||||
|
||||
// this.decode(opCode);
|
||||
this.opDecode(opCode);
|
||||
|
||||
} while (this.nStepCycles > 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ var PDP10 = {
|
|||
*/
|
||||
ADDR_INVALID: -1,
|
||||
ADDR_LIMIT: Math.pow(2, 18),
|
||||
ADDR_MASK: Math.pow(2, 18) - 1,
|
||||
DATA_INVALID: -1,
|
||||
DATA_LIMIT: Math.pow(2, 36),
|
||||
|
||||
|
|
@ -128,10 +129,10 @@ var PDP10 = {
|
|||
* 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
* 1 1 1 D D D D D D D O O O I X X X X Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
|
||||
*
|
||||
* Bits 0-22 (I,X,Y) contain what we call a "reference address" (R), which is used to
|
||||
* calculate the "effective address" (E). To determine E from R, we must extract I, X,
|
||||
* and Y from R, set E to Y, then add [X] to E if X is non-zero. If I is zero, then
|
||||
* we're done; otherwise, we must set set R to [E] and repeat the process.
|
||||
* Bits 0-22 (I,X,Y) contain what we call a "reference address" (R), which is used to calculate the
|
||||
* "effective address" (E). To determine E from R, we must extract I, X, and Y from R, set E to Y,
|
||||
* then add [X] to E if X is non-zero. If I is zero, then we're done; otherwise, we must set R to [E]
|
||||
* and repeat the process.
|
||||
*/
|
||||
OPCODE: {
|
||||
OPMASK: 0o77700, // operation mask
|
||||
|
|
@ -145,8 +146,6 @@ var PDP10 = {
|
|||
FNMASK: 0o17, // accumulator/function mask (after shift)
|
||||
IOSHIFT: Math.pow(2, 26), // input-output device code shift
|
||||
IOMASK: 0o177, // input-output device code mask (after shift)
|
||||
O_SHIFT: Math.pow(2, 27), // operation shift
|
||||
O_MASK: 0o777, // operation mask (after shift)
|
||||
I_BIT: 0o20000000, // indirect bit
|
||||
X_SHIFT: 18, // X shift
|
||||
X_MASK: 0o17, // X mask (after shift)
|
||||
|
|
|
|||
|
|
@ -167,14 +167,14 @@ class CPUStatePDP11 extends CPUPDP11 {
|
|||
this.maskRegSrcByte = 0xff;
|
||||
|
||||
if (this.model <= PDP11.MODEL_1120) {
|
||||
this.decode = PDP11.op1120.bind(this);
|
||||
this.opDecode = PDP11.op1120.bind(this);
|
||||
this.checkStackLimit = this.checkStackLimit1120;
|
||||
this.offRegSrc = 8;
|
||||
this.maskRegSrcByte = -1;
|
||||
this.pswUsed = ~(PDP11.PSW.UNUSED | PDP11.PSW.REGSET | PDP11.PSW.PMODE | PDP11.PSW.CMODE) & 0xffff;
|
||||
this.pswRegSet = 0;
|
||||
} else {
|
||||
this.decode = PDP11.op1140.bind(this);
|
||||
this.opDecode = PDP11.op1140.bind(this);
|
||||
this.checkStackLimit = this.checkStackLimit1140;
|
||||
/*
|
||||
* The alternate register set (REGSET) doesn't exist on the 11/20 or 11/40; it's available on the 11/45 and 11/70.
|
||||
|
|
@ -3058,7 +3058,7 @@ class CPUStatePDP11 extends CPUPDP11 {
|
|||
this.opFlags = (this.opFlags & PDP11.OPFLAG.PRESERVE) | (this.regPSW & PDP11.PSW.TF);
|
||||
|
||||
var opCode = this.getOpcode();
|
||||
this.decode(opCode);
|
||||
this.opDecode(opCode);
|
||||
|
||||
} while (this.nStepCycles > 0);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue