Assorted Debugger fixes
This commit is contained in:
parent
a150bc51aa
commit
c2187e1e1b
28 changed files with 2360 additions and 2212 deletions
|
|
@ -453,10 +453,10 @@ if (DEBUGGER) {
|
|||
Debugger.TYPE_IMPREG = 0x0060; // implicit register in TYPE_IREG
|
||||
Debugger.TYPE_IMPSEG = 0x0070; // implicit segment register in TYPE_IREG
|
||||
Debugger.TYPE_MODRM = 0x0080; // (E) standard ModRM decoding
|
||||
Debugger.TYPE_MEM = 0x0090; // (M) ModRM refers to memory only
|
||||
Debugger.TYPE_REG = 0x00A0; // (G) standard Reg decoding
|
||||
Debugger.TYPE_SEGREG = 0x00B0; // (S) Reg selects segment register
|
||||
Debugger.TYPE_MODREG = 0x00C0; // (R) Mod refers to register only
|
||||
Debugger.TYPE_MODMEM = 0x0090; // (M) ModRM refers to memory only
|
||||
Debugger.TYPE_MODREG = 0x00A0; // (R) ModRM refers to register only
|
||||
Debugger.TYPE_REG = 0x00B0; // (G) standard Reg decoding
|
||||
Debugger.TYPE_SEGREG = 0x00C0; // (S) Reg selects segment register
|
||||
Debugger.TYPE_CTLREG = 0x00D0; // (C) Reg selects control register
|
||||
Debugger.TYPE_DBGREG = 0x00E0; // (D) Reg selects debug register
|
||||
Debugger.TYPE_TSTREG = 0x00F0; // (T) Reg selects test register
|
||||
|
|
@ -779,7 +779,7 @@ if (DEBUGGER) {
|
|||
/* 0x8A */ [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_BYTE | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
/* 0x8B */ [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
/* 0x8C */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_SEGREG | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
/* 0x8D */ [Debugger.INS.LEA, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_VWORD],
|
||||
/* 0x8D */ [Debugger.INS.LEA, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MODMEM | Debugger.TYPE_VWORD],
|
||||
/* 0x8E */ [Debugger.INS.MOV, Debugger.TYPE_SEGREG | Debugger.TYPE_WORD | Debugger.TYPE_OUT, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
/* 0x8F */ [Debugger.INS.POP, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_OUT],
|
||||
|
||||
|
|
@ -841,10 +841,10 @@ if (DEBUGGER) {
|
|||
/* 0xC1 */ [Debugger.INS.GRP2W, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_BOTH | Debugger.TYPE_80186, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
/* 0xC2 */ [Debugger.INS.RET, Debugger.TYPE_IMM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
/* 0xC3 */ [Debugger.INS.RET],
|
||||
/* 0xC4 */ [Debugger.INS.LES, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
/* 0xC5 */ [Debugger.INS.LDS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
/* 0xC6 */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_OUT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
/* 0xC7 */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_IMM | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
/* 0xC4 */ [Debugger.INS.LES, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MODMEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
/* 0xC5 */ [Debugger.INS.LDS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MODMEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
/* 0xC6 */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_OUT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
/* 0xC7 */ [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_IMM | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
|
||||
/* 0xC8 */ [Debugger.INS.ENTER, Debugger.TYPE_IMM | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_80286, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
/* 0xC9 */ [Debugger.INS.LEAVE, Debugger.TYPE_NONE | Debugger.TYPE_80286],
|
||||
|
|
@ -913,12 +913,12 @@ if (DEBUGGER) {
|
|||
Debugger.aaOp0FDescs = {
|
||||
0x00: [Debugger.INS.GRP6, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
|
||||
0x01: [Debugger.INS.GRP7, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
|
||||
0x02: [Debugger.INS.LAR, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0x02: [Debugger.INS.LAR, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MODMEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MODMEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0x05: [Debugger.INS.LOADALL,Debugger.TYPE_80286],
|
||||
0x06: [Debugger.INS.CLTS, Debugger.TYPE_80286],
|
||||
0x20: [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x22: [Debugger.INS.MOV, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x20: [Debugger.INS.MOV, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x22: [Debugger.INS.MOV, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x80: [Debugger.INS.JO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||
0x81: [Debugger.INS.JNO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||
0x82: [Debugger.INS.JC, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||
|
|
@ -962,10 +962,10 @@ if (DEBUGGER) {
|
|||
0xAC: [Debugger.INS.SHRD, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_IN, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
0xAD: [Debugger.INS.SHRD, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_IN, Debugger.TYPE_IMPREG | Debugger.TYPE_CL | Debugger.TYPE_IN],
|
||||
0xAF: [Debugger.INS.IMUL, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_BOTH | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
0xB2: [Debugger.INS.LSS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
0xB2: [Debugger.INS.LSS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MODMEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
0xB3: [Debugger.INS.BTR, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
0xB4: [Debugger.INS.LFS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
0xB5: [Debugger.INS.LGS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
0xB4: [Debugger.INS.LFS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MODMEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
0xB5: [Debugger.INS.LGS, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT, Debugger.TYPE_MODMEM | Debugger.TYPE_SEGP | Debugger.TYPE_IN],
|
||||
0xB6: [Debugger.INS.MOVZX, Debugger.TYPE_REG | Debugger.TYPE_VWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
0xB7: [Debugger.INS.MOVZX, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0xBA: [Debugger.INS.GRP8, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_BOTH | Debugger.TYPE_80386, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
|
|
@ -1703,7 +1703,7 @@ if (DEBUGGER) {
|
|||
Debugger.prototype.hexOffset = function(off, sel, fAddr32)
|
||||
{
|
||||
if (sel != null) {
|
||||
return str.toHex(sel, 4) + ":" + str.toHex(off, (off & (0xffff0000|0)) || fAddr32? 8 : 4);
|
||||
return str.toHex(sel, 4) + ":" + str.toHex(off, (off & ~0xffff) || fAddr32? 8 : 4);
|
||||
}
|
||||
return str.toHex(off);
|
||||
};
|
||||
|
|
@ -1899,7 +1899,7 @@ if (DEBUGGER) {
|
|||
if (fGate) {
|
||||
sDump = "seg=" + str.toHexWord(seg.base & 0xffff) + " off=" + str.toHexWord(seg.limit);
|
||||
} else {
|
||||
sDump = "base=" + str.toHex(seg.base, this.cchAddr) + " limit=" + str.toHex(seg.limit, (seg.limit & ~0xffff)? 8 : 4);
|
||||
sDump = "base=" + str.toHex(seg.base, this.cchAddr) + " limit=" + this.getLimitString(seg.limit);
|
||||
}
|
||||
/*
|
||||
* When we dump the EXT word, we mask off the LIMIT1619 and BASE2431 bits, because those have already
|
||||
|
|
@ -2981,23 +2981,23 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* addBreakpoint(aBreak, dbgAddr, fTempBreak)
|
||||
* addBreakpoint(aBreak, dbgAddr, fTemp)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aBreak
|
||||
* @param {{DbgAddr}} dbgAddr
|
||||
* @param {boolean} [fTempBreak]
|
||||
* @param {boolean} [fTemp]
|
||||
* @return {boolean} true if breakpoint added, false if already exists
|
||||
*/
|
||||
Debugger.prototype.addBreakpoint = function(aBreak, dbgAddr, fTempBreak)
|
||||
Debugger.prototype.addBreakpoint = function(aBreak, dbgAddr, fTemp)
|
||||
{
|
||||
if (!this.findBreakpoint(aBreak, dbgAddr)) {
|
||||
dbgAddr.fTempBreak = fTempBreak;
|
||||
dbgAddr.fTempBreak = fTemp;
|
||||
aBreak.push(dbgAddr);
|
||||
if (aBreak != this.aBreakExec) {
|
||||
this.bus.addMemBreak(this.getAddr(dbgAddr), aBreak == this.aBreakWrite);
|
||||
}
|
||||
if (fTempBreak) {
|
||||
if (fTemp) {
|
||||
/*
|
||||
* Force temporary breakpoints to be interpreted as linear breakpoints
|
||||
* (hence the assertion that there IS a linear address stored in dbgAddr);
|
||||
|
|
@ -3008,7 +3008,7 @@ if (DEBUGGER) {
|
|||
} else {
|
||||
this.println("breakpoint enabled: " + this.hexAddr(dbgAddr) + " (" + aBreak[0] + ")");
|
||||
}
|
||||
this.historyInit();
|
||||
if (!fTemp) this.historyInit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -3304,11 +3304,29 @@ if (DEBUGGER) {
|
|||
if (bModRM < 0) {
|
||||
bModRM = this.getByte(dbgAddr, 1);
|
||||
}
|
||||
if (typeMode >= Debugger.TYPE_REG) {
|
||||
sOperand = this.getRegOperand((bModRM >> 3) & 0x7, type, dbgAddr);
|
||||
if (typeMode < Debugger.TYPE_MODREG) {
|
||||
/*
|
||||
* This test also encompasses TYPE_MODMEM, which is basically the inverse of the case
|
||||
* below (ie, only Mod values *other* than 11 are allowed); however, I believe that in
|
||||
* some cases that's merely a convention, and that if you try to execute an instruction
|
||||
* like "LEA AX,BX", it will actually do something (on some if not all processors), so
|
||||
* there's probably some diagnostic value in allowing those cases to be disassembled.
|
||||
*/
|
||||
sOperand = this.getModRMOperand(bModRM, type, dbgAddr);
|
||||
}
|
||||
else if (typeMode == Debugger.TYPE_MODREG) {
|
||||
/*
|
||||
* TYPE_MODREG instructions assume that Mod is 11 (only certain early 80486 steppings
|
||||
* actually *required* that Mod contain 11) and always treat RM as a register (which we
|
||||
* could also simulate by setting Mod to 11 and letting getModRMOperand() do its thing).
|
||||
*/
|
||||
sOperand = this.getRegOperand(bModRM & 0x7, type, dbgAddr);
|
||||
}
|
||||
else {
|
||||
sOperand = this.getModRMOperand(bModRM, type, dbgAddr);
|
||||
/*
|
||||
* All the remaining cases are Reg-centric; getRegOperand() will figure out which case.
|
||||
*/
|
||||
sOperand = this.getRegOperand((bModRM >> 3) & 0x7, type, dbgAddr);
|
||||
}
|
||||
}
|
||||
else if (typeMode == Debugger.TYPE_ONE) {
|
||||
|
|
@ -3647,6 +3665,18 @@ if (DEBUGGER) {
|
|||
return sFlag + (b? '1' : '0') + ' ';
|
||||
};
|
||||
|
||||
/**
|
||||
* getLimitString(l)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} l
|
||||
* @return {string}
|
||||
*/
|
||||
Debugger.prototype.getLimitString = function(l)
|
||||
{
|
||||
return str.toHex(l, (l & ~0xffff)? 8 : 4);
|
||||
};
|
||||
|
||||
/**
|
||||
* getRegString(iReg)
|
||||
*
|
||||
|
|
@ -3672,7 +3702,7 @@ if (DEBUGGER) {
|
|||
*/
|
||||
Debugger.prototype.getSegString = function(seg, fProt)
|
||||
{
|
||||
return seg.sName + '=' + str.toHex(seg.sel, 4) + (fProt? '[' + str.toHex(seg.base, this.cchAddr) + ',' + str.toHex(seg.limit, (seg.limit & ~0xffff)? 8 : 4) + ']' : "");
|
||||
return seg.sName + '=' + str.toHex(seg.sel, 4) + (fProt? '[' + str.toHex(seg.base, this.cchAddr) + ',' + this.getLimitString(seg.limit) + ']' : "");
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4950,7 +4980,7 @@ if (DEBUGGER) {
|
|||
}
|
||||
var fValid = false;
|
||||
var w = str.parseInt(sValue, 16);
|
||||
if (!isNaN(w)) {
|
||||
if (w !== undefined) {
|
||||
fValid = true;
|
||||
var sRegMatch = sReg.toUpperCase();
|
||||
if (sRegMatch.charAt(0) == 'E' && this.cchReg <= 4) {
|
||||
|
|
@ -5110,12 +5140,14 @@ if (DEBUGGER) {
|
|||
break;
|
||||
case "CR0":
|
||||
this.cpu.regCR0 = w;
|
||||
X86.fnLCR0.call(this.cpu, w);
|
||||
break;
|
||||
case "CR2":
|
||||
this.cpu.regCR2 = w;
|
||||
break;
|
||||
case "CR3":
|
||||
this.cpu.regCR3 = w;
|
||||
X86.fnLCR3.call(this.cpu, w);
|
||||
break;
|
||||
/*
|
||||
* TODO: Add support for DR0-DR7 and TR6-TR7.
|
||||
|
|
|
|||
|
|
@ -438,8 +438,8 @@ X86CPU.CYCLES_80286 = {
|
|||
};
|
||||
|
||||
/*
|
||||
* TODO: Except for the cycle counts at the end of this table (ie, those marked "unique to the 80386"), all these
|
||||
* values were simply copied from the 80286 table and still need to be modified and verified.
|
||||
* TODO: All these values were simply copied from the 80286 table and still need to be modified and verified.
|
||||
* Cycle counts for 80386-only instructions are hard-coded in their respective handlers, since those counts don't vary.
|
||||
*/
|
||||
X86CPU.CYCLES_80386 = {
|
||||
nWordCyclePenalty: 0,
|
||||
|
|
@ -554,25 +554,7 @@ X86CPU.CYCLES_80386 = {
|
|||
nOpCyclesTestMI: 6,
|
||||
nOpCyclesXchgRR: 3,
|
||||
nOpCyclesXchgRM: 5,
|
||||
nOpCyclesXLAT: 5,
|
||||
/*
|
||||
* Cycle counts unique to the 80386
|
||||
*/
|
||||
nOpCyclesBitScan: 11,
|
||||
nOpCyclesBitSetR: 6,
|
||||
nOpCyclesBitSetM: 8,
|
||||
nOpCyclesBitSetMExtra: 5, // extra cycle cost for non-immediate BTC/BTR/BTS opcodes
|
||||
nOpCyclesBitTestR: 3,
|
||||
nOpCyclesBitTestM: 6,
|
||||
nOpCyclesBitTestMExtra: 6, // extra cycle cost for non-immediate BT opcode
|
||||
nOpCyclesIMulR: 9,
|
||||
nOpCyclesIMulM: 12,
|
||||
nOpCyclesMovXR: 3,
|
||||
nOpCyclesMovXM: 6,
|
||||
nOpCyclesSetR: 4,
|
||||
nOpCyclesSetM: 5,
|
||||
nOpCyclesShiftDR: 3,
|
||||
nOpCyclesShiftDM: 7
|
||||
nOpCyclesXLAT: 5
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -723,6 +705,7 @@ X86CPU.prototype.enablePageBlocks = function()
|
|||
}
|
||||
}
|
||||
this.aBlocksPaged = [];
|
||||
this.stopCPU();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1351,6 +1334,25 @@ X86CPU.prototype.resetRegs = function()
|
|||
this.setProtMode();
|
||||
};
|
||||
|
||||
/**
|
||||
* setAddrSize(size)
|
||||
*
|
||||
* This is used by opcodes that require a particular ADDRESS size, which we enforce by
|
||||
* internally simulating an ADDRESS size override, if needed.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} size (2 for 2-byte/16-bit operands, or 4 for 4-byte/32-bit operands)
|
||||
*/
|
||||
X86CPU.prototype.setAddrSize = function(size)
|
||||
{
|
||||
if (this.addrSize != size) {
|
||||
this.opPrefixes |= X86.OPFLAG.ADDRSIZE;
|
||||
this.addrSize = size;
|
||||
this.addrMask = (size == 2? 0xffff : (0xffffffff|0));
|
||||
this.updateAddrSize();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateAddrSize()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ X86.fnBSF = function BSF(dst, src)
|
|||
n++; // TODO: Determine if n should be incremented before the bailout for an accurate cycle count
|
||||
}
|
||||
}
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesBitScan + n * 3;
|
||||
this.nStepCycles -= 11 + n * 3;
|
||||
return dst;
|
||||
};
|
||||
|
||||
|
|
@ -263,7 +263,7 @@ X86.fnBSR = function BSR(dst, src)
|
|||
}
|
||||
|
||||
}
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesBitScan + n * 3;
|
||||
this.nStepCycles -= 11 + n * 3;
|
||||
return dst;
|
||||
};
|
||||
|
||||
|
|
@ -278,7 +278,7 @@ X86.fnBSR = function BSR(dst, src)
|
|||
X86.fnBT = function BT(dst, src)
|
||||
{
|
||||
if (dst & (1 << (src & 0x1f))) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesBitTestR : this.cycleCounts.nOpCyclesBitTestM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -295,7 +295,7 @@ X86.fnBTC = function BTC(dst, src)
|
|||
{
|
||||
var bit = 1 << (src & 0x1f);
|
||||
if (dst & bit) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesBitSetR : this.cycleCounts.nOpCyclesBitSetM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 6 : 8);
|
||||
return dst ^ bit;
|
||||
};
|
||||
|
||||
|
|
@ -311,7 +311,7 @@ X86.fnBTR = function BTR(dst, src)
|
|||
{
|
||||
var bit = 1 << (src & 0x1f);
|
||||
if (dst & bit) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesBitSetR : this.cycleCounts.nOpCyclesBitSetM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 6 : 8);
|
||||
return dst & ~bit;
|
||||
};
|
||||
|
||||
|
|
@ -327,7 +327,7 @@ X86.fnBTS = function BTS(dst, src)
|
|||
{
|
||||
var bit = 1 << (src & 0x1f);
|
||||
if (dst & bit) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesBitSetR : this.cycleCounts.nOpCyclesBitSetM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 6 : 8);
|
||||
return dst | bit;
|
||||
};
|
||||
|
||||
|
|
@ -1118,7 +1118,7 @@ X86.fnIMULrw = function IMULrw(dst, src)
|
|||
this.clearCF(); this.clearOF();
|
||||
}
|
||||
result &= 0xffff;
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulR : this.cycleCounts.nOpCyclesIMulM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 9 : 12);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
|
@ -1139,7 +1139,7 @@ X86.fnIMULrd = function IMULrd(dst, src)
|
|||
this.clearCF(); this.clearOF();
|
||||
}
|
||||
result |= 0;
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulR : this.cycleCounts.nOpCyclesIMulM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 9 : 12);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
|
@ -2438,7 +2438,7 @@ X86.fnSETcc = function SETcc(fnSet)
|
|||
{
|
||||
this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
this.aOpModMemByte[this.getIPByte()].call(this, fnSet);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesSetR : this.cycleCounts.nOpCyclesSetM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 4 : 5);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -200,29 +200,23 @@ X86.opCLTS = function CLTS()
|
|||
*
|
||||
* op=0x0F,0x20 (MOV reg,creg)
|
||||
*
|
||||
* NOTE: Since the ModRM decoders deal only with general-purpose registers, we must move
|
||||
* the appropriate control register into a special variable (regXX), which our helper function
|
||||
* (fnMOVxx) will use to replace the decoder's src operand.
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* From PCMag_Prog_TechRef, p.476: "The 80386 executes the MOV to/from control registers (CRn)
|
||||
* regardless of the setting of the MOD field. The MOD field should be set to 0b11, but an early
|
||||
* 80386 documentation error indicated that the MOD field value was a don't care. Early versions
|
||||
* of the 80486 detect a MOD != 0b11 as an illegal opcode. This was changed in later versions to
|
||||
* ignore the value of MOD. Assemblers that generate MOD != 0b11 for these instructions will fail
|
||||
* on some 80486s."
|
||||
* From PCMag_Prog_TechRef, p.476: "The 80386 executes the MOV to/from control registers (CRn) regardless
|
||||
* of the setting of the MOD field. The MOD field should be set to 0b11, but an early 80386 documentation
|
||||
* error indicated that the MOD field value was a don't care. Early versions of the 80486 detect
|
||||
* a MOD != 0b11 as an illegal opcode. This was changed in later versions to ignore the value of MOD.
|
||||
* Assemblers that generate MOD != 0b11 for these instructions will fail on some 80486s."
|
||||
*
|
||||
* And in fact, the Compaq DeskPro 386 ROM BIOS executes this instruction with MOD set to 0b00, so we have
|
||||
* to ignore it.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opMOVrc = function MOVrc()
|
||||
{
|
||||
/*
|
||||
* We address the MOD field problem (see above) by coercing it to 0b11 (0xc0), regardless.
|
||||
*
|
||||
* TODO: One issue not clearly addressed is if, when an assembler/compiler generated a bogus MOD value,
|
||||
* it also generated the additional displacement bytes, if any, that would typically accompany such a MOD
|
||||
* value. I assume not.
|
||||
*/
|
||||
var bModRM = this.getIPByte() | 0xc0;
|
||||
var bModRM = this.getIPByte();
|
||||
|
||||
if (this.segCS.cpl) {
|
||||
/*
|
||||
|
|
@ -233,35 +227,54 @@ X86.opMOVrc = function MOVrc()
|
|||
return;
|
||||
}
|
||||
|
||||
var reg = (bModRM & 0x38) >> 3;
|
||||
switch(reg) {
|
||||
var reg;
|
||||
switch((bModRM & 0x38) >> 3) {
|
||||
case 0x0:
|
||||
this.regXX = this.regCR0;
|
||||
break;
|
||||
case 0x1:
|
||||
this.regXX = this.regCR1;
|
||||
reg = this.regCR0;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regXX = this.regCR2;
|
||||
reg = this.regCR2;
|
||||
break;
|
||||
case 0x3:
|
||||
this.regXX = this.regCR3;
|
||||
reg = this.regCR3;
|
||||
break;
|
||||
default:
|
||||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(bModRM & 0x7) {
|
||||
case 0x0:
|
||||
this.regEAX = reg;
|
||||
break;
|
||||
case 0x1:
|
||||
this.regECX = reg;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regEDX = reg;
|
||||
break;
|
||||
case 0x3:
|
||||
this.regEBX = reg;
|
||||
break;
|
||||
case 0x4:
|
||||
this.regESP = reg;
|
||||
break;
|
||||
case 0x5:
|
||||
this.regEBP = reg;
|
||||
break;
|
||||
case 0x6:
|
||||
this.regESI = reg;
|
||||
break;
|
||||
case 0x7:
|
||||
this.regEDI = reg;
|
||||
break;
|
||||
}
|
||||
|
||||
this.nStepCycles -= 6;
|
||||
|
||||
/*
|
||||
* Like other MOV operations, the destination does not need to be read, just written;
|
||||
* however, it's moot, because we've already restricted this opcode to registers only.
|
||||
*
|
||||
* this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
*
|
||||
* Another issue, however, is that this instruction always assumes a 32-bit OPERAND size,
|
||||
* so we must call setDataSize(4) first.
|
||||
* TODO: Implement BACKTRACK for this instruction....
|
||||
*/
|
||||
this.setDataSize(4);
|
||||
this.aOpModRegWord[bModRM].call(this, X86.fnMOVxx);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -269,30 +282,23 @@ X86.opMOVrc = function MOVrc()
|
|||
*
|
||||
* op=0x0F,0x22 (MOV creg,reg)
|
||||
*
|
||||
* 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 control register.
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* From PCMag_Prog_TechRef, p.476: "The 80386 executes the MOV to/from control registers (CRn)
|
||||
* regardless of the setting of the MOD field. The MOD field should be set to 0b11, but an early
|
||||
* 80386 documentation error indicated that the MOD field value was a don't care. Early versions
|
||||
* of the 80486 detect a MOD != 0b11 as an illegal opcode. This was changed in later versions to
|
||||
* ignore the value of MOD. Assemblers that generate MOD != 0b11 for these instructions will fail
|
||||
* on some 80486s."
|
||||
* From PCMag_Prog_TechRef, p.476: "The 80386 executes the MOV to/from control registers (CRn) regardless
|
||||
* of the setting of the MOD field. The MOD field should be set to 0b11, but an early 80386 documentation
|
||||
* error indicated that the MOD field value was a don't care. Early versions of the 80486 detect
|
||||
* a MOD != 0b11 as an illegal opcode. This was changed in later versions to ignore the value of MOD.
|
||||
* Assemblers that generate MOD != 0b11 for these instructions will fail on some 80486s."
|
||||
*
|
||||
* And in fact, the Compaq DeskPro 386 ROM BIOS executes this instruction with MOD set to 0b00, so we have
|
||||
* to ignore it.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opMOVcr = function MOVcr()
|
||||
{
|
||||
var temp;
|
||||
/*
|
||||
* We address the MOD field problem (see above) by coercing it to 0b11 (0xc0), regardless.
|
||||
*
|
||||
* TODO: One issue not clearly addressed is if, when an assembler/compiler generated a bogus MOD value,
|
||||
* it also generated the additional displacement bytes, if any, that would typically accompany such a MOD
|
||||
* value. I assume not.
|
||||
*/
|
||||
var bModRM = this.getIPByte() | 0xc0;
|
||||
var bModRM = this.getIPByte();
|
||||
|
||||
if (this.segCS.cpl) {
|
||||
/*
|
||||
|
|
@ -303,51 +309,55 @@ X86.opMOVcr = function MOVcr()
|
|||
return;
|
||||
}
|
||||
|
||||
var reg = (bModRM & 0x38) >> 3;
|
||||
switch(reg) {
|
||||
var reg;
|
||||
switch(bModRM & 0x7) {
|
||||
case 0x0:
|
||||
temp = this.regEAX;
|
||||
reg = this.regEAX;
|
||||
break;
|
||||
case 0x1:
|
||||
temp = this.regECX; // TODO: Is setting CR1 actually allowed on an 80386?
|
||||
reg = this.regECX;
|
||||
break;
|
||||
case 0x2:
|
||||
temp = this.regEDX;
|
||||
reg = this.regEDX;
|
||||
break;
|
||||
case 0x3:
|
||||
temp = this.regEBX;
|
||||
reg = this.regEBX;
|
||||
break;
|
||||
case 0x4:
|
||||
reg = this.regESP;
|
||||
break;
|
||||
case 0x5:
|
||||
reg = this.regEBP;
|
||||
break;
|
||||
case 0x6:
|
||||
reg = this.regESI;
|
||||
break;
|
||||
case 0x7:
|
||||
reg = this.regEDI;
|
||||
break;
|
||||
}
|
||||
|
||||
switch((bModRM & 0x38) >> 3) {
|
||||
case 0x0:
|
||||
X86.fnLCR0.call(this, reg);
|
||||
this.nStepCycles -= 10;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regCR2 = reg;
|
||||
this.nStepCycles -= 4;
|
||||
break;
|
||||
case 0x3:
|
||||
X86.fnLCR3.call(this, reg);
|
||||
this.nStepCycles -= 5;
|
||||
break;
|
||||
default:
|
||||
X86.opInvalid.call(this);
|
||||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This instruction always assumes a 32-bit OPERAND size, so we must call setDataSize(4) first.
|
||||
* TODO: Implement BACKTRACK for this instruction....
|
||||
*/
|
||||
this.setDataSize(4);
|
||||
this.aOpModRegWord[bModRM].call(this, X86.fnMOV);
|
||||
|
||||
switch(reg) {
|
||||
case 0x0:
|
||||
reg = this.regEAX;
|
||||
this.regEAX = temp;
|
||||
X86.fnLCR0.call(this, reg);
|
||||
break;
|
||||
case 0x1:
|
||||
this.regCR1 = this.regECX;
|
||||
this.regECX = temp;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regCR2 = this.regEDX;
|
||||
this.regEDX = temp;
|
||||
break;
|
||||
case 0x3:
|
||||
reg = this.regEBX;
|
||||
this.regEBX = temp;
|
||||
X86.fnLCR3.call(this, reg);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -883,7 +893,7 @@ X86.opPOPFS = function POPFS()
|
|||
X86.opBT = function BT()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBT);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= this.cycleCounts.nOpCyclesBitTestMExtra;
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 6;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -896,7 +906,7 @@ X86.opBT = function BT()
|
|||
X86.opSHLDn = function SHLDn()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHLDwi : X86.fnSHLDdi);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesShiftDR : this.cycleCounts.nOpCyclesShiftDM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -909,7 +919,7 @@ X86.opSHLDn = function SHLDn()
|
|||
X86.opSHLDcl = function SHLDcl()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHLDwCL : X86.fnSHLDdCL);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesShiftDR : this.cycleCounts.nOpCyclesShiftDM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -948,7 +958,7 @@ X86.opPOPGS = function POPGS()
|
|||
X86.opBTS = function BTS()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTS);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= this.cycleCounts.nOpCyclesBitSetMExtra;
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 5;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -961,7 +971,7 @@ X86.opBTS = function BTS()
|
|||
X86.opSHRDn = function SHRDn()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHRDwi : X86.fnSHRDdi);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesShiftDR : this.cycleCounts.nOpCyclesShiftDM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -974,7 +984,7 @@ X86.opSHRDn = function SHRDn()
|
|||
X86.opSHRDcl = function SHRDcl()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHRDwCL : X86.fnSHRDdCL);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesShiftDR : this.cycleCounts.nOpCyclesShiftDM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 7);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1013,7 +1023,7 @@ X86.opLSS = function LSS()
|
|||
X86.opBTR = function BTR()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTR);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= this.cycleCounts.nOpCyclesBitSetMExtra;
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 5;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1113,7 +1123,7 @@ X86.opMOVZXb = function MOVZXb()
|
|||
this.regEBX = temp;
|
||||
break;
|
||||
}
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMovXR : this.cycleCounts.nOpCyclesMovXM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1154,7 +1164,7 @@ X86.opMOVZXw = function MOVZXw()
|
|||
this.regEDI = (this.regEDI & 0xffff);
|
||||
break;
|
||||
}
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMovXR : this.cycleCounts.nOpCyclesMovXM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1177,7 +1187,7 @@ X86.opGRP8 = function GRP8()
|
|||
X86.opBTC = function BTC()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTC);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= this.cycleCounts.nOpCyclesBitSetMExtra;
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= 5;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1273,7 +1283,7 @@ X86.opMOVSXb = function MOVSXb()
|
|||
this.regEBX = temp;
|
||||
break;
|
||||
}
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMovXR : this.cycleCounts.nOpCyclesMovXM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1314,7 +1324,7 @@ X86.opMOVSXw = function MOVSXw()
|
|||
this.regEDI = ((this.regEDI << 16) >> 16);
|
||||
break;
|
||||
}
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMovXR : this.cycleCounts.nOpCyclesMovXM);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
|
||||
};
|
||||
|
||||
X86.aOps0F = new Array(256);
|
||||
|
|
@ -1333,14 +1343,26 @@ X86.aOps0F[0x06] = X86.opCLTS;
|
|||
X86.aOps0F[0x0B] = X86.opInvalid;
|
||||
|
||||
/*
|
||||
* NOTE: Any other opcode slots NOT explicitly initialized above with either a dedicated function OR opInvalid()
|
||||
* will be set to opUndefined() when initProcessor() finalizes the opcode tables. If the processor is an 80386,
|
||||
* initProcessor() will also incorporate all the handlers listed below in aOps0F386.
|
||||
* The following 0x0F opcodes are of no consequence to us, since they were all introduced post-80386;
|
||||
* 0x0F,0xA6 and 0x0F,0xA7 were introduced on some 80486 processors (and then deprecated), while 0x0F,0xB0
|
||||
* and 0x0F,0xB1 were introduced on 80586 (aka Pentium) processors.
|
||||
*
|
||||
* A call to opUndefined() implies something serious has occurred that merits our attention (eg, perhaps someone
|
||||
* is using an undocumented opcode that we haven't implemented yet), whereas a call to opInvalid() may or may not.
|
||||
* CMPXCHG r/m8,reg8 ; 0F B0 /r [PENT]
|
||||
* CMPXCHG r/m16,reg16 ; o16 0F B1 /r [PENT]
|
||||
* CMPXCHG r/m32,reg32 ; o32 0F B1 /r [PENT]
|
||||
* CMPXCHG486 r/m8,reg8 ; 0F A6 /r [486,UNDOC]
|
||||
* CMPXCHG486 r/m16,reg16 ; o16 0F A7 /r [486,UNDOC]
|
||||
* CMPXCHG486 r/m32,reg32 ; o32 0F A7 /r [486,UNDOC]
|
||||
*
|
||||
* For example, when Windows initializes in protected-mode, it sets a DPMI exception handler for UD_FAULT and
|
||||
* So why are we even mentioning them here? Only because some software (eg, Windows 3.00) attempts to execute
|
||||
* 0x0F,0xA6, so we need to explicitly mark it as invalid. TODO: Purely out of curiosity, I would like to
|
||||
* eventually learn *why* Windows 3.00 does this; is it hoping to use the CMPXCHG486 opcode, or is it performing
|
||||
* a CPU/stepping check to detect/work-around some errata, or....?
|
||||
*/
|
||||
X86.aOps0F[0xA6] = X86.opInvalid;
|
||||
|
||||
/*
|
||||
* When Windows 95 Setup initializes in protected-mode, it sets a DPMI exception handler for UD_FAULT and
|
||||
* then attempts to generate that exception with undefined opcode 0x0F,0xFF. Apparently, whoever wrote that code
|
||||
* (davidw?) didn't get the Intel memo regarding the preferred invalid opcode (0x0F,0x0B, aka UD2), or perhaps Intel
|
||||
* hadn't written that memo yet -- although if that's the case, then Intel should have followed Microsoft's lead and
|
||||
|
|
@ -1350,6 +1372,15 @@ X86.aOps0F[0x0B] = X86.opInvalid;
|
|||
*/
|
||||
X86.aOps0F[0xFF] = X86.opInvalid;
|
||||
|
||||
/*
|
||||
* NOTE: Any other opcode slots NOT explicitly initialized above with either a dedicated function OR opInvalid()
|
||||
* will be set to opUndefined() when initProcessor() finalizes the opcode tables. If the processor is an 80386,
|
||||
* initProcessor() will also incorporate all the handlers listed below in aOps0F386.
|
||||
*
|
||||
* A call to opUndefined() implies something serious has occurred that merits our attention (eg, perhaps someone
|
||||
* is using an undocumented opcode that we haven't implemented yet), whereas a call to opInvalid() may or may not.
|
||||
*/
|
||||
|
||||
if (I386) {
|
||||
X86.aOps0F386 = [];
|
||||
X86.aOps0F386[0x20] = X86.opMOVrc;
|
||||
|
|
|
|||
Loading…
Reference in a new issue