Fixed new modRM decoders

This commit is contained in:
Jeff Parsons 2016-03-08 16:39:10 -08:00
commit 7953383fa9
37 changed files with 7973 additions and 1603 deletions

View file

@ -39,14 +39,14 @@ if (NODE) {
}
/**
* fnAdd64(dst, src)
* helpAdd64(dst, src)
*
* Adds src to dst.
*
* @param {Array} dst is a 64-bit value
* @param {Array} src is a 64-bit value
*/
X86.fnAdd64 = function(dst, src)
X86.helpAdd64 = function(dst, src)
{
dst[0] += src[0];
dst[1] += src[1];
@ -57,7 +57,7 @@ X86.fnAdd64 = function(dst, src)
};
/**
* fnCmp64(dst, src)
* helpCmp64(dst, src)
*
* Compares dst to src, by computing dst - src.
*
@ -65,7 +65,7 @@ X86.fnAdd64 = function(dst, src)
* @param {Array} src is a 64-bit value
* @return {number} > 0 if dst > src, == 0 if dst == src, < 0 if dst < src
*/
X86.fnCmp64 = function(dst, src)
X86.helpCmp64 = function(dst, src)
{
var result = dst[1] - src[1];
if (!result) result = dst[0] - src[0];
@ -73,24 +73,24 @@ X86.fnCmp64 = function(dst, src)
};
/**
* fnSet64(lo, hi)
* helpSet64(lo, hi)
*
* @param {number} lo
* @param {number} hi
*/
X86.fnSet64 = function(lo, hi)
X86.helpSet64 = function(lo, hi)
{
return [lo >>> 0, hi >>> 0];
};
/**
* fnShr64(dst)
* helpShr64(dst)
*
* Shifts dst right one bit.
*
* @param {Array} dst is a 64-bit value
*/
X86.fnShr64 = function(dst)
X86.helpShr64 = function(dst)
{
dst[0] >>>= 1;
if (dst[1] & 0x1) {
@ -100,14 +100,14 @@ X86.fnShr64 = function(dst)
};
/**
* fnSub64(dst, src)
* helpSub64(dst, src)
*
* Subtracts src from dst.
*
* @param {Array} dst is a 64-bit value
* @param {Array} src is a 64-bit value
*/
X86.fnSub64 = function(dst, src)
X86.helpSub64 = function(dst, src)
{
dst[0] -= src[0];
dst[1] -= src[1];
@ -118,13 +118,13 @@ X86.fnSub64 = function(dst, src)
};
/**
* fnDECr(w)
* helpDECreg(w)
*
* @this {X86CPU}
* @param {number} w
* @return {number}
*/
X86.fnDECr = function(w)
X86.helpDECreg = function(w)
{
var result = (w - 1)|0;
this.setArithResult(w, 1, result, this.typeData | X86.RESULT.NOTCF, true);
@ -133,7 +133,7 @@ X86.fnDECr = function(w)
};
/**
* fnDIV32(dstLo, dstHi, src)
* helpDIV32(dstLo, dstHi, src)
*
* This sets regMDLo to dstHi:dstLo / src, and regMDHi to dstHi:dstLo % src; all inputs are treated as unsigned.
*
@ -145,7 +145,7 @@ X86.fnDECr = function(w)
* @param {number} src (32-bit divisor)
* @return {boolean} true if successful, false if overflow (ie, the divisor was either zero or too small)
*/
X86.fnDIV32 = function(dstLo, dstHi, src)
X86.helpDIV32 = function(dstLo, dstHi, src)
{
src >>>= 0;
if (!src || src <= (dstHi >>> 0)) {
@ -154,19 +154,19 @@ X86.fnDIV32 = function(dstLo, dstHi, src)
var result = 0, bit = 1;
var div = X86.fnSet64(src, 0);
var rem = X86.fnSet64(dstLo, dstHi);
var div = X86.helpSet64(src, 0);
var rem = X86.helpSet64(dstLo, dstHi);
while (X86.fnCmp64(rem, div) > 0) {
X86.fnAdd64(div, div);
while (X86.helpCmp64(rem, div) > 0) {
X86.helpAdd64(div, div);
bit += bit;
}
do {
if (X86.fnCmp64(rem, div) >= 0) {
X86.fnSub64(rem, div);
if (X86.helpCmp64(rem, div) >= 0) {
X86.helpSub64(rem, div);
result += bit;
}
X86.fnShr64(div);
X86.helpShr64(div);
bit /= 2;
} while (bit >= 1);
@ -178,7 +178,7 @@ X86.fnDIV32 = function(dstLo, dstHi, src)
};
/**
* fnIDIV32(dstLo, dstHi, src)
* helpIDIV32(dstLo, dstHi, src)
*
* This sets regMDLo to dstHi:dstLo / src, and regMDHi to dstHi:dstLo % src; all inputs are treated as signed.
*
@ -190,7 +190,7 @@ X86.fnDIV32 = function(dstLo, dstHi, src)
* @param {number} src (32-bit divisor)
* @return {boolean} true if successful, false if overflow (ie, the divisor was either zero or too small)
*/
X86.fnIDIV32 = function(dstLo, dstHi, src)
X86.helpIDIV32 = function(dstLo, dstHi, src)
{
var bNegLo = 0, bNegHi = 0;
/*
@ -212,7 +212,7 @@ X86.fnIDIV32 = function(dstLo, dstHi, src)
bNegHi = 1;
bNegLo = 1 - bNegLo;
}
if (!X86.fnDIV32.call(this, dstLo, dstHi, src) || this.regMDLo > 0x7fffffff+bNegLo || this.regMDHi > 0x7fffffff+bNegHi) {
if (!X86.helpDIV32.call(this, dstLo, dstHi, src) || this.regMDLo > 0x7fffffff+bNegLo || this.regMDHi > 0x7fffffff+bNegHi) {
return false;
}
if (bNegLo) this.regMDLo = -this.regMDLo;
@ -221,13 +221,13 @@ X86.fnIDIV32 = function(dstLo, dstHi, src)
};
/**
* fnINCr(w)
* helpINCreg(w)
*
* @this {X86CPU}
* @param {number} w
* @return {number}
*/
X86.fnINCr = function(w)
X86.helpINCreg = function(w)
{
var result = (w + 1)|0;
this.setArithResult(w, 1, result, this.typeData | X86.RESULT.NOTCF);
@ -236,7 +236,7 @@ X86.fnINCr = function(w)
};
/**
* fnLCR0(l)
* helpLoadCR0(l)
*
* This is called by an 80386 control instruction (ie, MOV CR0,reg).
*
@ -245,7 +245,7 @@ X86.fnINCr = function(w)
* @this {X86CPU}
* @param {number} l
*/
X86.fnLCR0 = function(l)
X86.helpLoadCR0 = function(l)
{
this.regCR0 = l;
this.setProtMode();
@ -261,14 +261,14 @@ X86.fnLCR0 = function(l)
};
/**
* fnLCR3(l)
* helpLoadCR3(l)
*
* This is called by an 80386 control instruction (ie, MOV CR3,reg) or an 80386 task switch.
*
* @this {X86CPU}
* @param {number} l
*/
X86.fnLCR3 = function(l)
X86.helpLoadCR3 = function(l)
{
this.regCR3 = l;
/*
@ -280,12 +280,12 @@ X86.fnLCR3 = function(l)
};
/**
* fnSETcc()
* helpSETcc()
*
* @this {X86CPU}
* @param {function(number,number)} fnSet
*/
X86.fnSETcc = function(fnSet)
X86.helpSETcc = function(fnSet)
{
this.opFlags |= X86.OPFLAG.NOREAD;
this.decodeModMemByte.call(this, fnSet);
@ -293,7 +293,7 @@ X86.fnSETcc = function(fnSet)
};
/**
* fnSHLDw(dst, src, count)
* helpSHLDw(dst, src, count)
*
* @this {X86CPU}
* @param {number} dst
@ -301,7 +301,7 @@ X86.fnSETcc = function(fnSet)
* @param {number} count (0-31)
* @return {number}
*/
X86.fnSHLDw = function(dst, src, count)
X86.helpSHLDw = function(dst, src, count)
{
if (count) {
if (count > 16) {
@ -316,7 +316,7 @@ X86.fnSHLDw = function(dst, src, count)
};
/**
* fnSHLDd(dst, src, count)
* helpSHLDd(dst, src, count)
*
* @this {X86CPU}
* @param {number} dst
@ -324,7 +324,7 @@ X86.fnSHLDw = function(dst, src, count)
* @param {number} count
* @return {number}
*/
X86.fnSHLDd = function(dst, src, count)
X86.helpSHLDd = function(dst, src, count)
{
if (count) {
var carry = dst << (count - 1);
@ -335,7 +335,7 @@ X86.fnSHLDd = function(dst, src, count)
};
/**
* fnSHRDw(dst, src, count)
* helpSHRDw(dst, src, count)
*
* @this {X86CPU}
* @param {number} dst
@ -343,7 +343,7 @@ X86.fnSHLDd = function(dst, src, count)
* @param {number} count (0-31)
* @return {number}
*/
X86.fnSHRDw = function(dst, src, count)
X86.helpSHRDw = function(dst, src, count)
{
if (count) {
if (count > 16) {
@ -358,7 +358,7 @@ X86.fnSHRDw = function(dst, src, count)
};
/**
* fnSHRDd(dst, src, count)
* helpSHRDd(dst, src, count)
*
* @this {X86CPU}
* @param {number} dst
@ -366,7 +366,7 @@ X86.fnSHRDw = function(dst, src, count)
* @param {number} count
* @return {number}
*/
X86.fnSHRDd = function(dst, src, count)
X86.helpSHRDd = function(dst, src, count)
{
if (count) {
var carry = dst >>> (count - 1);
@ -377,24 +377,24 @@ X86.fnSHRDd = function(dst, src, count)
};
/**
* fnSRC1()
* helpSRC1()
*
* @this {X86CPU}
* @return {number}
*/
X86.fnSRC1 = function()
X86.helpSRC1 = function()
{
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 2 : this.cycleCounts.nOpCyclesShift1M);
return 1;
};
/**
* fnSRCCL()
* helpSRCCL()
*
* @this {X86CPU}
* @return {number}
*/
X86.fnSRCCL = function()
X86.helpSRCCL = function()
{
var count = this.regECX & 0xff;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesShiftCR : this.cycleCounts.nOpCyclesShiftCM) + (count << this.cycleCounts.nOpCyclesShiftCS);
@ -402,12 +402,12 @@ X86.fnSRCCL = function()
};
/**
* fnSRCByte()
* helpSRCByte()
*
* @this {X86CPU}
* @return {number}
*/
X86.fnSRCByte = function()
X86.helpSRCByte = function()
{
var count = this.getIPByte();
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesShiftCR : this.cycleCounts.nOpCyclesShiftCM) + (count << this.cycleCounts.nOpCyclesShiftCS);
@ -415,18 +415,18 @@ X86.fnSRCByte = function()
};
/**
* fnSRCNone()
* helpSRCNone()
*
* @this {X86CPU}
* @return {number|null}
*/
X86.fnSRCNone = function()
X86.helpSRCNone = function()
{
return null;
};
/**
* fnSRCxx()
* helpSRCxx()
*
* This is used by opPOPmw(), because the actual pop must occur BEFORE the effective address (EA)
* calculation. So opPOPmw() does the pop, saves the popped value in regXX, and this passes src function
@ -435,13 +435,13 @@ X86.fnSRCNone = function()
* @this {X86CPU}
* @return {number} regXX
*/
X86.fnSRCxx = function()
X86.helpSRCxx = function()
{
return this.regXX;
};
/**
* fnCALLF(off, sel)
* helpCALLF(off, sel)
*
* For protected-mode, this function must attempt to load the new code segment first, because if the new segment
* requires a change in privilege level, the return address must be pushed on the NEW stack, not the current stack.
@ -459,12 +459,12 @@ X86.fnSRCxx = function()
* @param {number} off
* @param {number} sel
*/
X86.fnCALLF = function(off, sel)
X86.helpCALLF = function(off, sel)
{
/*
* Since we always push the return address AFTER calling setCSIP(), and since either push could trigger a
* fault (eg, segment fault, page fault, etc), we must not only snapshot regLSP into opLSP, but also the
* current CS into opCS, so that fnFault() can always make CALLF restartable. Ditto for opSS and the SS register.
* current CS into opCS, so that helpFault() can always make CALLF restartable. Ditto for opSS and the SS register.
*/
this.opCS = this.getCS();
this.opSS = this.getSS();
@ -485,7 +485,7 @@ X86.fnCALLF = function(off, sel)
};
/**
* fnINT(nIDT, nError, nCycles)
* helpINT(nIDT, nError, nCycles)
*
* NOTE: We no longer use setCSIP(), because it always loads the new CS using segCS.load(), which only knows
* how to load GDT and LDT descriptors, whereas interrupts must use setCS.loadIDT(), which deals exclusively
@ -496,7 +496,7 @@ X86.fnCALLF = function(off, sel)
* @param {number|null} [nError]
* @param {number} [nCycles] (in addition to the default of nOpCyclesInt)
*/
X86.fnINT = function(nIDT, nError, nCycles)
X86.helpINT = function(nIDT, nError, nCycles)
{
/*
* TODO: We assess the cycle cost up front, because otherwise, if loadIDT() fails, no cost may be assessed.
@ -509,10 +509,10 @@ X86.fnINT = function(nIDT, nError, nCycles)
if (addr !== X86.ADDR_INVALID) {
/*
* TODO: Determine if we should use pushData() instead of pushWord() for oldCS and nError, to deal with
* the same 32-bit 80386 compatibility issue that fnCALLF(), opPUSHCS(), et al must deal with; namely, that
* the same 32-bit 80386 compatibility issue that helpCALLF(), opPUSHCS(), et al must deal with; namely, that
* 32-bit segment register writes (and, reportedly, 32-bit error codes) don't modify the upper 16 bits.
*
* Also, note that fnCALLF() is using the OPERAND size in effect *before* CS is loaded, whereas here we're
* Also, note that helpCALLF() is using the OPERAND size in effect *before* CS is loaded, whereas here we're
* using the OPERAND size in effect *after* CS is loaded. Is that correct? And does an explicit OPERAND
* size override on an "INT" instruction have any effect on that behavior? Is that even allowed?
*/
@ -526,11 +526,11 @@ X86.fnINT = function(nIDT, nError, nCycles)
};
/**
* fnIRET()
* helpIRET()
*
* @this {X86CPU}
*/
X86.fnIRET = function()
X86.helpIRET = function()
{
/*
* Originally, we would snapshot regLSP into opLSP because newCS could trigger a segment fault,
@ -615,7 +615,7 @@ X86.fnIRET = function()
};
/**
* fnRETF(n)
* helpRETF(n)
*
* For protected-mode, this function must pop any arguments off the current stack AND whatever stack
* we may have switched to; setCSIP() returns true if a stack switch occurred, false if not, and null
@ -624,7 +624,7 @@ X86.fnIRET = function()
* @this {X86CPU}
* @param {number} n
*/
X86.fnRETF = function(n)
X86.helpRETF = function(n)
{
/*
* Originally, we would snapshot regLSP into opLSP because newCS could trigger a segment fault,
@ -669,11 +669,11 @@ X86.fnRETF = function(n)
};
/**
* fnDivOverflow()
* helpDIVOverflow()
*
* @this {X86CPU}
*/
X86.fnDivOverflow = function()
X86.helpDIVOverflow = function()
{
/*
* Divide error exceptions are traps on the 8086 and faults on later processors. I question the value of that
@ -685,14 +685,14 @@ X86.fnDivOverflow = function()
* TODO: Determine the proper cycle cost.
*/
if (this.model == X86.MODEL_8086) {
X86.fnTrap.call(this, X86.EXCEPTION.DE_EXC, 2);
X86.helpTrap.call(this, X86.EXCEPTION.DE_EXC, 2);
} else {
X86.fnFault.call(this, X86.EXCEPTION.DE_EXC, null, 2);
X86.helpFault.call(this, X86.EXCEPTION.DE_EXC, null, 2);
}
};
/**
* fnInterrupt(nIDT, nCycles)
* helpInterrupt(nIDT, nCycles)
*
* Helper to dispatch external interrupts. nCycles defaults to 11 for the 8086/8088
* if no alternate value is specified.
@ -701,15 +701,15 @@ X86.fnDivOverflow = function()
* @param {number} nIDT
* @param {number} [nCycles] (number of cycles in addition to the default of nOpCyclesInt)
*/
X86.fnInterrupt = function(nIDT, nCycles)
X86.helpInterrupt = function(nIDT, nCycles)
{
this.nFault = nIDT;
if (nCycles === undefined) nCycles = 11;
X86.fnINT.call(this, nIDT, null, nCycles);
X86.helpINT.call(this, nIDT, null, nCycles);
};
/**
* fnTrap(nIDT, nCycles)
* helpTrap(nIDT, nCycles)
*
* Helper to dispatch traps (ie, exceptions that occur AFTER the instruction, with NO error code)
*
@ -717,24 +717,24 @@ X86.fnInterrupt = function(nIDT, nCycles)
* @param {number} nIDT
* @param {number} [nCycles] (number of cycles in addition to the default of nOpCyclesInt)
*/
X86.fnTrap = function(nIDT, nCycles)
X86.helpTrap = function(nIDT, nCycles)
{
this.nFault = -1;
X86.fnINT.call(this, nIDT, null, nCycles);
X86.helpINT.call(this, nIDT, null, nCycles);
};
/**
* fnFault(nFault, nError, nCycles, fHalt)
* helpFault(nFault, nError, nCycles, fHalt)
*
* Helper to dispatch faults (ie, exceptions that occur DURING an instruction and MAY generate an error code)
*
* @this {X86CPU}
* @param {number} nFault
* @param {number|null} [nError] (if omitted, no error code will be pushed)
* @param {number} [nCycles] cycle count to pass through to fnINT(), if any
* @param {number} [nCycles] cycle count to pass through to helpINT(), if any
* @param {boolean} [fHalt] (true to halt the CPU, false to not, undefined if "it depends")
*/
X86.fnFault = function(nFault, nError, nCycles, fHalt)
X86.helpFault = function(nFault, nError, nCycles, fHalt)
{
var fDispatch = false;
@ -793,9 +793,9 @@ X86.fnFault = function(nFault, nError, nCycles, fHalt)
}
}
if (X86.fnCheckFault.call(this, nFault, nError, fHalt)) {
if (X86.helpCheckFault.call(this, nFault, nError, fHalt)) {
/*
* If this is a fault that would normally be dispatched BUT fnCheckFault() wants us to halt,
* If this is a fault that would normally be dispatched BUT helpCheckFault() wants us to halt,
* then we throw a bogus fault number (-1), simply to interrupt the current instruction in exactly
* the same way that a dispatched fault would interrupt it.
*/
@ -805,7 +805,7 @@ X86.fnFault = function(nFault, nError, nCycles, fHalt)
if (fDispatch) {
this.nFault = nFault;
X86.fnINT.call(this, nFault, nError, nCycles);
X86.helpINT.call(this, nFault, nError, nCycles);
/*
* REP'eated instructions that rewind regLIP to opLIP used to screw up this dispatch,
@ -850,7 +850,7 @@ X86.fnFault = function(nFault, nError, nCycles, fHalt)
};
/**
* fnPageFault(addr, fPresent, fWrite)
* helpPageFault(addr, fPresent, fWrite)
*
* Helper to dispatch page faults.
*
@ -859,18 +859,18 @@ X86.fnFault = function(nFault, nError, nCycles, fHalt)
* @param {boolean} fPresent
* @param {boolean} fWrite
*/
X86.fnPageFault = function(addr, fPresent, fWrite)
X86.helpPageFault = function(addr, fPresent, fWrite)
{
this.regCR2 = addr;
var nError = 0;
if (fPresent) nError |= X86.PTE.PRESENT;
if (fWrite) nError |= X86.PTE.READWRITE;
if (this.nCPL == 3) nError |= X86.PTE.USER;
X86.fnFault.call(this, X86.EXCEPTION.PF_FAULT, nError);
X86.helpFault.call(this, X86.EXCEPTION.PF_FAULT, nError);
};
/**
* fnCheckFault(nFault, nError, fHalt)
* helpCheckFault(nFault, nError, fHalt)
*
* Aside from giving the Debugger an opportunity to report every fault, this also gives us the ability to
* halt exception processing in tracks: return true to prevent the fault handler from being dispatched.
@ -886,7 +886,7 @@ X86.fnPageFault = function(addr, fPresent, fWrite)
* @param {boolean} [fHalt] (true to halt the CPU, false to not, undefined if "it depends")
* @return {boolean|undefined} true to block the fault (often desirable when fHalt is true), otherwise dispatch it
*/
X86.fnCheckFault = function(nFault, nError, fHalt)
X86.helpCheckFault = function(nFault, nError, fHalt)
{
var bitsMessage = Messages.FAULT;