Slimmed-down ModRegRM decoding (at some potential performance cost)

This commit is contained in:
Jeff Parsons 2016-03-07 15:34:28 -08:00
commit 49ca936a18
179 changed files with 6200 additions and 57074 deletions

View file

@ -44,31 +44,6 @@ if (NODE) {
var X86Seg = require("./x86seg");
}
if (!I386) {
/*
* These are the original ModRM decoders, which were simpler and faster because they could treat all
* word instructions as 16-bit, assume bits 16-31 of all registers were always zero, and use masking
* constants instead of variables. If I386 is enabled, these decoders are not used, and the Closure
* Compiler will eliminate them from the compiled JavaScript code.
*/
if (NODE) {
var X86ModB = require("./x86modb");
var X86ModW = require("./x86modw");
}
} else {
/*
* These are the more general-purpose ModRM decoders, required for I386 support. The current addressing
* mode (16-bit or 32-bit) dynamically selects the appropriate set of decoders.
*/
if (NODE) {
var X86ModB16 = require("./x86modb16");
var X86ModW16 = require("./x86modw16");
var X86ModB32 = require("./x86modb32");
var X86ModW32 = require("./x86modw32");
var X86ModSIB = require("./x86modsib");
}
}
/**
* X86CPU(parmsCPU)
*
@ -1088,7 +1063,7 @@ X86CPU.prototype.resetRegs = function()
*/
this.fMDSet = false; // regMDHi and/or regMDLo are invalid unless fMDSet is true
this.regMDLo = this.regMDHi = 0;
this.regXX = 0; // internal register for segment register and control register moves
this.regXX = 0; // for internal use only (eg, assists with ModRM decoder helper functions)
/*
* This internal "register" is set in selected opcode handlers to record the original opcode; ordinarily,
@ -1341,35 +1316,76 @@ X86CPU.prototype.setAddrSize = function(size)
* Select the appropriate ModRM dispatch tables, based on the current ADDRESS size (addrSize), which
* is based foremost on segCS.sizeAddr, but can also be overridden by an ADDRESS size instruction prefix.
*
* There used to be six primary ModRM dispatch table pointers:
*
* aOpModRegByte
* aOpModMemByte
* aOpModGrpByte
* aOpModRegWord
* aOpModMemWord
* aOpModGrpWord
*
* However, when support for the 80386 was added, the number of dispatch tables doubled, and since each entry
* in the table was a discrete function, decoding was fast, but it also produced a lot of code.
*
* So we have now replaced the above table pointers with function pointers:
*
* decodeModRegByte (set to one of: decodeModRegByte16, decodeModRegByte32)
* decodeModMemByte (set to one of: decodeModMemByte16, decodeModMemByte32)
* decodeModGrpByte (set to one of: decodeModGrpByte16, decodeModGrpByte32)
* decodeModRegWord (set to one of: decodeModRegShort16, decodeModRegLong16, decodeModRegShort32, decodeModRegLong32)
* decodeModMemWord (set to one of: decodeModMemShort16, decodeModMemLong16, decodeModMemShort32, decodeModMemLong32)
* decodeModGrpWord (set to one of: decodeModGrpShort16, decodeModGrpLong16, decodeModGrpShort32, decodeModGrpLong32)
*
* So opcode handlers that used to do this:
*
* this.aOpModMemByte[b].call(this, X86.fnADDb);
*
* now do this:
*
* this.decodeModMemByte.call(this, X86.fnADDb);
*
* @this {X86CPU}
*/
X86CPU.prototype.updateAddrSize = function()
{
if (!I386) {
this.getAddr = (PREFETCH? this.getShortPrefetch : this.getShort);
this.aOpModRegByte = X86ModB.aOpModReg;
this.aOpModMemByte = X86ModB.aOpModMem;
this.aOpModGrpByte = X86ModB.aOpModGrp;
this.aOpModRegWord = X86ModW.aOpModReg;
this.aOpModMemWord = X86ModW.aOpModMem;
this.aOpModGrpWord = X86ModW.aOpModGrp;
this.decodeModRegByte = X86.decodeModRegByte16;
this.decodeModMemByte = X86.decodeModMemByte16;
this.decodeModGrpByte = X86.decodeModGrpByte16;
this.decodeModRegWord = X86.decodeModRegShort16;
this.decodeModMemWord = X86.decodeModMemShort16;
this.decodeModGrpWord = X86.decodeModGrpShort16;
} else {
if (this.sizeAddr == 2) {
this.getAddr = (PREFETCH? this.getShortPrefetch : this.getShort);
this.aOpModRegByte = X86ModB16.aOpModReg;
this.aOpModMemByte = X86ModB16.aOpModMem;
this.aOpModGrpByte = X86ModB16.aOpModGrp;
this.aOpModRegWord = X86ModW16.aOpModReg;
this.aOpModMemWord = X86ModW16.aOpModMem;
this.aOpModGrpWord = X86ModW16.aOpModGrp;
this.decodeModRegByte = X86.decodeModRegByte16;
this.decodeModMemByte = X86.decodeModMemByte16;
this.decodeModGrpByte = X86.decodeModGrpByte16;
if (this.sizeData == 2) {
this.decodeModRegWord = X86.decodeModRegShort16;
this.decodeModMemWord = X86.decodeModMemShort16;
this.decodeModGrpWord = X86.decodeModGrpShort16;
} else {
this.decodeModRegWord = X86.decodeModRegLong16;
this.decodeModMemWord = X86.decodeModMemLong16;
this.decodeModGrpWord = X86.decodeModGrpLong16;
}
} else {
this.getAddr = (PREFETCH? this.getLongPrefetch : this.getLong);
this.aOpModRegByte = X86ModB32.aOpModReg;
this.aOpModMemByte = X86ModB32.aOpModMem;
this.aOpModGrpByte = X86ModB32.aOpModGrp;
this.aOpModRegWord = X86ModW32.aOpModReg;
this.aOpModMemWord = X86ModW32.aOpModMem;
this.aOpModGrpWord = X86ModW32.aOpModGrp;
this.decodeModRegByte = X86.decodeModRegByte32;
this.decodeModMemByte = X86.decodeModMemByte32;
this.decodeModGrpByte = X86.decodeModGrpByte32;
if (this.sizeData == 2) {
this.decodeModRegWord = X86.decodeModRegShort32;
this.decodeModMemWord = X86.decodeModMemShort32;
this.decodeModGrpWord = X86.decodeModGrpShort32;
} else {
this.decodeModRegWord = X86.decodeModRegLong32;
this.decodeModMemWord = X86.decodeModMemLong32;
this.decodeModGrpWord = X86.decodeModGrpLong32;
}
}
}
};
@ -1404,10 +1420,28 @@ X86CPU.prototype.updateDataSize = function()
this.typeData = X86.RESULT.WORD;
this.getWord = this.getShort;
this.setWord = this.setShort;
if (this.sizeAddr == 2) {
this.decodeModRegWord = X86.decodeModRegShort16;
this.decodeModMemWord = X86.decodeModMemShort16;
this.decodeModGrpWord = X86.decodeModGrpShort16;
} else {
this.decodeModRegWord = X86.decodeModRegShort32;
this.decodeModMemWord = X86.decodeModMemShort32;
this.decodeModGrpWord = X86.decodeModGrpShort32;
}
} else {
this.typeData = X86.RESULT.DWORD;
this.getWord = this.getLong;
this.setWord = this.setLong;
if (this.sizeAddr == 2) {
this.decodeModRegWord = X86.decodeModRegLong16;
this.decodeModMemWord = X86.decodeModMemLong16;
this.decodeModGrpWord = X86.decodeModGrpLong16;
} else {
this.decodeModRegWord = X86.decodeModRegLong32;
this.decodeModMemWord = X86.decodeModMemLong32;
this.decodeModGrpWord = X86.decodeModGrpLong32;
}
}
};
@ -3296,6 +3330,88 @@ X86CPU.prototype.getEAByteStack = function(off)
return this.getEAByte(this.segStack, off & (I386? this.maskAddr : 0xffff));
};
/**
* getEAShortData(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.getEAShortData = function(off)
{
this.segEA = this.segData;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = this.segEA.checkRead(this.offEA, 2);
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getShort(this.regEA);
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
}
return w;
};
/**
* getEAShortStack(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.getEAShortStack = function(off)
{
this.segEA = this.segStack;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = this.segEA.checkRead(this.offEA, 2);
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getShort(this.regEA);
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
}
return w;
};
/**
* getEALongData(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.getEALongData = function(off)
{
this.segEA = this.segData;
this.regEA = this.segEA.checkRead(this.offEA = off, 4);
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getLong(this.regEA);
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
}
return w;
};
/**
* getEALongStack(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.getEALongStack = function(off)
{
this.segEA = this.segStack;
this.regEA = this.segEA.checkRead(this.offEA = off, 4);
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getLong(this.regEA);
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
}
return w;
};
/**
* getEAWord(seg, off)
*
@ -3341,93 +3457,6 @@ X86CPU.prototype.getEAWordStack = function(off)
return this.getEAWord(this.segStack, off & (I386? this.maskAddr : 0xffff));
};
/**
* modEAByte(seg, off)
*
* @this {X86CPU}
* @param {X86Seg} seg register (eg, segDS)
* @param {number} off is a segment-relative offset
* @return {number} byte (8-bit) value at that address
*/
X86CPU.prototype.modEAByte = function(seg, off)
{
this.segEA = seg;
this.regEAWrite = this.regEA = seg.checkRead(this.offEA = off, 1);
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var b = this.getByte(this.regEA);
if (BACKTRACK) this.backTrack.btiEALo = this.backTrack.btiMem0;
return b;
};
/**
* modEAByteData(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} byte (8-bit) value at that address
*/
X86CPU.prototype.modEAByteData = function(off)
{
return this.modEAByte(this.segData, off & (I386? this.maskAddr : 0xffff));
};
/**
* modEAByteStack(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} byte (8-bit) value at that address
*/
X86CPU.prototype.modEAByteStack = function(off)
{
return this.modEAByte(this.segStack, off & (I386? this.maskAddr : 0xffff));
};
/**
* modEAWord(seg, off)
*
* @this {X86CPU}
* @param {X86Seg} seg register (eg, segDS)
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.modEAWord = function(seg, off)
{
this.segEA = seg;
this.regEAWrite = this.regEA = seg.checkRead(this.offEA = off, (I386? this.sizeData : 2));
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getWord(this.regEA);
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
}
return w;
};
/**
* modEAWordData(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.modEAWordData = function(off)
{
return this.modEAWord(this.segData, off & (I386? this.maskAddr : 0xffff));
};
/**
* modEAWordStack(off)
*
* @this {X86CPU}
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.modEAWordStack = function(off)
{
return this.modEAWord(this.segStack, off & (I386? this.maskAddr : 0xffff));
};
/**
* setEAByte(b)
*
@ -3441,11 +3470,43 @@ X86CPU.prototype.setEAByte = function(b)
this.setByte(this.segEA.checkWrite(this.offEA, 1), b);
};
/**
* setEAShort(w)
*
* @this {X86CPU}
* @param {number} w is the short (16-bit) value to write
*/
X86CPU.prototype.setEAShort = function(w)
{
if (this.opFlags & X86.OPFLAG.NOWRITE) return;
if (BACKTRACK) {
this.backTrack.btiMem0 = this.backTrack.btiEALo;
this.backTrack.btiMem1 = this.backTrack.btiEAHi;
}
this.setShort(this.segEA.checkWrite(this.offEA, 2), w);
};
/**
* setEALong(l)
*
* @this {X86CPU}
* @param {number} l is the long (32-bit) value to write
*/
X86CPU.prototype.setEALong = function(l)
{
if (this.opFlags & X86.OPFLAG.NOWRITE) return;
if (BACKTRACK) {
this.backTrack.btiMem0 = this.backTrack.btiEALo;
this.backTrack.btiMem1 = this.backTrack.btiEAHi;
}
this.setLong(this.segEA.checkWrite(this.offEA, 4), l);
};
/**
* setEAWord(w)
*
* @this {X86CPU}
* @param {number} w is the word (16-bit) value to write
* @param {number} w is the word (16-bit or 32-bit) value to write
*/
X86CPU.prototype.setEAWord = function(w)
{
@ -3743,18 +3804,14 @@ X86CPU.prototype.getIPDisp = function()
};
/**
* getSIBAddr(mod)
* peekIPByte()
*
* @this {X86CPU}
* @param {number} mod
* @return {number}
* @return {number} byte at the current IP
*/
X86CPU.prototype.getSIBAddr = function(mod)
X86CPU.prototype.peekIPByte = function()
{
var b = PREFETCH? this.getBytePrefetch() : this.getByte(this.regLIP);
if (BACKTRACK) this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMem0);
this.advanceIP(1);
return X86ModSIB.aOpModSIB[b].call(this, mod);
return (PREFETCH? this.getBytePrefetch() : this.getByte(this.regLIP));
};
/**

View file

@ -572,6 +572,9 @@ X86.fnCMPb = function(dst, src)
{
var b = (dst - src)|0;
this.setArithResult(dst, src, b, X86.RESULT.BYTE | X86.RESULT.ALL, true);
/*
* TODO: Verify that it makes sense for any fnCMPb() callers to be setting regEAWrite...
*/
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesArithRR : this.cycleCounts.nOpCyclesCompareRM) : this.cycleCounts.nOpCyclesArithRM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
@ -589,6 +592,9 @@ X86.fnCMPw = function(dst, src)
{
var w = (dst - src)|0;
this.setArithResult(dst, src, w, this.typeData | X86.RESULT.ALL, true);
/*
* TODO: Verify that it makes sense for any fnCMPw() callers to be setting regEAWrite...
*/
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesArithRR : this.cycleCounts.nOpCyclesCompareRM) : this.cycleCounts.nOpCyclesArithRM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
@ -1517,6 +1523,48 @@ X86.fnMOVX = function(dst, src)
return src;
};
/**
* fnMOVXb(dst, src)
*
* Helper for opMOVSXb() and opMOVZXb()
*
* @this {X86CPU}
* @param {number} dst (current value, ignored)
* @param {number} src (new value)
* @return {number} dst (updated value, from src)
*/
X86.fnMOVXb = function(dst, src)
{
/*
* The ModRegByte handlers update the registers in the 1st column, but we need to update those in the 2nd column.
*
* 000: AL -> 000: AX
* 001: CL -> 001: CX
* 010: DL -> 010: DX
* 011: BL -> 011: BX
* 100: AH -> 100: SP
* 101: CH -> 101: BP
* 110: DH -> 110: SI
* 111: BH -> 111: DI
*/
var reg = (this.bModRM & 0x38) >> 3;
switch(reg) {
case 0x4:
this.regXX = this.regEAX;
break;
case 0x5:
this.regXX = this.regECX;
break;
case 0x6:
this.regXX = this.regEDX;
break;
case 0x7:
this.regXX = this.regEBX;
break;
}
return src;
};
/**
* fnMOVn(dst, src)
*
@ -1532,15 +1580,50 @@ X86.fnMOVn = function(dst, src)
};
/**
* fnMOVxx(dst, src)
* fnMOVwsr(dst, src)
*
* @this {X86CPU}
* @param {number} dst (current value, ignored)
* @param {number} src (new value)
* @return {number} dst (src is overridden, replaced with regXX, as specified by opMOVwsr() or opMOVrc())
* @return {number} dst
*/
X86.fnMOVxx = function(dst, src)
X86.fnMOVwsr = function(dst, src)
{
var reg = (this.bModRM & 0x38) >> 3;
switch (reg) {
case 0x0:
src = this.segES.sel;
break;
case 0x1:
src = this.segCS.sel;
break;
case 0x2:
src = this.segSS.sel;
break;
case 0x3:
src = this.segDS.sel;
break;
case 0x4:
if (I386 && this.model >= X86.MODEL_80386) {
src = this.segFS.sel;
break;
}
X86.opInvalid.call(this);
src = dst;
break;
case 0x5:
if (I386 && this.model >= X86.MODEL_80386) {
src = this.segGS.sel;
break;
}
/* falls through */
default:
X86.opInvalid.call(this);
src = dst;
break;
}
/*
* When a 32-bit OPERAND size is in effect, segment register writes via opMOVwsr() must write 32 bits
* (zero-extended) if the destination is a register, but only 16 bits if the destination is memory,
@ -1551,7 +1634,61 @@ X86.fnMOVxx = function(dst, src)
if (this.regEAWrite !== X86.ADDR_INVALID) {
this.setDataSize(2);
}
return X86.fnMOV.call(this, dst, this.regXX);
return X86.fnMOV.call(this, dst, src);
};
/**
* fnMOVsrw(dst, src)
*
* This helper saves the contents of the general-purpose register that will be overwritten, so that the caller
* can restore it after moving the updated value to the correct segment register.
*
* @this {X86CPU}
* @param {number} dst (current value, ignored)
* @param {number} src (new value)
* @return {number} dst (updated value, from src)
*/
X86.fnMOVsrw = function(dst, src)
{
var reg = (this.bModRM >> 3) & 0x7;
switch(reg) {
case 0x0:
this.regXX = this.regEAX;
break;
case 0x2:
this.regXX = this.regEDX;
break;
case 0x3:
this.regXX = this.regEBX;
break;
default:
if (this.model == X86.MODEL_80286 || this.model == X86.MODEL_80386 && reg != 0x4 && reg != 0x5) {
X86.opInvalid.call(this);
break;
}
switch(reg) {
case 0x1: // MOV to CS is undocumented on 8086/8088/80186/80188, and invalid on 80286 and up
this.regXX = this.regECX;
break;
case 0x4: // this form of MOV to ES is undocumented on 8086/8088/80186/80188, invalid on 80286, and uses FS starting with 80386
this.regXX = this.getSP();
break;
case 0x5: // this form of MOV to CS is undocumented on 8086/8088/80186/80188, invalid on 80286, and uses GS starting with 80386
this.regXX = this.regEBP;
break;
case 0x6: // this form of MOV to SS is undocumented on 8086/8088/80186/80188, invalid on 80286 and up
this.regXX = this.regESI;
break;
case 0x7: // this form of MOV to DS is undocumented on 8086/8088/80186/80188, invalid on 80286 and up
this.regXX = this.regEDI;
break;
default:
break;
}
break;
}
return src;
};
/**
@ -3103,9 +3240,9 @@ X86.fnXCHGrb = function(dst, src)
this.nStepCycles -= this.cycleCounts.nOpCyclesXchgRR;
} else {
/*
* This is a case where the ModRM decoder that's calling us didn't know it should have called modEAByte()
* instead of getEAByte(), so we compensate by updating regEAWrite. However, setEAByte() has since been
* changed to revalidate the write using segEA:offEA, so updating regEAWrite here isn't strictly necessary.
* This is a case where the ModRM decoder that's calling us didn't know it should have set regEAWrite,
* so we compensate by updating regEAWrite. However, setEAWord() has since been changed to revalidate
* the write using segEA:offEA, so updating regEAWrite here isn't strictly necessary.
*/
this.regEAWrite = this.regEA;
this.setEAByte(dst);
@ -3168,9 +3305,9 @@ X86.fnXCHGrw = function(dst, src)
this.nStepCycles -= this.cycleCounts.nOpCyclesXchgRR;
} else {
/*
* This is a case where the ModRM decoder that's calling us didn't know it should have called modEAWord()
* instead of getEAWord(), so we compensate by updating regEAWrite. However, setEAWord() has since been
* changed to revalidate the write using segEA:offEA, so updating regEAWrite here isn't strictly necessary.
* This is a case where the ModRM decoder that's calling us didn't know it should have set regEAWrite,
* so we compensate by updating regEAWrite. However, setEAWord() has since been changed to revalidate
* the write using segEA:offEA, so updating regEAWrite here isn't strictly necessary.
*/
this.regEAWrite = this.regEA;
this.setEAWord(dst);

View file

@ -288,7 +288,7 @@ X86.fnLCR3 = function(l)
X86.fnSETcc = function(fnSet)
{
this.opFlags |= X86.OPFLAG.NOREAD;
this.aOpModMemByte[this.getIPByte()].call(this, fnSet);
this.decodeModMemByte.call(this, fnSet);
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 4 : 5);
};

View file

@ -1,5 +1,5 @@
/**
* @fileoverview Implements PCjs control flow helpers.
* @fileoverview Implements PCjs control flow functions.
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
* @version 1.0
* Created 2016-Mar-04

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

4184
modules/pcjs/lib/x86mods.js Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -43,11 +43,11 @@ if (NODE) {
*/
X86.opGRP6 = function()
{
var bModRM = this.getIPByte();
var bModRM = this.peekIPByte();
if ((bModRM & 0x38) < 0x10) { // possible reg values: 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
this.opFlags |= X86.OPFLAG.NOREAD;
}
this.aOpModGrpWord[bModRM].call(this, this.aOpGrp6, X86.fnSRCNone);
this.decodeModGrpWord.call(this, this.aOpGrp6, X86.fnSRCNone);
};
/**
@ -57,11 +57,11 @@ X86.opGRP6 = function()
*/
X86.opGRP7 = function()
{
var bModRM = this.getIPByte();
var bModRM = this.peekIPByte();
if (!(bModRM & 0x10)) {
this.opFlags |= X86.OPFLAG.NOREAD;
}
this.aOpModGrpWord[bModRM].call(this, X86.aOpGrp7, X86.fnSRCNone);
this.decodeModGrpWord.call(this, X86.aOpGrp7, X86.fnSRCNone);
};
/**
@ -80,7 +80,7 @@ X86.opLAR = function()
X86.opInvalid.call(this);
return;
}
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLAR);
this.decodeModRegWord.call(this, X86.fnLAR);
};
/**
@ -99,7 +99,7 @@ X86.opLSL = function()
X86.opInvalid.call(this);
return;
}
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLSL);
this.decodeModRegWord.call(this, X86.fnLSL);
};
/**
@ -567,6 +567,7 @@ X86.opMOVdr = function()
}
this.nStepCycles -= (iDst < 4? 22 : 14);
/*
* TODO: Implement BACKTRACK for this instruction (although Debug registers are not likely to be a conduit for interesting data).
*/
@ -1214,7 +1215,7 @@ X86.opPOPFS = function()
*/
X86.opBT = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTMem);
this.decodeModMemWord.call(this, X86.fnBTMem);
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 6;
};
@ -1227,7 +1228,7 @@ X86.opBT = function()
*/
X86.opSHLDn = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, this.sizeData == 2? X86.fnSHLDwi : X86.fnSHLDdi);
this.decodeModMemWord.call(this, this.sizeData == 2? X86.fnSHLDwi : X86.fnSHLDdi);
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
};
@ -1240,7 +1241,7 @@ X86.opSHLDn = function()
*/
X86.opSHLDcl = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, this.sizeData == 2? X86.fnSHLDwCL : X86.fnSHLDdCL);
this.decodeModMemWord.call(this, this.sizeData == 2? X86.fnSHLDwCL : X86.fnSHLDdCL);
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
};
@ -1253,7 +1254,7 @@ X86.opSHLDcl = function()
*/
X86.opXBTS = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnXBTS);
this.decodeModRegWord.call(this, X86.fnXBTS);
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 6 : 13);
};
@ -1266,7 +1267,7 @@ X86.opXBTS = function()
*/
X86.opIBTS = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnIBTS);
this.decodeModMemWord.call(this, X86.fnIBTS);
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 12 : 19);
};
@ -1319,7 +1320,7 @@ X86.opPOPGS = function()
*/
X86.opBTS = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTSMem);
this.decodeModMemWord.call(this, X86.fnBTSMem);
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 5;
};
@ -1332,7 +1333,7 @@ X86.opBTS = function()
*/
X86.opSHRDn = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, this.sizeData == 2? X86.fnSHRDwi : X86.fnSHRDdi);
this.decodeModMemWord.call(this, this.sizeData == 2? X86.fnSHRDwi : X86.fnSHRDdi);
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
};
@ -1345,7 +1346,7 @@ X86.opSHRDn = function()
*/
X86.opSHRDcl = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, this.sizeData == 2? X86.fnSHRDwCL : X86.fnSHRDdCL);
this.decodeModMemWord.call(this, this.sizeData == 2? X86.fnSHRDwCL : X86.fnSHRDdCL);
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
};
@ -1358,7 +1359,7 @@ X86.opSHRDcl = function()
*/
X86.opIMUL = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, this.sizeData == 2? X86.fnIMULrw : X86.fnIMULrd);
this.decodeModRegWord.call(this, this.sizeData == 2? X86.fnIMULrw : X86.fnIMULrd);
};
/**
@ -1372,7 +1373,7 @@ X86.opIMUL = function()
*/
X86.opLSS = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLSS);
this.decodeModRegWord.call(this, X86.fnLSS);
};
/**
@ -1384,7 +1385,7 @@ X86.opLSS = function()
*/
X86.opBTR = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTRMem);
this.decodeModMemWord.call(this, X86.fnBTRMem);
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 5;
};
@ -1399,7 +1400,7 @@ X86.opBTR = function()
*/
X86.opLFS = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLFS);
this.decodeModRegWord.call(this, X86.fnLFS);
};
/**
@ -1413,7 +1414,7 @@ X86.opLFS = function()
*/
X86.opLGS = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLGS);
this.decodeModRegWord.call(this, X86.fnLGS);
};
/**
@ -1425,36 +1426,8 @@ X86.opLGS = function()
*/
X86.opMOVZXb = function()
{
/*
* The ModRegByte handlers update the registers in the 1st column, but we need to update those in the 2nd column.
*
* 000: AL -> 000: AX
* 001: CL -> 001: CX
* 010: DL -> 010: DX
* 011: BL -> 011: BX
* 100: AH -> 100: SP
* 101: CH -> 101: BP
* 110: DH -> 110: SI
* 111: BH -> 111: DI
*/
var temp;
var bModRM = this.getIPByte();
var reg = (bModRM & 0x38) >> 3;
switch(reg) {
case 0x4:
temp = this.regEAX;
break;
case 0x5:
temp = this.regECX;
break;
case 0x6:
temp = this.regEDX;
break;
case 0x7:
temp = this.regEBX;
break;
}
this.aOpModRegByte[bModRM].call(this, X86.fnMOVX);
this.decodeModRegByte.call(this, X86.fnMOVXb);
var reg = (this.bModRM & 0x38) >> 3;
switch(reg) {
case 0x0:
this.regEAX = (this.regEAX & ~this.maskData) | (this.regEAX & 0xff);
@ -1470,19 +1443,19 @@ X86.opMOVZXb = function()
break;
case 0x4:
this.regESP = (this.regESP & ~this.maskData) | ((this.regEAX >> 8) & 0xff);
this.regEAX = temp;
this.regEAX = this.regXX;
break;
case 0x5:
this.regEBP = (this.regEBP & ~this.maskData) | ((this.regECX >> 8) & 0xff);
this.regECX = temp;
this.regECX = this.regXX;
break;
case 0x6:
this.regESI = (this.regESI & ~this.maskData) | ((this.regEDX >> 8) & 0xff);
this.regEDX = temp;
this.regEDX = this.regXX;
break;
case 0x7:
this.regEDI = (this.regEDI & ~this.maskData) | ((this.regEBX >> 8) & 0xff);
this.regEBX = temp;
this.regEBX = this.regXX;
break;
}
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
@ -1497,10 +1470,9 @@ X86.opMOVZXb = function()
*/
X86.opMOVZXw = function()
{
var bModRM = this.getIPByte();
this.setDataSize(2);
this.aOpModRegWord[bModRM].call(this, X86.fnMOVX);
switch((bModRM & 0x38) >> 3) {
this.decodeModRegWord.call(this, X86.fnMOVX);
switch((this.bModRM & 0x38) >> 3) {
case 0x0:
this.regEAX = (this.regEAX & 0xffff);
break;
@ -1536,7 +1508,7 @@ X86.opMOVZXw = function()
*/
X86.opGRP8 = function()
{
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp8, this.getIPByte);
this.decodeModGrpWord.call(this, X86.aOpGrp8, this.getIPByte);
};
/**
@ -1548,7 +1520,7 @@ X86.opGRP8 = function()
*/
X86.opBTC = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTCMem);
this.decodeModMemWord.call(this, X86.fnBTCMem);
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 5;
};
@ -1561,7 +1533,7 @@ X86.opBTC = function()
*/
X86.opBSF = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnBSF);
this.decodeModRegWord.call(this, X86.fnBSF);
};
/**
@ -1573,7 +1545,7 @@ X86.opBSF = function()
*/
X86.opBSR = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnBSR);
this.decodeModRegWord.call(this, X86.fnBSR);
};
/**
@ -1585,36 +1557,8 @@ X86.opBSR = function()
*/
X86.opMOVSXb = function()
{
/*
* The ModRegByte handlers update the registers in the 1st column, but we need to update those in the 2nd column.
*
* 000: AL -> 000: AX
* 001: CL -> 001: CX
* 010: DL -> 010: DX
* 011: BL -> 011: BX
* 100: AH -> 100: SP
* 101: CH -> 101: BP
* 110: DH -> 110: SI
* 111: BH -> 111: DI
*/
var temp;
var bModRM = this.getIPByte();
var reg = (bModRM & 0x38) >> 3;
switch(reg) {
case 0x4:
temp = this.regEAX;
break;
case 0x5:
temp = this.regECX;
break;
case 0x6:
temp = this.regEDX;
break;
case 0x7:
temp = this.regEBX;
break;
}
this.aOpModRegByte[bModRM].call(this, X86.fnMOVX);
this.decodeModRegByte.call(this, X86.fnMOVXb);
var reg = (this.bModRM & 0x38) >> 3;
switch(reg) {
case 0x0:
this.regEAX = (this.regEAX & ~this.maskData) | ((((this.regEAX & 0xff) << 24) >> 24) & this.maskData);
@ -1630,19 +1574,19 @@ X86.opMOVSXb = function()
break;
case 0x4:
this.regESP = (this.regESP & ~this.maskData) | (((this.regEAX << 16) >> 24) & this.maskData);
this.regEAX = temp;
this.regEAX = this.regXX;
break;
case 0x5:
this.regEBP = (this.regEBP & ~this.maskData) | (((this.regECX << 16) >> 24) & this.maskData);
this.regECX = temp;
this.regECX = this.regXX;
break;
case 0x6:
this.regESI = (this.regESI & ~this.maskData) | (((this.regEDX << 16) >> 24) & this.maskData);
this.regEDX = temp;
this.regEDX = this.regXX;
break;
case 0x7:
this.regEDI = (this.regEDI & ~this.maskData) | (((this.regEBX << 16) >> 24) & this.maskData);
this.regEBX = temp;
this.regEBX = this.regXX;
break;
}
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
@ -1657,10 +1601,9 @@ X86.opMOVSXb = function()
*/
X86.opMOVSXw = function()
{
var bModRM = this.getIPByte();
this.setDataSize(2);
this.aOpModRegWord[bModRM].call(this, X86.fnMOVX);
switch((bModRM & 0x38) >> 3) {
this.decodeModRegWord.call(this, X86.fnMOVX);
switch((this.bModRM & 0x38) >> 3) {
case 0x0:
this.regEAX = ((this.regEAX << 16) >> 16);
break;

View file

@ -45,7 +45,7 @@ if (NODE) {
*/
X86.opADDmb = function()
{
var b = this.getIPByte();
this.decodeModMemByte.call(this, X86.fnADDb);
/*
* Opcode bytes 0x00 0x00 are sufficiently uncommon that it's more likely we've started
* executing in the weeds, so if you're in DEBUG mode, we'll print a warning and stop the
@ -54,11 +54,10 @@ X86.opADDmb = function()
* Notice that we also test fRunning: this allows the Debugger to step over the instruction,
* because its trace ("t") command doesn't "run" the CPU; it merely "steps" the CPU.
*/
if (DEBUG && !b && this.aFlags.fRunning) {
if (DEBUG && !this.bModRM && this.aFlags.fRunning) {
this.printMessage("suspicious opcode: 0x00 0x00", DEBUGGER || this.bitsMessage);
if (DEBUGGER && this.dbg) this.dbg.stopCPU();
}
this.aOpModMemByte[b].call(this, X86.fnADDb);
};
/**
@ -68,7 +67,7 @@ X86.opADDmb = function()
*/
X86.opADDmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnADDw);
this.decodeModMemWord.call(this, X86.fnADDw);
};
/**
@ -78,7 +77,7 @@ X86.opADDmw = function()
*/
X86.opADDrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnADDb);
this.decodeModRegByte.call(this, X86.fnADDb);
};
/**
@ -88,7 +87,7 @@ X86.opADDrb = function()
*/
X86.opADDrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnADDw);
this.decodeModRegWord.call(this, X86.fnADDw);
};
/**
@ -164,7 +163,7 @@ X86.opPOPES = function()
*/
X86.opORmb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnORb);
this.decodeModMemByte.call(this, X86.fnORb);
};
/**
@ -174,7 +173,7 @@ X86.opORmb = function()
*/
X86.opORmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnORw);
this.decodeModMemWord.call(this, X86.fnORw);
};
/**
@ -184,7 +183,7 @@ X86.opORmw = function()
*/
X86.opORrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnORb);
this.decodeModRegByte.call(this, X86.fnORb);
};
/**
@ -194,7 +193,7 @@ X86.opORrb = function()
*/
X86.opORrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnORw);
this.decodeModRegWord.call(this, X86.fnORw);
};
/**
@ -274,7 +273,7 @@ X86.op0F = function()
*/
X86.opADCmb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnADCb);
this.decodeModMemByte.call(this, X86.fnADCb);
};
/**
@ -284,7 +283,7 @@ X86.opADCmb = function()
*/
X86.opADCmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnADCw);
this.decodeModMemWord.call(this, X86.fnADCw);
};
/**
@ -294,7 +293,7 @@ X86.opADCmw = function()
*/
X86.opADCrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnADCb);
this.decodeModRegByte.call(this, X86.fnADCb);
};
/**
@ -304,7 +303,7 @@ X86.opADCrb = function()
*/
X86.opADCrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnADCw);
this.decodeModRegWord.call(this, X86.fnADCw);
};
/**
@ -376,7 +375,7 @@ X86.opPOPSS = function()
*/
X86.opSBBmb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnSBBb);
this.decodeModMemByte.call(this, X86.fnSBBb);
};
/**
@ -386,7 +385,7 @@ X86.opSBBmb = function()
*/
X86.opSBBmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnSBBw);
this.decodeModMemWord.call(this, X86.fnSBBw);
};
/**
@ -396,7 +395,7 @@ X86.opSBBmw = function()
*/
X86.opSBBrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnSBBb);
this.decodeModRegByte.call(this, X86.fnSBBb);
};
/**
@ -406,7 +405,7 @@ X86.opSBBrb = function()
*/
X86.opSBBrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnSBBw);
this.decodeModRegWord.call(this, X86.fnSBBw);
};
/**
@ -478,7 +477,7 @@ X86.opPOPDS = function()
*/
X86.opANDmb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnANDb);
this.decodeModMemByte.call(this, X86.fnANDb);
};
/**
@ -488,7 +487,7 @@ X86.opANDmb = function()
*/
X86.opANDmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnANDw);
this.decodeModMemWord.call(this, X86.fnANDw);
};
/**
@ -498,7 +497,7 @@ X86.opANDmw = function()
*/
X86.opANDrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnANDb);
this.decodeModRegByte.call(this, X86.fnANDb);
};
/**
@ -508,7 +507,7 @@ X86.opANDrb = function()
*/
X86.opANDrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnANDw);
this.decodeModRegWord.call(this, X86.fnANDw);
};
/**
@ -586,7 +585,7 @@ X86.opDAA = function()
*/
X86.opSUBmb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnSUBb);
this.decodeModMemByte.call(this, X86.fnSUBb);
};
/**
@ -596,7 +595,7 @@ X86.opSUBmb = function()
*/
X86.opSUBmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnSUBw);
this.decodeModMemWord.call(this, X86.fnSUBw);
};
/**
@ -606,7 +605,7 @@ X86.opSUBmw = function()
*/
X86.opSUBrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnSUBb);
this.decodeModRegByte.call(this, X86.fnSUBb);
};
/**
@ -616,7 +615,7 @@ X86.opSUBrb = function()
*/
X86.opSUBrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnSUBw);
this.decodeModRegWord.call(this, X86.fnSUBw);
};
/**
@ -694,7 +693,7 @@ X86.opDAS = function()
*/
X86.opXORmb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnXORb);
this.decodeModMemByte.call(this, X86.fnXORb);
};
/**
@ -704,7 +703,7 @@ X86.opXORmb = function()
*/
X86.opXORmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnXORw);
this.decodeModMemWord.call(this, X86.fnXORw);
};
/**
@ -714,7 +713,7 @@ X86.opXORmw = function()
*/
X86.opXORrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnXORb);
this.decodeModRegByte.call(this, X86.fnXORb);
};
/**
@ -724,7 +723,7 @@ X86.opXORrb = function()
*/
X86.opXORrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnXORw);
this.decodeModRegWord.call(this, X86.fnXORw);
};
/**
@ -803,7 +802,7 @@ X86.opAAA = function()
*/
X86.opCMPmb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnCMPb);
this.decodeModMemByte.call(this, X86.fnCMPb);
};
/**
@ -813,7 +812,7 @@ X86.opCMPmb = function()
*/
X86.opCMPmw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnCMPw);
this.decodeModMemWord.call(this, X86.fnCMPw);
};
/**
@ -823,7 +822,7 @@ X86.opCMPmw = function()
*/
X86.opCMPrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnCMPb);
this.decodeModRegByte.call(this, X86.fnCMPb);
};
/**
@ -833,7 +832,7 @@ X86.opCMPrb = function()
*/
X86.opCMPrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnCMPw);
this.decodeModRegWord.call(this, X86.fnCMPw);
};
/**
@ -1440,7 +1439,7 @@ X86.opPOPA = function()
*/
X86.opBOUND = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnBOUND);
this.decodeModRegWord.call(this, X86.fnBOUND);
};
/**
@ -1475,7 +1474,7 @@ X86.opARPL = function()
X86.opInvalid.call(this);
return;
}
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnARPL);
this.decodeModMemWord.call(this, X86.fnARPL);
};
/**
@ -1593,7 +1592,7 @@ X86.opPUSHn = function()
*/
X86.opIMULn = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnIMULn);
this.decodeModRegWord.call(this, X86.fnIMULn);
};
/**
@ -1615,7 +1614,7 @@ X86.opPUSH8 = function()
*/
X86.opIMUL8 = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnIMUL8);
this.decodeModRegWord.call(this, X86.fnIMUL8);
};
/**
@ -2082,7 +2081,7 @@ X86.opJNLE = function()
*/
X86.opGRP1b = function()
{
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp1b, this.getIPByte);
this.decodeModGrpByte.call(this, X86.aOpGrp1b, this.getIPByte);
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.cycleCounts.nOpCyclesArithMID);
};
@ -2093,7 +2092,7 @@ X86.opGRP1b = function()
*/
X86.opGRP1w = function()
{
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPWord);
this.decodeModGrpWord.call(this, X86.aOpGrp1w, this.getIPWord);
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.cycleCounts.nOpCyclesArithMID);
};
@ -2108,7 +2107,7 @@ X86.opGRP1w = function()
*/
X86.opGRP1sw = function()
{
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPDisp);
this.decodeModGrpWord.call(this, X86.aOpGrp1w, this.getIPDisp);
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.cycleCounts.nOpCyclesArithMID);
};
@ -2119,7 +2118,7 @@ X86.opGRP1sw = function()
*/
X86.opTESTrb = function()
{
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnTESTb);
this.decodeModMemByte.call(this, X86.fnTESTb);
};
/**
@ -2129,7 +2128,7 @@ X86.opTESTrb = function()
*/
X86.opTESTrw = function()
{
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnTESTw);
this.decodeModMemWord.call(this, X86.fnTESTw);
};
/**
@ -2162,7 +2161,7 @@ X86.opXCHGrb = function()
* this.regEDX = (this.regEDX & 0xff) | (b << 8);
* }
*/
this.aOpModRegByte[this.bModRM = this.getIPByte()].call(this, X86.fnXCHGrb);
this.decodeModRegByte.call(this, X86.fnXCHGrb);
};
/**
@ -2175,7 +2174,7 @@ X86.opXCHGrb = function()
*/
X86.opXCHGrw = function()
{
this.aOpModRegWord[this.bModRM = this.getIPByte()].call(this, X86.fnXCHGrw);
this.decodeModRegWord.call(this, X86.fnXCHGrw);
};
/**
@ -2189,7 +2188,7 @@ X86.opMOVmb = function()
* Like other MOV operations, the destination does not need to be read, just written.
*/
this.opFlags |= X86.OPFLAG.NOREAD;
this.aOpModMemByte[this.getIPByte()].call(this, X86.fnMOV);
this.decodeModMemByte.call(this, X86.fnMOV);
};
/**
@ -2203,7 +2202,7 @@ X86.opMOVmw = function()
* Like other MOV operations, the destination does not need to be read, just written.
*/
this.opFlags |= X86.OPFLAG.NOREAD;
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnMOV);
this.decodeModMemWord.call(this, X86.fnMOV);
};
/**
@ -2213,7 +2212,7 @@ X86.opMOVmw = function()
*/
X86.opMOVrb = function()
{
this.aOpModRegByte[this.getIPByte()].call(this, X86.fnMOV);
this.decodeModRegByte.call(this, X86.fnMOV);
};
/**
@ -2223,57 +2222,24 @@ X86.opMOVrb = function()
*/
X86.opMOVrw = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnMOV);
this.decodeModRegWord.call(this, X86.fnMOV);
};
/**
* op=0x8C (MOV word,sreg)
*
* NOTE: Since the ModRM decoders deal only with general-purpose registers, we must move
* the appropriate segment register into a special variable (regXX), which our helper function
* (fnMOVxx) will use to replace the decoder's src operand.
* NOTE: Since the ModRM decoders deal only with general-purpose registers, we rely on our helper
* function (fnMOVwsr) to select the appropriate segment register and replace the decoder's src operand.
*
* @this {X86CPU}
*/
X86.opMOVwsr = function()
{
var bModRM = this.getIPByte();
var reg = (bModRM & 0x38) >> 3;
switch (reg) {
case 0x0:
this.regXX = this.segES.sel;
break;
case 0x1:
this.regXX = this.segCS.sel;
break;
case 0x2:
this.regXX = this.segSS.sel;
break;
case 0x3:
this.regXX = this.segDS.sel;
break;
case 0x4:
if (I386 && this.model >= X86.MODEL_80386) {
this.regXX = this.segFS.sel;
break;
}
X86.opInvalid.call(this);
return;
case 0x5:
if (I386 && this.model >= X86.MODEL_80386) {
this.regXX = this.segGS.sel;
break;
}
/* falls through */
default:
X86.opInvalid.call(this);
return;
}
/*
* Like other MOV operations, the destination does not need to be read, just written.
*/
this.opFlags |= X86.OPFLAG.NOREAD;
this.aOpModMemWord[bModRM].call(this, X86.fnMOVxx);
this.decodeModMemWord.call(this, X86.fnMOVwsr);
};
/**
@ -2285,84 +2251,46 @@ X86.opLEA = function()
{
this.opFlags |= X86.OPFLAG.NOREAD;
this.segData = this.segStack = this.segNULL; // we can't have the EA calculation, if any, "polluted" by segment arithmetic
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLEA);
this.decodeModRegWord.call(this, X86.fnLEA);
};
/**
* op=0x8E (MOV sreg,word)
*
* NOTE: Since the ModRM decoders deal only with general-purpose registers, we have to
* make a note of which general-purpose register will be overwritten, so that we can restore it
* after moving the modified value to the correct segment register.
* NOTE: Since the ModRM decoders deal only with general-purpose registers, we rely on our
* helper function (fnMOVsrw) to make a note of which general-purpose register will be overwritten,
* so that we can restore it after moving the updated value to the correct segment register.
*
* @this {X86CPU}
*/
X86.opMOVsrw = function()
{
var temp, sel;
var bModRM = this.getIPByte();
var reg = (bModRM & 0x38) >> 3;
switch(reg) {
case 0x0:
temp = this.regEAX;
break;
case 0x2:
temp = this.regEDX;
break;
case 0x3:
temp = this.regEBX;
break;
default:
if (this.model == X86.MODEL_80286 || this.model == X86.MODEL_80386 && reg != 0x4 && reg != 0x5) {
X86.opInvalid.call(this);
return;
}
switch(reg) {
case 0x1: // MOV to CS is undocumented on 8086/8088/80186/80188, and invalid on 80286 and up
temp = this.regECX;
break;
case 0x4: // this form of MOV to ES is undocumented on 8086/8088/80186/80188, invalid on 80286, and uses FS starting with 80386
temp = this.getSP();
break;
case 0x5: // this form of MOV to CS is undocumented on 8086/8088/80186/80188, invalid on 80286, and uses GS starting with 80386
temp = this.regEBP;
break;
case 0x6: // this form of MOV to SS is undocumented on 8086/8088/80186/80188, invalid on 80286 and up
temp = this.regESI;
break;
case 0x7: // this form of MOV to DS is undocumented on 8086/8088/80186/80188, invalid on 80286 and up
temp = this.regEDI;
break;
default:
break;
}
break;
}
this.aOpModRegWord[bModRM].call(this, X86.fnMOV);
switch (reg) {
var sel;
this.decodeModRegWord.call(this, X86.fnMOVsrw);
switch ((this.bModRM >> 3) & 0x7) {
case 0x0:
sel = this.regEAX;
this.regEAX = temp;
this.regEAX = this.regXX;
this.setES(sel);
break;
case 0x1:
sel = this.regECX;
this.regECX = temp;
this.regECX = this.regXX;
this.setCS(sel);
break;
case 0x2:
sel = this.regEDX;
this.regEDX = temp;
this.regEDX = this.regXX;
this.setSS(sel);
break;
case 0x3:
sel = this.regEBX;
this.regEBX = temp;
this.regEBX = this.regXX;
this.setDS(sel);
break;
case 0x4:
sel = this.getSP();
this.setSP(temp);
this.setSP(this.regXX);
if (I386 && this.model >= X86.MODEL_80386) {
this.setFS(sel);
} else {
@ -2371,7 +2299,7 @@ X86.opMOVsrw = function()
break;
case 0x5:
sel = this.regEBP;
this.regEBP = temp;
this.regEBP = this.regXX;
if (I386 && this.model >= X86.MODEL_80386) {
this.setGS(sel);
} else {
@ -2380,12 +2308,12 @@ X86.opMOVsrw = function()
break;
case 0x6:
sel = this.regESI;
this.regESI = temp;
this.regESI = this.regXX;
this.setSS(sel);
break;
case 0x7:
sel = this.regEDI;
this.regEDI = temp;
this.regEDI = this.regXX;
this.setDS(sel);
break;
}
@ -2425,7 +2353,7 @@ X86.opPOPmw = function()
*/
this.regXX = this.popWord();
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrpPOPw, X86.fnSRCxx);
this.decodeModGrpWord.call(this, X86.aOpGrpPOPw, X86.fnSRCxx);
this.opLSP = X86.ADDR_INVALID;
};
@ -2873,7 +2801,8 @@ X86.opCMPSb = function()
}
if (nReps--) {
var bDst = this.getEAByte(this.segData, this.regESI & maskAddr);
var bSrc = this.modEAByte(this.segES, this.regEDI & maskAddr);
var bSrc = this.getEAByte(this.segES, this.regEDI & maskAddr);
this.regEAWrite = this.regEA; // TODO: Is this necessary?
/*
* fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary.
*
@ -2920,7 +2849,8 @@ X86.opCMPSw = function()
}
if (nReps--) {
var wDst = this.getEAWord(this.segData, this.regESI & maskAddr);
var wSrc = this.modEAWord(this.segES, this.regEDI & maskAddr);
var wSrc = this.getEAWord(this.segES, this.regEDI & maskAddr);
this.regEAWrite = this.regEA; // TODO: Is this necessary?
/*
* fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary.
*
@ -3162,7 +3092,10 @@ X86.opSCASb = function()
if (!(this.opPrefixes & X86.OPFLAG.REPEAT)) this.nStepCycles -= this.cycleCounts.nOpCyclesScaSr0;
}
if (nReps--) {
X86.fnCMPb.call(this, this.regEAX & 0xff, this.modEAByte(this.segES, this.regEDI & maskAddr));
var bDst = this.regEAX & 0xff;
var bSrc = this.getEAByte(this.segES, this.regEDI & maskAddr);
this.regEAWrite = this.regEA; // TODO: Is this necessary?
X86.fnCMPb.call(this, bDst, bSrc);
/*
* fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary.
*
@ -3205,7 +3138,10 @@ X86.opSCASw = function()
if (!(this.opPrefixes & X86.OPFLAG.REPEAT)) this.nStepCycles -= this.cycleCounts.nOpCyclesScaSr0;
}
if (nReps--) {
X86.fnCMPw.call(this, this.regEAX & this.maskData, this.modEAWord(this.segES, this.regEDI & maskAddr));
var wDst = this.regEAX & this.maskData;
var wSrc = this.getEAWord(this.segES, this.regEDI & maskAddr);
this.regEAWrite = this.regEA; // TODO: Is this necessary?
X86.fnCMPw.call(this, wDst, wSrc);
/*
* fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary.
*
@ -3441,7 +3377,7 @@ X86.opMOVDI = function()
*/
X86.opGRP2bn = function()
{
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp2b, X86.fnSRCByte);
this.decodeModGrpByte.call(this, X86.aOpGrp2b, X86.fnSRCByte);
};
/**
@ -3451,7 +3387,7 @@ X86.opGRP2bn = function()
*/
X86.opGRP2wn = function()
{
this.aOpModGrpWord[this.getIPByte()].call(this, this.sizeData == 2? X86.aOpGrp2w : X86.aOpGrp2d, X86.fnSRCByte);
this.decodeModGrpWord.call(this, this.sizeData == 2? X86.aOpGrp2w : X86.aOpGrp2d, X86.fnSRCByte);
};
/**
@ -3489,7 +3425,7 @@ X86.opRET = function()
*/
X86.opLES = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLES);
this.decodeModRegWord.call(this, X86.fnLES);
};
/**
@ -3501,7 +3437,7 @@ X86.opLES = function()
*/
X86.opLDS = function()
{
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLDS);
this.decodeModRegWord.call(this, X86.fnLDS);
};
/**
@ -3515,7 +3451,7 @@ X86.opMOVb = function()
* Like other MOV operations, the destination does not need to be read, just written.
*/
this.opFlags |= X86.OPFLAG.NOREAD;
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrpMOVn, this.getIPByte);
this.decodeModGrpByte.call(this, X86.aOpGrpMOVn, this.getIPByte);
};
/**
@ -3529,7 +3465,7 @@ X86.opMOVw = function()
* Like other MOV operations, the destination does not need to be read, just written.
*/
this.opFlags |= X86.OPFLAG.NOREAD;
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrpMOVn, this.getIPWord);
this.decodeModGrpWord.call(this, X86.aOpGrpMOVn, this.getIPWord);
};
/**
@ -3710,7 +3646,7 @@ X86.opIRET = function()
*/
X86.opGRP2b1 = function()
{
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp2b, X86.fnSRC1);
this.decodeModGrpByte.call(this, X86.aOpGrp2b, X86.fnSRC1);
};
/**
@ -3720,7 +3656,7 @@ X86.opGRP2b1 = function()
*/
X86.opGRP2w1 = function()
{
this.aOpModGrpWord[this.getIPByte()].call(this, this.sizeData == 2? X86.aOpGrp2w : X86.aOpGrp2d, X86.fnSRC1);
this.decodeModGrpWord.call(this, this.sizeData == 2? X86.aOpGrp2w : X86.aOpGrp2d, X86.fnSRC1);
};
/**
@ -3730,7 +3666,7 @@ X86.opGRP2w1 = function()
*/
X86.opGRP2bCL = function()
{
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp2b, X86.fnSRCCL);
this.decodeModGrpByte.call(this, X86.aOpGrp2b, X86.fnSRCCL);
};
/**
@ -3740,7 +3676,7 @@ X86.opGRP2bCL = function()
*/
X86.opGRP2wCL = function()
{
this.aOpModGrpWord[this.getIPByte()].call(this, this.sizeData == 2? X86.aOpGrp2w : X86.aOpGrp2d, X86.fnSRCCL);
this.decodeModGrpWord.call(this, this.sizeData == 2? X86.aOpGrp2w : X86.aOpGrp2d, X86.fnSRCCL);
};
/**
@ -3882,7 +3818,7 @@ X86.opXLAT = function()
X86.opESC = function(bOpcode)
{
this.bOpcode = bOpcode;
this.aOpModRegWord[this.bModRM = this.getIPByte()].call(this, X86.fnESC);
this.decodeModRegWord.call(this, X86.fnESC);
};
/**
@ -4356,7 +4292,7 @@ X86.opCMC = function()
X86.opGRP3b = function()
{
this.fMDSet = false;
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp3b, X86.fnSRCNone);
this.decodeModGrpByte.call(this, X86.aOpGrp3b, X86.fnSRCNone);
if (this.fMDSet) this.regEAX = (this.regEAX & ~this.maskData) | (this.regMDLo & this.maskData);
};
@ -4382,7 +4318,7 @@ X86.opGRP3b = function()
X86.opGRP3w = function()
{
this.fMDSet = false;
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp3w, X86.fnSRCNone);
this.decodeModGrpWord.call(this, X86.aOpGrp3w, X86.fnSRCNone);
if (this.fMDSet) {
this.regEAX = (this.regEAX & ~this.maskData) | (this.regMDLo & this.maskData);
this.regEDX = (this.regEDX & ~this.maskData) | (this.regMDHi & this.maskData);
@ -4481,7 +4417,7 @@ X86.opSTD = function()
*/
X86.opGRP4b = function()
{
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp4b, X86.fnSRCNone);
this.decodeModGrpByte.call(this, X86.aOpGrp4b, X86.fnSRCNone);
};
/**
@ -4491,7 +4427,7 @@ X86.opGRP4b = function()
*/
X86.opGRP4w = function()
{
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp4w, X86.fnSRCNone);
this.decodeModGrpWord.call(this, X86.aOpGrp4w, X86.fnSRCNone);
};
/**