Added support for machine configs with a specific CPU stepping (also, fixed IMUL reg,r/m,imm disassembly)
This commit is contained in:
parent
b967ba9a52
commit
6dcb644a05
14 changed files with 1169 additions and 1096 deletions
|
|
@ -480,8 +480,7 @@ if (DEBUGGER) {
|
|||
Debugger.TYPE_OTHER = 0xF000; // "other" field
|
||||
|
||||
/*
|
||||
* TYPE_SIZE values. Some of the values (eg, TYPE_WORDIB and TYPE_WORDIW)
|
||||
* imply the presence of a third operand, for those weird cases....
|
||||
* TYPE_SIZE values.
|
||||
*/
|
||||
Debugger.TYPE_NONE = 0x0000; // (all other TYPE fields ignored)
|
||||
Debugger.TYPE_BYTE = 0x0001; // (b) byte, regardless of operand size
|
||||
|
|
@ -493,8 +492,6 @@ if (DEBUGGER) {
|
|||
Debugger.TYPE_FARP = 0x0007; // (p) 32-bit or 48-bit pointer for JMP/CALL
|
||||
Debugger.TYPE_2WORD = 0x0008; // (a) two memory operands (BOUND only)
|
||||
Debugger.TYPE_DESC = 0x0009; // (s) 6 byte pseudo-descriptor
|
||||
Debugger.TYPE_WORDIB = 0x000A; // two source operands (eg, IMUL)
|
||||
Debugger.TYPE_WORDIW = 0x000B; // two source operands (eg, IMUL)
|
||||
Debugger.TYPE_PREFIX = 0x000F; // (treat similarly to TYPE_NONE)
|
||||
|
||||
/*
|
||||
|
|
@ -763,9 +760,9 @@ if (DEBUGGER) {
|
|||
/* 0x67 */ [Debugger.INS.AS, Debugger.TYPE_PREFIX | Debugger.TYPE_80386],
|
||||
|
||||
/* 0x68 */ [Debugger.INS.PUSH, Debugger.TYPE_IMM | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80286],
|
||||
/* 0x69 */ [Debugger.INS.IMUL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_BOTH | Debugger.TYPE_80286, Debugger.TYPE_MODRM | Debugger.TYPE_WORDIW | Debugger.TYPE_IN],
|
||||
/* 0x69 */ [Debugger.INS.IMUL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_BOTH | Debugger.TYPE_80286, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_IN, Debugger.TYPE_IMM | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
/* 0x6A */ [Debugger.INS.PUSH, Debugger.TYPE_IMM | Debugger.TYPE_SBYTE | Debugger.TYPE_IN | Debugger.TYPE_80286],
|
||||
/* 0x6B */ [Debugger.INS.IMUL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_BOTH | Debugger.TYPE_80286, Debugger.TYPE_MODRM | Debugger.TYPE_WORDIB | Debugger.TYPE_IN],
|
||||
/* 0x6B */ [Debugger.INS.IMUL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MODRM | Debugger.TYPE_VWORD | Debugger.TYPE_IN, Debugger.TYPE_IMM | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
/* 0x6C */ [Debugger.INS.INS, Debugger.TYPE_ESDI | Debugger.TYPE_BYTE | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_DX | Debugger.TYPE_IN],
|
||||
/* 0x6D */ [Debugger.INS.INS, Debugger.TYPE_ESDI | Debugger.TYPE_VWORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_DX | Debugger.TYPE_IN],
|
||||
/* 0x6E */ [Debugger.INS.OUTS, Debugger.TYPE_DX | Debugger.TYPE_IN | Debugger.TYPE_80286, Debugger.TYPE_DSSI | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
var X86 = {
|
||||
/*
|
||||
* CPU model numbers
|
||||
* CPU model numbers (supported)
|
||||
*/
|
||||
MODEL_8086: 8086,
|
||||
MODEL_8088: 8088,
|
||||
|
|
@ -43,6 +43,12 @@ var X86 = {
|
|||
MODEL_80286: 80286,
|
||||
MODEL_80386: 80386,
|
||||
|
||||
/*
|
||||
* CPU stepping identifiers (supported)
|
||||
*/
|
||||
STEPPING_B1: 0xB1, // our version of the B1 stepping also includes the infamous 32-bit multiplication bug
|
||||
STEPPING_B2: 0xB2, // this is an imaginary stepping that simply means "B1 without the 32-bit multiplication bug" (ie, a B1 with the "double sigma" stamp)
|
||||
|
||||
/*
|
||||
* This constant is used to mark points in the code where the physical address being returned
|
||||
* is invalid and should not be used. TODO: There are still functions that will use an invalid
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ if (!I386) {
|
|||
* The X86CPU class uses the following (parmsCPU) properties:
|
||||
*
|
||||
* model: a number (eg, 8088) that should match one of the X86.MODEL values
|
||||
* stepping: a string (eg, "B1") that should match one of the X86.STEPPING values
|
||||
*
|
||||
* This extends the CPU class and passes any remaining parmsCPU properties to the CPU class
|
||||
* constructor, along with a default speed (cycles per second) based on the specified (or default)
|
||||
|
|
@ -109,6 +110,9 @@ function X86CPU(parmsCPU)
|
|||
{
|
||||
this.model = parmsCPU['model'] || X86.MODEL_8088;
|
||||
|
||||
var stepping = parmsCPU['stepping'];
|
||||
this.stepping = (stepping? str.parseInt(stepping, 16) : 0);
|
||||
|
||||
var nCyclesDefault = 0;
|
||||
switch(this.model) {
|
||||
case X86.MODEL_8088:
|
||||
|
|
@ -2884,6 +2888,12 @@ X86CPU.prototype.probeAddr = function(addr, size, fLinear)
|
|||
}
|
||||
if (block) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
/*
|
||||
* TODO: We actually hit this assert in rare cases where the Debugger is disassembling
|
||||
* an instruction straddling a page boundary that also references a short or long operand.
|
||||
* The best solution is to change the Debugger's getShort(), getLong(), etc, functions to
|
||||
* use getByte() internally, which in turn will never call probeAddr() with a size > 1.
|
||||
*/
|
||||
this.assert(off + (size || 1) <= this.nBlockSize);
|
||||
switch(size) {
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -2033,6 +2033,18 @@ X86.fnMULw = function(dst, src)
|
|||
this.regMDHi = (result >> 16) & 0xffff;
|
||||
} else {
|
||||
X86.fnMUL32.call(this, dst, this.regEAX);
|
||||
if (this.model == X86.MODEL_80386 && this.stepping == X86.STEPPING_B1) {
|
||||
if (this.regEAX == 0x0417A000 && dst == 0x00000081) {
|
||||
/*
|
||||
* In this case, the result should be 0x20FE7A000 (ie, regMDHi should be 0x2), and I'm not
|
||||
* sure what the typical failure would look like, so I'll just set regMDHi to 0.
|
||||
*
|
||||
* If you want a B1 stepping without this 32-bit multiplication flaw, select the B2 stepping.
|
||||
*/
|
||||
this.assert(this.regMDLo == 0x0FE7A000 && this.regMDHi == 0x00000002);
|
||||
this.regMDHi = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.regMDHi) {
|
||||
|
|
|
|||
|
|
@ -2940,8 +2940,27 @@ X86.opSTOSb = function STOSb()
|
|||
if (this.opFlags & X86.OPFLAG.FAULT) return;
|
||||
|
||||
if (BACKTRACK) this.backTrack.btiMem0 = this.backTrack.btiAL;
|
||||
this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & maskAddr);
|
||||
|
||||
this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr);
|
||||
|
||||
/*
|
||||
* Implement 80386 B1 Errata #7 (to the extent that Windows 95 checks for the errata). This
|
||||
* isn't a rock-solid implementation of the errata (for example, the ADDRESS override on the next
|
||||
* instruction, if it exists, may or may not be the first prefix byte), but it's close enough.
|
||||
*
|
||||
* Note that we carefully monkey with maskAddr only AFTER updating ECX, because this errata affects
|
||||
* only EDI in the case of STOS. The other instructions mentioned below monkey with different
|
||||
* registers, so read the errata carefully.
|
||||
*
|
||||
* TODO: Extend this errata to STOSW, as well as MOVSB, MOVSW, INSB, and INSW.
|
||||
*/
|
||||
if (this.model == X86.MODEL_80386 && this.stepping == X86.STEPPING_B1) {
|
||||
if (!(this.opPrefixes & X86.OPFLAG.ADDRSIZE) != (this.getByte(this.regLIP) != X86.OPCODE.AS)) {
|
||||
maskAddr ^= (0xffff0000|0);
|
||||
}
|
||||
}
|
||||
this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & maskAddr);
|
||||
|
||||
this.nStepCycles -= nCycles;
|
||||
if (nReps) {
|
||||
this.resetIP(-2);
|
||||
|
|
|
|||
|
|
@ -522,6 +522,12 @@
|
|||
<xsl:otherwise>8088</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="stepping">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@stepping"><xsl:value-of select="@stepping"/></xsl:when>
|
||||
<xsl:otherwise></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="cycles">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@cycles"><xsl:value-of select="@cycles"/></xsl:when>
|
||||
|
|
@ -561,7 +567,7 @@
|
|||
<xsl:call-template name="component">
|
||||
<xsl:with-param name="machine" select="$machine"/>
|
||||
<xsl:with-param name="class" select="'cpu'"/>
|
||||
<xsl:with-param name="parms">,model:<xsl:value-of select="$model"/>,cycles:<xsl:value-of select="$cycles"/>,multiplier:<xsl:value-of select="$multiplier"/>,autoStart:<xsl:value-of select="$autoStart"/>,csStart:<xsl:value-of select="$csStart"/>,csInterval:<xsl:value-of select="$csInterval"/>,csStop:<xsl:value-of select="$csStop"/></xsl:with-param>
|
||||
<xsl:with-param name="parms">,model:<xsl:value-of select="$model"/>,stepping:'<xsl:value-of select="$stepping"/>',cycles:<xsl:value-of select="$cycles"/>,multiplier:<xsl:value-of select="$multiplier"/>,autoStart:<xsl:value-of select="$autoStart"/>,csStart:<xsl:value-of select="$csStart"/>,csInterval:<xsl:value-of select="$csInterval"/>,csStop:<xsl:value-of select="$csStop"/></xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue