First cut at PDP-10 byte instructions
This commit is contained in:
parent
affaa1075c
commit
25aa95cec8
7 changed files with 396 additions and 276 deletions
|
|
@ -188,11 +188,27 @@ PDP10.opFSC = function(op, acc)
|
|||
*/
|
||||
PDP10.opIBP = function(op, acc)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
var w = this.readWord(this.regEA);
|
||||
var p = (w / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
|
||||
var s = (w >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
|
||||
p -= s;
|
||||
if (p < 0) {
|
||||
p = 36 - s;
|
||||
w++;
|
||||
}
|
||||
w = (p * PDP10.OPCODE.P_SCALE) + (s << PDP10.OPCODE.S_SHIFT) + (w & PDP10.OPCODE.PTR_MASK);
|
||||
this.writeWord(this.regEA, w);
|
||||
};
|
||||
|
||||
/**
|
||||
* opILDB(0o134000)
|
||||
* opILDB(0o134000): Increment Pointer and Load Byte
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
|
||||
*
|
||||
* Increment the byte pointer in location E as explained above. Then retrieve a byte of S bits from the
|
||||
* location and position specified by the newly incremented pointer, load it into the right end of AC,
|
||||
* and clear the remaining AC bits. The location containing the byte is unaffected, the original contents
|
||||
* of AC are lost.
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
|
|
@ -200,11 +216,30 @@ PDP10.opIBP = function(op, acc)
|
|||
*/
|
||||
PDP10.opILDB = function(op, acc)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
/*
|
||||
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
|
||||
* is with regEA containing the address of the bits to be loaded.
|
||||
*
|
||||
* 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) {
|
||||
//noinspection JSUnresolvedFunction
|
||||
PDP10.opIBP.call(this, op, acc);
|
||||
}
|
||||
|
||||
//noinspection JSUnresolvedFunction
|
||||
PDP10.opLDB.call(this, op, acc);
|
||||
};
|
||||
|
||||
/**
|
||||
* opLDB(0o135000)
|
||||
* opLDB(0o135000): Load Byte
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
|
||||
*
|
||||
* Retrieve a byte of S bits from the location and position specified by the pointer contained in location E,
|
||||
* load it into the right end of AC, and clear the remaining AC bits. The location containing the byte is unaffected,
|
||||
* the original contents of AC are lost.
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
|
|
@ -212,23 +247,67 @@ PDP10.opILDB = function(op, acc)
|
|||
*/
|
||||
PDP10.opLDB = function(op, acc)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
/*
|
||||
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
|
||||
* 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;
|
||||
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;
|
||||
if (p + s <= 32) {
|
||||
w = (w >> p) & ((1 << s) - 1);
|
||||
} else {
|
||||
w = Math.trunc(w / Math.pow(2, p)) % Math.pow(2, s);
|
||||
}
|
||||
this.writeWord(acc, w);
|
||||
this.regPS = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* opIDPB(0o136000)
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
|
||||
*
|
||||
* Increment the byte pointer in location E as explained above. Then deposit the right S bits of AC into
|
||||
* the location and position specified by the newly incremented pointer. The original contents of the bits
|
||||
* that receive the byte are lost, AC and the remaining bits of the deposit location are unaffected.
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
* @param {number} acc
|
||||
*/
|
||||
PDP10.opIDPB = function(op, acc)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
/*
|
||||
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
|
||||
* is with regEA containing the address of the bits to be stored.
|
||||
*
|
||||
* 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) {
|
||||
//noinspection JSUnresolvedFunction
|
||||
PDP10.opIBP.call(this, op, acc);
|
||||
}
|
||||
|
||||
//noinspection JSUnresolvedFunction
|
||||
PDP10.opDPB.call(this, op, acc);
|
||||
};
|
||||
|
||||
/**
|
||||
* opDPB(0o137000)
|
||||
* opDPB(0o137000): Deposit Byte
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
|
||||
*
|
||||
* Deposit the right S bits of AC into the location and position specified by the pointer contained
|
||||
* in location E. The original contents of the bits that receive the byte are lost, AC and the remaining
|
||||
* bits of the deposit location are unaffected.
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
|
|
@ -236,7 +315,23 @@ PDP10.opIDPB = function(op, acc)
|
|||
*/
|
||||
PDP10.opDPB = function(op, acc)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
/*
|
||||
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
|
||||
* 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;
|
||||
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 b = (this.readWord(acc) % Math.pow(2, s)) * Math.pow(2, p);
|
||||
w = (w - (w % Math.pow(2, p + s))) + b + (w % Math.pow(2, p));
|
||||
this.writeWord(this.regEA, w);
|
||||
this.regPS = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -178,6 +178,12 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
this.regPC = this.lastPC = this.addrReset;
|
||||
this.fOverflow = this.fCarry0 = this.fCarry1 = this.fNoDivide = this.fPDOverflow = false;
|
||||
|
||||
/*
|
||||
* This next two internal regs are used only with byte instructions, to record an active byte
|
||||
* pointer state (regPS) and pointer address (regPA).
|
||||
*/
|
||||
this.regPS = this.regPA = -1;
|
||||
|
||||
/*
|
||||
* This is queried and displayed by the Panel when it's not displaying its own ADDRESS register
|
||||
* (which takes precedence when, for example, you've manually halted the CPU and are independently
|
||||
|
|
@ -279,6 +285,8 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
state.set(0, [
|
||||
this.regEA,
|
||||
this.regRA,
|
||||
this.regPS,
|
||||
this.regPA,
|
||||
this.regOP,
|
||||
this.regPC,
|
||||
this.lastPC,
|
||||
|
|
@ -308,6 +316,8 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
[
|
||||
this.regEA,
|
||||
this.regRA,
|
||||
this.regPS,
|
||||
this.regPA,
|
||||
this.regOP,
|
||||
this.regPC,
|
||||
this.lastPC,
|
||||
|
|
@ -369,7 +379,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
if (this.regRA & PDP10.OPCODE.I_BIT) return -1;
|
||||
|
||||
this.regPC = (this.regPC + 1) % PDP10.ADDR_LIMIT;
|
||||
return (this.regOP / PDP10.OPCODE.ACSHIFT)|0;
|
||||
return (this.regOP / PDP10.OPCODE.A_SCALE)|0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1415,7 +1415,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
findInstruction(opCode, fOperands = true)
|
||||
{
|
||||
var opNum, opMask, aModes, iMode = 0;
|
||||
var op = (opCode / PDP10.OPCODE.OPSHIFT)|0;
|
||||
var op = (opCode / PDP10.OPCODE.OP_SCALE)|0;
|
||||
|
||||
for (var mask in DebuggerPDP10.OPTABLE) {
|
||||
var opMasks = DebuggerPDP10.OPTABLE[mask];
|
||||
|
|
@ -1423,7 +1423,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
if (opNum) {
|
||||
opMask = +mask;
|
||||
/*
|
||||
* When we extracted op from opCode using OPSHIFT, we included 6 additional bits
|
||||
* When we extracted op from opCode using OP_SCALE, we included 6 additional bits
|
||||
* to help distinguish OPIO instructions from non-OPIO instructions. But for the
|
||||
* following tests, we don't need those bits, so we get rid of them now.
|
||||
*/
|
||||
|
|
@ -1458,7 +1458,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
sOperation += this.toStrWord(opCode);
|
||||
} else {
|
||||
if (opMask == PDP10.OPCODE.OPIO) {
|
||||
sOperation += this.toStrBase((opCode / PDP10.OPCODE.IOSHIFT) & PDP10.OPCODE.IOMASK, -1);
|
||||
sOperation += this.toStrBase((opCode / PDP10.OPCODE.IO_SCALE) & PDP10.OPCODE.IO_MASK, -1);
|
||||
} else {
|
||||
sOperation += this.toStrBase((opCode >> PDP10.OPCODE.A_SHIFT) & PDP10.OPCODE.A_MASK, -1);
|
||||
}
|
||||
|
|
@ -1564,7 +1564,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
} else {
|
||||
opMode = ((iMode & 0o3) << 1) | ((iMode & 0o14) << 2);
|
||||
}
|
||||
opCode = (op | (opMode << 6)) * PDP10.OPCODE.OPSHIFT;
|
||||
opCode = (op | (opMode << 6)) * PDP10.OPCODE.OP_SCALE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1601,12 +1601,12 @@ class DebuggerPDP10 extends Debugger {
|
|||
}
|
||||
if (!i && aOperands.length > 1) {
|
||||
if (opMask == PDP10.OPCODE.OPIO) {
|
||||
if (operand < 0 || operand > PDP10.OPCODE.IOMASK) {
|
||||
if (operand < 0 || operand > PDP10.OPCODE.IO_MASK) {
|
||||
this.println("device code out of range: " + match[2]);
|
||||
opCode = -1;
|
||||
break;
|
||||
}
|
||||
opCode += (operand * PDP10.OPCODE.IOSHIFT);
|
||||
opCode += (operand * PDP10.OPCODE.IO_SCALE);
|
||||
}
|
||||
else {
|
||||
if (operand < 0 || operand > PDP10.OPCODE.A_MASK) {
|
||||
|
|
|
|||
|
|
@ -158,10 +158,14 @@ var PDP10 = {
|
|||
OPTEST: 0o71100, // operation with test
|
||||
OPIO: 0o70034, // input-output operation
|
||||
OPUUO: 0o70000, // unimplemented user operation (UUO) mask
|
||||
OPSHIFT: Math.pow(2, 21), // operation shift
|
||||
IOSHIFT: Math.pow(2, 26), // input-output device code shift
|
||||
IOMASK: 0o177, // input-output device code mask (after shift)
|
||||
ACSHIFT: Math.pow(2, 23), // used to shift down the high 13 bits, with A starting at bit 0
|
||||
OP_SCALE: Math.pow(2, 21), // operation scale
|
||||
IO_SCALE: Math.pow(2, 26), // input-output device code scale
|
||||
IO_MASK: 0o177, // input-output device code mask (after descale)
|
||||
A_SCALE: Math.pow(2, 23), // used to shift down the high 13 bits, with A starting at bit 0
|
||||
P_SCALE: Math.pow(2, 30), // P scale
|
||||
P_MASK: 0o77, // P mask (after descale)
|
||||
S_SHIFT: 24, // S shift
|
||||
S_MASK: 0o77, // S mask (after shift)
|
||||
A_SHIFT: 23, // A shift
|
||||
A_MASK: 0o17, // A mask (after shift)
|
||||
I_BIT: 0o20000000, // indirect bit
|
||||
|
|
@ -169,6 +173,7 @@ var PDP10 = {
|
|||
X_MASK: 0o17, // X mask (after shift)
|
||||
Y_MASK: 0o777777, // Y mask
|
||||
R_MASK: 0o37777777, // used to isolate the low 23 bits (I,X,Y)
|
||||
PTR_MASK: 0o77777777, // used to isolate the low 24 bits (?,I,X,Y) of a byte pointer
|
||||
HALT: 0o5304 // operation code for HALT
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue