Tested a couple half-word instructions (so far, so good)
This commit is contained in:
parent
0255b7b891
commit
17e807ecb6
8 changed files with 479 additions and 579 deletions
|
|
@ -540,7 +540,7 @@ class BusPDP10 extends Component {
|
|||
*
|
||||
* @this {BusPDP10}
|
||||
* @param {number} addr is a physical address
|
||||
* @param {number} w is the word (36-bit) value to write (we truncate it to 16 bits to be safe)
|
||||
* @param {number} w is the word (36-bit) value to write
|
||||
*/
|
||||
setWordDirect(addr, w)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2651,7 +2651,7 @@ PDP10.opSETOB = function(op)
|
|||
};
|
||||
|
||||
/**
|
||||
* opHLL(0o500000): Half Word Left to Left
|
||||
* opHLL(0o5N0000): Half Word Left to Left
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-3:
|
||||
*
|
||||
|
|
@ -2668,12 +2668,12 @@ PDP10.opHLL = function(op)
|
|||
var a = op & PDP10.OPCODE.A_MASK;
|
||||
var src = this.readWord(this.regEA);
|
||||
var dst = this.readWord(a);
|
||||
dst = (dst & PDP10.WORD_MASK) + (src - (src & PDP10.WORD_MASK));
|
||||
dst = PDP10.setHR(op, dst, src) + (src - (src & PDP10.WORD_MASK));
|
||||
this.writeWord(a, dst);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLI(0o501000): Half Word Left to Left, Immediate
|
||||
* opHLLI(0o5N1000): Half Word Left to Left, Immediate
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-3:
|
||||
*
|
||||
|
|
@ -2692,12 +2692,12 @@ PDP10.opHLLI = function(op)
|
|||
{
|
||||
var a = op & PDP10.OPCODE.A_MASK;
|
||||
var dst = this.readWord(a);
|
||||
dst = (dst & PDP10.WORD_MASK);
|
||||
dst = PDP10.setHR(op, dst, 0);
|
||||
this.writeWord(a, dst);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLM(0o502000): Half Word Left to Left, Memory
|
||||
* opHLLM(0o5N2000): Half Word Left to Left, Memory
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-3:
|
||||
*
|
||||
|
|
@ -2714,12 +2714,12 @@ PDP10.opHLLM = function(op)
|
|||
var a = op & PDP10.OPCODE.A_MASK;
|
||||
var src = this.readWord(a);
|
||||
var dst = this.readWord(this.regEA);
|
||||
dst = (dst & PDP10.WORD_MASK) + (src - (src & PDP10.WORD_MASK));
|
||||
dst = PDP10.setHR(op, dst, src) + (src - (src & PDP10.WORD_MASK));
|
||||
this.writeWord(this.regEA, dst);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLS(0o503000): Half Word Left to Left, Self
|
||||
* opHLLS(0o5N3000): Half Word Left to Left, Self
|
||||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-3:
|
||||
*
|
||||
|
|
@ -2735,7 +2735,13 @@ PDP10.opHLLM = function(op)
|
|||
*/
|
||||
PDP10.opHLLS = function(op)
|
||||
{
|
||||
if (op & PDP10.OPCODE.A_MASK) PDP10.opHLL.call(this, op);
|
||||
var dst = this.readWord(this.regEA);
|
||||
this.writeWord(this.regEA, PDP10.setHR(op, dst, dst));
|
||||
var a = op & PDP10.OPCODE.A_MASK;
|
||||
if (a) {
|
||||
dst = this.readWord(a);
|
||||
this.writeWord(a, PDP10.setHR(op, dst, dst));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2831,50 +2837,6 @@ PDP10.opHRLS = function(op)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLZ(0o510000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLZ = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLZI(0o511000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLZI = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLZM(0o512000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLZM = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLZS(0o513000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLZS = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHRLZ(0o514000)
|
||||
*
|
||||
|
|
@ -2919,50 +2881,6 @@ PDP10.opHRLZS = function(op)
|
|||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLO(0o520000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLO = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLOI(0o521000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLOI = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLOM(0o522000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLOM = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLOS(0o523000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLOS = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHRLO(0o524000)
|
||||
*
|
||||
|
|
@ -3007,50 +2925,6 @@ PDP10.opHRLOS = function(op)
|
|||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLE(0o530000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLE = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLEI(0o531000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLEI = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLEM(0o532000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLEM = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHLLES(0o533000)
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
*/
|
||||
PDP10.opHLLES = function(op)
|
||||
{
|
||||
this.opUndefined(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* opHRLE(0o534000)
|
||||
*
|
||||
|
|
@ -4355,6 +4229,56 @@ PDP10.opUndefined = function(op)
|
|||
this.stopCPU();
|
||||
};
|
||||
|
||||
/**
|
||||
* setHR(op, dst, src)
|
||||
*
|
||||
* @param {number} op
|
||||
* @param {number} dst (36-bit value whose 18-bit right half is either preserved or modified)
|
||||
* @param {number} src (36-bit value used to determine the sign extension, if any, for the right half of dst)
|
||||
* @return {number} (updated dst)
|
||||
*/
|
||||
PDP10.setHR = function(op, dst, src)
|
||||
{
|
||||
switch(op & 0o600) {
|
||||
case 0o000:
|
||||
dst = (dst & PDP10.WORD_MASK);
|
||||
break;
|
||||
case 0o200:
|
||||
dst = 0;
|
||||
break;
|
||||
case 0o400:
|
||||
dst = PDP10.WORD_MASK;
|
||||
break;
|
||||
case 0o600:
|
||||
dst = (src > PDP10.MAX_POS? PDP10.WORD_MASK : 0);
|
||||
break;
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
/*
|
||||
* If we want the basic half-word operations to handle all the sub-operations; ie:
|
||||
*
|
||||
* None
|
||||
* Zero-extend
|
||||
* One-extend
|
||||
* Sign-extend
|
||||
*
|
||||
* then we need to alias all the sub-functions to the corresponding primary functions.
|
||||
*/
|
||||
PDP10.opHLLZ = PDP10.opHLL;
|
||||
PDP10.opHLLZI = PDP10.opHLLI;
|
||||
PDP10.opHLLZM = PDP10.opHLLM;
|
||||
PDP10.opHLLZS = PDP10.opHLLS;
|
||||
PDP10.opHLLO = PDP10.opHLL;
|
||||
PDP10.opHLLOI = PDP10.opHLLI;
|
||||
PDP10.opHLLOM = PDP10.opHLLM;
|
||||
PDP10.opHLLOS = PDP10.opHLLS;
|
||||
PDP10.opHLLE = PDP10.opHLL;
|
||||
PDP10.opHLLEI = PDP10.opHLLI;
|
||||
PDP10.opHLLEM = PDP10.opHLLM;
|
||||
PDP10.opHLLES = PDP10.opHLLS;
|
||||
|
||||
PDP10.aOpXXX_KA10 = [
|
||||
PDP10.opUUO, // 0o000xxx
|
||||
PDP10.opUUO, // 0o001xxx
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ var PDP10 = {
|
|||
DATA_LIMIT: Math.pow(2, 36),
|
||||
WORD_SHIFT: Math.pow(2, 18),
|
||||
WORD_MASK: 0o777777,
|
||||
MAX_POS: Math.pow(2, 35) - 1,
|
||||
|
||||
/*
|
||||
* PDP-10 opcodes are 36-bit values, most of which use the following layout:
|
||||
|
|
|
|||
|
|
@ -83,9 +83,7 @@ class MemoryPDP10 {
|
|||
this.type = type || MemoryPDP10.TYPE.NONE;
|
||||
this.fReadOnly = (type == MemoryPDP10.TYPE.ROM);
|
||||
this.dbg = null;
|
||||
this.readBits = this.readBitsDirect = this.readNone;
|
||||
this.readWord = this.readWordDirect = this.readNone;
|
||||
this.writeBits = this.writeBitsDirect = this.writeNone;
|
||||
this.writeWord = this.writeWordDirect = this.writeNone;
|
||||
this.cReadBreakpoints = this.cWriteBreakpoints = 0;
|
||||
this.copyBreakpoints(); // initialize the block's Debugger info; the caller will reinitialize
|
||||
|
|
@ -222,13 +220,11 @@ class MemoryPDP10 {
|
|||
/**
|
||||
* setAccess(afn, fDirect)
|
||||
*
|
||||
* The afn parameter should be a 4-entry function table containing two bits handlers and
|
||||
* two word handlers. See the static afnMemory table for an example.
|
||||
* The afn parameter should be a 2-entry function table containing word read and write handlers.
|
||||
* See the static afnMemory table for an example.
|
||||
*
|
||||
* If no function table is specified, a default is selected based on the Memory type;
|
||||
* similarly, any undefined entries in the table are filled with default handlers that fall
|
||||
* back to the bits handlers, and if one or both bits handlers are undefined, they default
|
||||
* to handlers that simply ignore the access.
|
||||
* If no function table is specified, a default is selected based on the Memory type; similarly,
|
||||
* any undefined entries in the table are filled with default handlers.
|
||||
*
|
||||
* fDirect indicates that both the default AND the direct handlers should be updated. Direct
|
||||
* handlers normally match the default handlers, except when "checked" handlers are installed;
|
||||
|
|
@ -260,12 +256,10 @@ class MemoryPDP10 {
|
|||
setReadAccess(afn, fDirect)
|
||||
{
|
||||
if (!fDirect || !this.cReadBreakpoints) {
|
||||
this.readBits = afn[0] || this.readNone;
|
||||
this.readWord = afn[2] || this.readNone;
|
||||
this.readWord = afn[0] || this.readNone;
|
||||
}
|
||||
if (fDirect || fDirect === undefined) {
|
||||
this.readBitsDirect = afn[0] || this.readNone;
|
||||
this.readWordDirect = afn[2] || this.readNone;
|
||||
this.readWordDirect = afn[0] || this.readNone;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -279,12 +273,10 @@ class MemoryPDP10 {
|
|||
setWriteAccess(afn, fDirect)
|
||||
{
|
||||
if (!fDirect || !this.cWriteBreakpoints) {
|
||||
this.writeBits = !this.fReadOnly && afn[1] || this.writeNone;
|
||||
this.writeWord = !this.fReadOnly && afn[3] || this.writeNone;
|
||||
this.writeWord = !this.fReadOnly && afn[1] || this.writeNone;
|
||||
}
|
||||
if (fDirect || fDirect === undefined) {
|
||||
this.writeBitsDirect = afn[1] || this.writeNone;
|
||||
this.writeWordDirect = afn[3] || this.writeNone;
|
||||
this.writeWordDirect = afn[1] || this.writeNone;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +287,6 @@ class MemoryPDP10 {
|
|||
*/
|
||||
resetReadAccess()
|
||||
{
|
||||
this.readBits = this.readBitsDirect;
|
||||
this.readWord = this.readWordDirect;
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +297,6 @@ class MemoryPDP10 {
|
|||
*/
|
||||
resetWriteAccess()
|
||||
{
|
||||
this.writeBits = this.fReadOnly? this.writeNone : this.writeBitsDirect;
|
||||
this.writeWord = this.fReadOnly? this.writeNone : this.writeWordDirect;
|
||||
}
|
||||
|
||||
|
|
@ -424,27 +414,6 @@ class MemoryPDP10 {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* readBitsMemory(off, addr, offBits, lenBits)
|
||||
*
|
||||
* @this {MemoryPDP10}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} offBits (the bit position of the right-most bit of the result, using modern bit numbering)
|
||||
* @param {number} lenBits
|
||||
* @return {number}
|
||||
*/
|
||||
readBitsMemory(off, addr, offBits, lenBits)
|
||||
{
|
||||
var w = this.aw[off];
|
||||
if (offBits + lenBits <= 32) {
|
||||
w = (w >> offBits) & ((1 << lenBits) - 1);
|
||||
} else {
|
||||
w = Math.trunc(w / Math.pow(2, offBits)) % Math.pow(2, lenBits);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* readWordMemory(off, addr)
|
||||
*
|
||||
|
|
@ -458,29 +427,6 @@ class MemoryPDP10 {
|
|||
return this.aw[off];
|
||||
}
|
||||
|
||||
/**
|
||||
* writeBitsMemory(bits, off, addr, offBits, lenBits)
|
||||
*
|
||||
* @this {MemoryPDP10}
|
||||
* @param {number} bits (only the right-most lenBits of bits are used, so it doesn't need to be pre-masked)
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} offBits (the bit position of the right-most bit of the result, using modern bit numbering)
|
||||
* @param {number} lenBits
|
||||
*/
|
||||
writeBitsMemory(bits, off, addr, offBits, lenBits)
|
||||
{
|
||||
var w = this.aw[off];
|
||||
var shiftBits = Math.pow(2, offBits);
|
||||
bits %= Math.pow(2, lenBits);
|
||||
var v = (w % Math.pow(2, offBits + lenBits));
|
||||
w = (w - v) + (bits * shiftBits) + (v % shiftBits);
|
||||
if (this.aw[off] != w) {
|
||||
this.aw[off] = w;
|
||||
this.fDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* writeWordMemory(w, off, addr)
|
||||
*
|
||||
|
|
@ -491,26 +437,10 @@ class MemoryPDP10 {
|
|||
*/
|
||||
writeWordMemory(w, off, addr)
|
||||
{
|
||||
this.aw[off] = w;
|
||||
this.fDirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* readBitsChecked(off, addr, offBits, lenBits)
|
||||
*
|
||||
* @this {MemoryPDP10}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} offBits (the bit position of the right-most bit of the result, using modern bit numbering)
|
||||
* @param {number} lenBits
|
||||
* @return {number}
|
||||
*/
|
||||
readBitsChecked(off, addr, offBits, lenBits)
|
||||
{
|
||||
if (DEBUGGER && this.dbg && this.addr != null) {
|
||||
this.dbg.checkMemoryRead(this.addr + off);
|
||||
if (this.aw[off] != w) {
|
||||
this.aw[off] = w;
|
||||
this.fDirty = true;
|
||||
}
|
||||
return this.readBitsDirect(off, addr, offBits, lenBits);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -529,24 +459,6 @@ class MemoryPDP10 {
|
|||
return this.readWordDirect(off, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* writeBitsChecked(bits, off, addr, offBits, lenBits)
|
||||
*
|
||||
* @this {MemoryPDP10}
|
||||
* @param {number} bits
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} offBits (the bit position of the right-most bit of the result, using modern bit numbering)
|
||||
* @param {number} lenBits
|
||||
*/
|
||||
writeBitsChecked(bits, off, addr, offBits, lenBits)
|
||||
{
|
||||
if (DEBUGGER && this.dbg && this.addr != null) {
|
||||
this.dbg.checkMemoryWrite(this.addr + off);
|
||||
}
|
||||
if (this.fReadOnly) this.writeNone(bits, off, addr); else this.writeBitsDirect(bits, off, addr, offBits, lenBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* writeWordChecked(w, off, addr)
|
||||
*
|
||||
|
|
@ -587,11 +499,9 @@ MemoryPDP10.idBlock = 0;
|
|||
|
||||
/*
|
||||
* This is the effective definition of afnNone, but we need not fully define it, because setAccess()
|
||||
* uses these defaults when any of the 4 handlers (ie, 2 bits handlers and 2 word handlers) are undefined.
|
||||
* uses these defaults when any of the handlers are undefined.
|
||||
*
|
||||
MemoryPDP10.afnNone = [
|
||||
MemoryPDP10.prototype.readNone,
|
||||
MemoryPDP10.prototype.writeNone,
|
||||
MemoryPDP10.prototype.readNone,
|
||||
MemoryPDP10.prototype.writeNone
|
||||
];
|
||||
|
|
@ -599,15 +509,11 @@ MemoryPDP10.afnNone = [
|
|||
MemoryPDP10.afnNone = [];
|
||||
|
||||
MemoryPDP10.afnMemory = [
|
||||
MemoryPDP10.prototype.readBitsMemory,
|
||||
MemoryPDP10.prototype.writeBitsMemory,
|
||||
MemoryPDP10.prototype.readWordMemory,
|
||||
MemoryPDP10.prototype.writeWordMemory
|
||||
];
|
||||
|
||||
MemoryPDP10.afnChecked = [
|
||||
MemoryPDP10.prototype.readBitsChecked,
|
||||
MemoryPDP10.prototype.writeBitsChecked,
|
||||
MemoryPDP10.prototype.readWordChecked,
|
||||
MemoryPDP10.prototype.writeWordChecked
|
||||
];
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ class Int36 {
|
|||
* The lower bound is ZERO and the upper bound is Int36.MAXVAL. Whenever an Int36 value should be
|
||||
* interpreted as a signed value, values above Int36.MAXPOS (ie, values with bit 35 set) should be
|
||||
* converted to their signed counterpart by subtracting the value from Int36.BIT36 (aka MAXVAL + 1);
|
||||
* the easiest way to do that is call isNegative() to check the sign bit and then call negate() as
|
||||
* the easiest way to do that is call isNeg() to check the sign bit and then call negate() as
|
||||
* appropriate.
|
||||
*
|
||||
* NOTE: We use modern bit numbering, where bit 0 is the right-most (least-significant) bit and
|
||||
|
|
@ -233,7 +233,7 @@ class Int36 {
|
|||
var i36Rem = new Int36();
|
||||
var i36Tmp = new Int36(this.value, this.extended);
|
||||
|
||||
if (!fUnsigned && i36Tmp.isNegative()) {
|
||||
if (!fUnsigned && i36Tmp.isNeg()) {
|
||||
i36Tmp.negate();
|
||||
fNeg = true;
|
||||
}
|
||||
|
|
@ -585,7 +585,7 @@ class Int36 {
|
|||
fNegQ = !fNegQ;
|
||||
}
|
||||
|
||||
if (this.isNegative()) {
|
||||
if (this.isNeg()) {
|
||||
this.negate();
|
||||
fNegR = true; fNegQ = !fNegQ;
|
||||
}
|
||||
|
|
@ -593,52 +593,52 @@ class Int36 {
|
|||
this.extend();
|
||||
|
||||
/*
|
||||
* Initialize the four double-length 72-bit "bits" values we need for the division process.
|
||||
* Initialize the four double-length 72-bit values we need for the division process.
|
||||
*
|
||||
* The process involves shifting the divisor left 1 bit (ie, doubling it) until it equals
|
||||
* or exceeds the dividend, and then repeatedly subtracting the divisor from the dividend and
|
||||
* shifting the divisor right 1 bit until the divisor is "exhausted" (no bits left), with an
|
||||
* "early out" if the dividend gets "exhausted" first.
|
||||
*
|
||||
* Note that each element of these "bits" arrays is a 36-bit value, so it's rarely a good idea
|
||||
* Note that each element of these double arrays is a 36-bit value, so it's rarely a good idea
|
||||
* to use bit-wise operators on them, because those would operate on only the low 32 bits.
|
||||
* Stick with the "bits" worker functions I've created, and trust your JavaScript engine to
|
||||
* Stick with the double worker functions I've created, and trust your JavaScript engine to
|
||||
* inline/optimize the code.
|
||||
*
|
||||
* TODO: Profile this code to determine if individual variables (eg, bitsResLo and bitsResHi)
|
||||
* TODO: Profile this code to determine if individual variables (eg, dResLo and dResHi)
|
||||
* instead of 2-element arrays is faster and/or less impactful on garbage collection. I prefer
|
||||
* both the simplified syntax of arrays as well as their extensibility if we ever want/need
|
||||
* to go beyond 72 bits.
|
||||
*/
|
||||
var bitsRes = [0, 0];
|
||||
var bitsPow = [1, 0];
|
||||
var bitsDiv = [divisor, 0];
|
||||
var bitsRem = [this.value, this.extended];
|
||||
var dRes = [0, 0];
|
||||
var dPow = [1, 0];
|
||||
var dDiv = [divisor, 0];
|
||||
var dRem = [this.value, this.extended];
|
||||
|
||||
while (Int36.cmpBits(bitsRem, bitsDiv) > 0) {
|
||||
Int36.addBits(bitsDiv, bitsDiv);
|
||||
Int36.addBits(bitsPow, bitsPow);
|
||||
while (Int36.cmpD(dRem, dDiv) > 0) {
|
||||
Int36.addD(dDiv, dDiv);
|
||||
Int36.addD(dPow, dPow);
|
||||
}
|
||||
do {
|
||||
if (Int36.cmpBits(bitsRem, bitsDiv) >= 0) {
|
||||
Int36.subBits(bitsRem, bitsDiv);
|
||||
Int36.addBits(bitsRes, bitsPow);
|
||||
if (Int36.zeroBits(bitsRem)) break;
|
||||
if (Int36.cmpD(dRem, dDiv) >= 0) {
|
||||
Int36.subD(dRem, dDiv);
|
||||
Int36.addD(dRes, dPow);
|
||||
if (Int36.zeroD(dRem)) break;
|
||||
}
|
||||
Int36.shrBits(bitsDiv);
|
||||
Int36.shrBits(bitsPow);
|
||||
} while (!Int36.zeroBits(bitsPow));
|
||||
Int36.shrD(dDiv);
|
||||
Int36.shrD(dPow);
|
||||
} while (!Int36.zeroD(dPow));
|
||||
|
||||
/*
|
||||
* Since divisors are limited to 36-bit values, something's wrong if we have an extended remainder.
|
||||
*/
|
||||
if (DEBUG && bitsRem[1]) {
|
||||
if (DEBUG && dRem[1]) {
|
||||
console.log("divExtended() assertion failure");
|
||||
}
|
||||
|
||||
this.value = bitsRes[0];
|
||||
this.extended = bitsRes[1];
|
||||
this.remainder = bitsRem[0];
|
||||
this.value = dRes[0];
|
||||
this.extended = dRes[1];
|
||||
this.remainder = dRem[0];
|
||||
|
||||
if (fNegQ) this.negate();
|
||||
|
||||
|
|
@ -689,11 +689,11 @@ class Int36 {
|
|||
}
|
||||
|
||||
/**
|
||||
* isNegative()
|
||||
* isNeg()
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isNegative()
|
||||
isNeg()
|
||||
{
|
||||
return (this.extended > Int36.MAXPOS || this.extended == null && this.value > Int36.MAXPOS);
|
||||
}
|
||||
|
|
@ -738,83 +738,118 @@ class Int36 {
|
|||
}
|
||||
|
||||
/**
|
||||
* addBits(bitsDst, bitsSrc)
|
||||
* readBits(off, len)
|
||||
*
|
||||
* Adds bitsSrc to bitsDst.
|
||||
*
|
||||
* @param {Array.<number>} bitsDst
|
||||
* @param {Array.<number>} bitsSrc
|
||||
* @param {number} off (the bit position of the right-most bit of the result, using modern bit numbering)
|
||||
* @param {number} len
|
||||
* @return {number}
|
||||
*/
|
||||
static addBits(bitsDst, bitsSrc)
|
||||
readBits(off, len)
|
||||
{
|
||||
bitsDst[0] += bitsSrc[0];
|
||||
bitsDst[1] += bitsSrc[1];
|
||||
if (bitsDst[0] >= Int36.BIT36) {
|
||||
bitsDst[0] %= Int36.BIT36;
|
||||
bitsDst[1]++;
|
||||
var w = this.value;
|
||||
if (off + len <= 32) {
|
||||
w = (w >> off) & ((1 << len) - 1);
|
||||
} else {
|
||||
w = Math.trunc(w / Math.pow(2, off)) % Math.pow(2, len);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* writeBits(bits, off, len)
|
||||
*
|
||||
* @param {number} bits (only the right-most len of bits are used, so it doesn't need to be pre-masked)
|
||||
* @param {number} off (the bit position of the right-most bit of the result, using modern bit numbering)
|
||||
* @param {number} len
|
||||
*/
|
||||
writeBits(bits, off, len)
|
||||
{
|
||||
var w = this.value;
|
||||
var shift = Math.pow(2, off);
|
||||
bits %= Math.pow(2, len);
|
||||
var v = (w % Math.pow(2, off + len));
|
||||
w = (w - v) + (bits * shift) + (v % shift);
|
||||
this.value = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* addD(dDst, dSrc)
|
||||
*
|
||||
* Adds dSrc to dDst.
|
||||
*
|
||||
* @param {Array.<number>} dDst
|
||||
* @param {Array.<number>} dSrc
|
||||
*/
|
||||
static addD(dDst, dSrc)
|
||||
{
|
||||
dDst[0] += dSrc[0];
|
||||
dDst[1] += dSrc[1];
|
||||
if (dDst[0] >= Int36.BIT36) {
|
||||
dDst[0] %= Int36.BIT36;
|
||||
dDst[1]++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cmpBits(bitsDst, bitsSrc)
|
||||
* cmpD(dDst, dSrc)
|
||||
*
|
||||
* Compares bitsDst to bitsSrc, by computing bitsDst - bitsSrc.
|
||||
* Compares dDst to dSrc, by computing dDst - dSrc.
|
||||
*
|
||||
* @param {Array.<number>} bitsDst
|
||||
* @param {Array.<number>} bitsSrc
|
||||
* @return {number} > 0 if bitsDst > bitsSrc, == 0 if bitsDst == bitsSrc, < 0 if bitsDst < bitsSrc
|
||||
* @param {Array.<number>} dDst
|
||||
* @param {Array.<number>} dSrc
|
||||
* @return {number} > 0 if dDst > dSrc, == 0 if dDst == dSrc, < 0 if dDst < dSrc
|
||||
*/
|
||||
static cmpBits(bitsDst, bitsSrc)
|
||||
static cmpD(dDst, dSrc)
|
||||
{
|
||||
var result = bitsDst[1] - bitsSrc[1];
|
||||
if (!result) result = bitsDst[0] - bitsSrc[0];
|
||||
var result = dDst[1] - dSrc[1];
|
||||
if (!result) result = dDst[0] - dSrc[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* shrBits(bitsDst)
|
||||
* shrD(dDst)
|
||||
*
|
||||
* Shifts bitsDst right one bit.
|
||||
* Shifts dDst right one bit.
|
||||
*
|
||||
* @param {Array.<number>} bitsDst
|
||||
* @param {Array.<number>} dDst
|
||||
*/
|
||||
static shrBits(bitsDst)
|
||||
static shrD(dDst)
|
||||
{
|
||||
if (bitsDst[1] % 2) {
|
||||
bitsDst[0] += Int36.BIT36;
|
||||
if (dDst[1] % 2) {
|
||||
dDst[0] += Int36.BIT36;
|
||||
}
|
||||
bitsDst[0] = Math.trunc(bitsDst[0] / 2);
|
||||
bitsDst[1] = Math.trunc(bitsDst[1] / 2);
|
||||
dDst[0] = Math.trunc(dDst[0] / 2);
|
||||
dDst[1] = Math.trunc(dDst[1] / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* subBits(bitsDst, bitsSrc)
|
||||
* subD(dDst, dSrc)
|
||||
*
|
||||
* Subtracts bitsSrc from bitsDst.
|
||||
* Subtracts dSrc from dDst.
|
||||
*
|
||||
* @param {Array.<number>} bitsDst
|
||||
* @param {Array.<number>} bitsSrc
|
||||
* @param {Array.<number>} dDst
|
||||
* @param {Array.<number>} dSrc
|
||||
*/
|
||||
static subBits(bitsDst, bitsSrc)
|
||||
static subD(dDst, dSrc)
|
||||
{
|
||||
bitsDst[0] -= bitsSrc[0];
|
||||
bitsDst[1] -= bitsSrc[1];
|
||||
if (bitsDst[0] < 0) {
|
||||
bitsDst[0] += Int36.BIT36;
|
||||
bitsDst[1]--;
|
||||
dDst[0] -= dSrc[0];
|
||||
dDst[1] -= dSrc[1];
|
||||
if (dDst[0] < 0) {
|
||||
dDst[0] += Int36.BIT36;
|
||||
dDst[1]--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* zeroBits(bits)
|
||||
* zeroD(d)
|
||||
*
|
||||
* True if bits are all zero, false otherwise.
|
||||
*
|
||||
* @param {Array.<number>} bits
|
||||
* @param {Array.<number>} d
|
||||
*/
|
||||
static zeroBits(bits)
|
||||
static zeroD(d)
|
||||
{
|
||||
return !bits[0] && !bits[1];
|
||||
return !d[0] && !d[1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue