First cut at PDP-10 byte instructions

This commit is contained in:
Jeff 2017-03-02 23:10:24 -08:00 committed by Jeff Parsons
commit 25aa95cec8
7 changed files with 396 additions and 276 deletions

View file

@ -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;
};
/**

View file

@ -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;
}
/**

View file

@ -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) {

View file

@ -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
},