Baby steps

This commit is contained in:
Jeff Parsons 2015-02-02 14:36:30 -08:00 • committed by jeffpar
commit 2cd13b2058
11 changed files with 2808 additions and 2743 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -106,6 +106,16 @@ var BACKTRACK = !COMPILED;
*/ */
var SAMPLER = false; var SAMPLER = false;
/**
* @define {boolean}
*
* Enables support for known 8086 bugs. It's turned off by default, because 1) it adds overhead, and 2) it's
* hard to imagine any software actually being dependent on any of the bugs covered by this (eg, the failure to
* properly restart string instructions with multiple prefixes, or the failure to inhibit hardware interrupts
* following SS segment loads).
*/
var BUGS_8086 = false;
/** /**
* @define {boolean} * @define {boolean}
* *

View file

@ -356,7 +356,7 @@ X86.PS.SET = (X86.PS.BIT1 | X86.PS.IOPL.MASK | X86.PS.NT | X86.PS.BIT15);
* These "result registers" are created/reset by an initial call to setPS(0); they include: * These "result registers" are created/reset by an initial call to setPS(0); they include:
* *
* this.resultSize (must be set to one of: SIZE_BYTE or SIZE_WORD) * this.resultSize (must be set to one of: SIZE_BYTE or SIZE_WORD)
* this.resultValue * this.resultZeroCarry
* this.resultParitySign * this.resultParitySign
* this.resultAuxOverflow * this.resultAuxOverflow
* *

View file

@ -813,7 +813,7 @@ X86CPU.prototype.resetRegs = function()
this.regEBX = 0; this.regEBX = 0;
this.regECX = 0; this.regECX = 0;
this.regEDX = 0; this.regEDX = 0;
this.regESP = 0; // this isn't needed in a 16-bit environment, but we'll need it later this.regESP = 0; // this isn't needed in a 16-bit environment, but is required for I386
this.regEBP = 0; this.regEBP = 0;
this.regESI = 0; this.regESI = 0;
this.regEDI = 0; this.regEDI = 0;
@ -1356,9 +1356,9 @@ X86CPU.prototype.getCS = function()
X86CPU.prototype.setCS = function(sel) X86CPU.prototype.setCS = function(sel)
{ {
var regEIP = this.getIP(); var regEIP = this.getIP();
this.regLIP = this.segCS.load(sel & 0xffff) + regEIP; this.regLIP = this.segCS.load(sel) + regEIP;
this.regLIPLimit = this.segCS.base + this.segCS.limit; this.regLIPLimit = this.segCS.base + this.segCS.limit;
this.opFlags |= this.OPFLAG_NOINTR8086; if (!BUGS_8086) this.opFlags |= this.OPFLAG_NOINTR8086;
if (PREFETCH) this.flushPrefetch(this.regLIP); if (PREFETCH) this.flushPrefetch(this.regLIP);
}; };
@ -1381,8 +1381,8 @@ X86CPU.prototype.getDS = function()
*/ */
X86CPU.prototype.setDS = function(sel) X86CPU.prototype.setDS = function(sel)
{ {
this.segDS.load(sel & 0xffff); this.segDS.load(sel);
this.opFlags |= this.OPFLAG_NOINTR8086; if (!BUGS_8086) this.opFlags |= this.OPFLAG_NOINTR8086;
}; };
/** /**
@ -1401,14 +1401,20 @@ X86CPU.prototype.getSS = function()
* *
* @this {X86CPU} * @this {X86CPU}
* @param {number} sel * @param {number} sel
* @param {boolean} [fInterruptable]
*/ */
X86CPU.prototype.setSS = function(sel) X86CPU.prototype.setSS = function(sel, fInterruptable)
{ {
var regESP = this.getSP(); var regESP = this.getSP();
this.regLSP = this.segSS.load(sel & 0xffff) + regESP; this.regLSP = this.segSS.load(sel) + regESP;
this.regLSPLimit = this.segSS.base + this.segSS.limit; if (this.segSS.fExpDown) {
this.regLSPLimitLow = this.segSS.base; // TODO: Set this to the actual low limit this.regLSPLimit = this.segSS.base + this.segSS.addrMask;
this.opFlags |= X86.OPFLAG.NOINTR; this.regLSPLimitLow = this.segSS.base + this.segSS.limit;
} else {
this.regLSPLimit = this.segSS.base + this.segSS.limit;
this.regLSPLimitLow = this.segSS.base;
}
if (!BUGS_8086 && !fInterruptable) this.opFlags |= X86.OPFLAG.NOINTR;
}; };
/** /**
@ -1430,8 +1436,8 @@ X86CPU.prototype.getES = function()
*/ */
X86CPU.prototype.setES = function(sel) X86CPU.prototype.setES = function(sel)
{ {
this.segES.load(sel & 0xffff); this.segES.load(sel);
this.opFlags |= this.OPFLAG_NOINTR8086; if (!BUGS_8086) this.opFlags |= this.OPFLAG_NOINTR8086;
}; };
/** /**
@ -1546,6 +1552,10 @@ X86CPU.prototype.advanceIP = function(inc)
*/ */
X86CPU.prototype.getSP = function() X86CPU.prototype.getSP = function()
{ {
if (I386) {
this.assert(!((this.regLSP - this.segSS.base) & ~this.segSS.addrMask));
return (this.regESP & ~this.segSS.addrMask) | (this.regLSP - this.segSS.base);
}
return this.regLSP - this.segSS.base; return this.regLSP - this.segSS.base;
}; };
@ -1557,7 +1567,12 @@ X86CPU.prototype.getSP = function()
*/ */
X86CPU.prototype.setSP = function(off) X86CPU.prototype.setSP = function(off)
{ {
this.regLSP = this.segSS.base + (off & (I386? this.segSS.addrMask : 0xffff)); if (I386) {
this.regESP = off;
this.regLSP = this.segSS.base + (off & this.segSS.addrMask);
} else {
this.regLSP = this.segSS.base + off;
}
}; };
/** /**
@ -1568,7 +1583,7 @@ X86CPU.prototype.setSP = function(off)
*/ */
X86CPU.prototype.getCF = function() X86CPU.prototype.getCF = function()
{ {
return (this.resultValue & this.resultSize)? X86.PS.CF : 0; return (this.resultZeroCarry & this.resultSize)? X86.PS.CF : 0;
}; };
/** /**
@ -1621,7 +1636,7 @@ X86CPU.prototype.getAF = function()
*/ */
X86CPU.prototype.getZF = function() X86CPU.prototype.getZF = function()
{ {
return (this.resultValue & (this.resultSize - 1))? 0 : X86.PS.ZF; return (this.resultZeroCarry & (this.resultSize - 1))? 0 : X86.PS.ZF;
}; };
/** /**
@ -1686,7 +1701,7 @@ X86CPU.prototype.getDF = function()
*/ */
X86CPU.prototype.clearCF = function() X86CPU.prototype.clearCF = function()
{ {
this.resultValue &= ~this.resultSize; this.resultZeroCarry &= ~this.resultSize;
}; };
/** /**
@ -1716,7 +1731,7 @@ X86CPU.prototype.clearAF = function()
*/ */
X86CPU.prototype.clearZF = function() X86CPU.prototype.clearZF = function()
{ {
this.resultValue |= (this.resultSize - 1); this.resultZeroCarry |= (this.resultSize - 1);
}; };
/** /**
@ -1770,7 +1785,7 @@ X86CPU.prototype.clearOF = function()
*/ */
X86CPU.prototype.setCF = function() X86CPU.prototype.setCF = function()
{ {
this.resultValue |= this.resultSize; this.resultZeroCarry |= this.resultSize;
}; };
/** /**
@ -1800,7 +1815,7 @@ X86CPU.prototype.setAF = function()
*/ */
X86CPU.prototype.setZF = function() X86CPU.prototype.setZF = function()
{ {
this.resultValue &= ~(this.resultSize - 1); this.resultZeroCarry &= ~(this.resultSize - 1);
}; };
/** /**
@ -1868,7 +1883,7 @@ X86CPU.prototype.getPS = function()
X86CPU.prototype.setPS = function(regPS, cpl) X86CPU.prototype.setPS = function(regPS, cpl)
{ {
this.resultSize = X86.RESULT.SIZE_BYTE; // NOTE: We could have chosen SIZE_WORD, too; it's irrelevant this.resultSize = X86.RESULT.SIZE_BYTE; // NOTE: We could have chosen SIZE_WORD, too; it's irrelevant
this.resultValue = this.resultParitySign = this.resultAuxOverflow = 0; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = 0;
if (regPS & X86.PS.CF) this.setCF(); if (regPS & X86.PS.CF) this.setCF();
if (!(regPS & X86.PS.PF)) this.resultParitySign |= 0x1; if (!(regPS & X86.PS.PF)) this.resultParitySign |= 0x1;
@ -2608,7 +2623,10 @@ X86CPU.prototype.popWord = function()
{ {
var w = (I386? this.opMem.getWord(this.regLSP) : this.getShort(this.regLSP)); var w = (I386? this.opMem.getWord(this.regLSP) : this.getShort(this.regLSP));
this.regLSP += (I386? this.dataSize : 2); this.regLSP += (I386? this.dataSize : 2);
if (this.regLSP > this.regLSPLimit) this.setSP(this.regLSP - this.segSS.base); if (this.regLSP > this.regLSPLimit) {
// TODO: Generate exception in protected mode
this.setSP(this.regLSP - this.segSS.base);
}
return w; return w;
}; };
@ -2622,7 +2640,10 @@ X86CPU.prototype.pushWord = function(w)
{ {
this.assert((w & this.dataMask) == w); this.assert((w & this.dataMask) == w);
this.regLSP -= (I386? this.dataSize : 2); this.regLSP -= (I386? this.dataSize : 2);
if (this.regLSP < this.regLSPLimitLow) this.setSP(this.regLSP - this.segSS.base); if (this.regLSP < this.regLSPLimitLow) {
// TODO: Generate exception in protected mode (and bail)
this.setSP(this.regLSP - this.segSS.base);
}
if (!I386) this.setShort(this.regLSP, w); else this.opMem.setWord(this.regLSP, w); if (!I386) this.setShort(this.regLSP, w); else this.opMem.setWord(this.regLSP, w);
}; };
@ -2904,6 +2925,19 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
if (opPrefixes) { if (opPrefixes) {
this.opPrefixes |= opPrefixes; this.opPrefixes |= opPrefixes;
} else { } else {
/*
* opLIP is used, among other things, to help string instructions rewind to the first prefix
* byte whenever the instruction needs to be repeated. Repeating string instructions in this
* manner (essentially restarting them) is a bit heavy-handed, but ultimately it's more compatible,
* because it allows hardware interrupts (as well as Trap processing and Debugger single-stepping)
* to occur at any point during the string operation, without any additional effort.
*
* NOTE: The way we restart string instructions actually fixes an 8086/8088 flaw, because string
* instructions with multiple prefixes (eg, a REP and a segment override) would not be restarted
* properly following a hardware interrupt. The recommended workarounds were to either turn off
* interrupts or make sure the REP prefix was first and follow the string instruction with a LOOPNZ
* back to the REP. To emulate this flawed behavior, turn on BUGS_8086.
*/
this.opLIP = this.regLIP; this.opLIP = this.regLIP;
this.regEA = this.regEAWrite = X86.ADDR_INVALID; this.regEA = this.regEAWrite = X86.ADDR_INVALID;
this.segData = this.segDS; this.segData = this.segDS;

View file

@ -48,7 +48,7 @@ var X86Grps = {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = dst + src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = dst + src) & 0xff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -59,7 +59,7 @@ var X86Grps = {
opGrpORb: function(dst, src) { opGrpORb: function(dst, src) {
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xff;
}, },
/** /**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before * NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
@ -72,10 +72,10 @@ var X86Grps = {
*/ */
opGrpADCb: function(dst, src) { opGrpADCb: function(dst, src) {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultValue = this.resultParitySign = dst + src + ((this.resultValue & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultValue & 0xff; return this.resultZeroCarry & 0xff;
}, },
/** /**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before * NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
@ -88,10 +88,10 @@ var X86Grps = {
*/ */
opGrpSBBb: function(dst, src) { opGrpSBBb: function(dst, src) {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultValue = this.resultParitySign = dst - src - ((this.resultValue & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultValue & 0xff; return this.resultZeroCarry & 0xff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -102,7 +102,7 @@ var X86Grps = {
opGrpANDb: function(dst, src) { opGrpANDb: function(dst, src) {
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -114,7 +114,7 @@ var X86Grps = {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = dst - src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = dst - src) & 0xff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -125,7 +125,7 @@ var X86Grps = {
opGrpXORb: function(dst, src) { opGrpXORb: function(dst, src) {
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -136,7 +136,7 @@ var X86Grps = {
opGrpCMPb: function(dst, src) { opGrpCMPb: function(dst, src) {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.resultValue = this.resultParitySign = dst - src; this.resultZeroCarry = this.resultParitySign = dst - src;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
@ -162,14 +162,14 @@ var X86Grps = {
* So, we can use “(dst ^ ((dst ^ src) & (src ^ res))) >>> 15” to shift the calculated carry bit (bit 31) * So, we can use “(dst ^ ((dst ^ src) & (src ^ res))) >>> 15” to shift the calculated carry bit (bit 31)
* into the conventional SIZE_WORD position (bit 16); eg: * into the conventional SIZE_WORD position (bit 16); eg:
* *
* resultValue = ((resultValue >>> 16) | (resultValue & 0xffff)) | (((dst ^ ((dst ^ src) & (src ^ resultValue))) >>> 15) & SIZE_WORD); * resultZeroCarry = ((resultZeroCarry >>> 16) | (resultZeroCarry & 0xffff)) | (((dst ^ ((dst ^ src) & (src ^ resultZeroCarry))) >>> 15) & SIZE_WORD);
* *
* Essentially, we’re “cramming” all 32 result bits into the low 16 bits (which will effectively represent the * Essentially, we’re “cramming” all 32 result bits into the low 16 bits (which will effectively represent the
* zero flag), and then setting bit 16 to the effective carry flag. This transforms the zero and carry conditions * zero flag), and then setting bit 16 to the effective carry flag. This transforms the zero and carry conditions
* for a DWORD computation into the corresponding conditions for a WORD computation. This will slow down 32-bit * for a DWORD computation into the corresponding conditions for a WORD computation. This will slow down 32-bit
* addition, but it allows 8-bit and 16-bit addition to remain fast. Languages that support 64-bit values in * addition, but it allows 8-bit and 16-bit addition to remain fast. Languages that support 64-bit values in
* conjunction with bit-wise operators can omit that one-line transformation, and we can set SIZE_DWORD to a 33-bit * conjunction with bit-wise operators can omit that one-line transformation, allowing us to set SIZE_DWORD to a
* value, but sadly, we cannot do that in JavaScript. * 33-bit value, but sadly, we cannot do that in JavaScript.
* *
* Alternatively, we could store src and dst into their own result variables (eg, resultSrc and resultDst) and * Alternatively, we could store src and dst into their own result variables (eg, resultSrc and resultDst) and
* compute carry lazily, but that would affect MUCH more existing code (eg, all code that currently inspects carry * compute carry lazily, but that would affect MUCH more existing code (eg, all code that currently inspects carry
@ -185,7 +185,7 @@ var X86Grps = {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = dst + src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = dst + src) & 0xffff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -196,7 +196,7 @@ var X86Grps = {
opGrpORw: function(dst, src) { opGrpORw: function(dst, src) {
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xffff;
}, },
/** /**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before * NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
@ -209,10 +209,10 @@ var X86Grps = {
*/ */
opGrpADCw: function(dst, src) { opGrpADCw: function(dst, src) {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultValue = this.resultParitySign = dst + src + ((this.resultValue & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultValue & 0xffff; return this.resultZeroCarry & 0xffff;
}, },
/** /**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before * NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
@ -225,10 +225,10 @@ var X86Grps = {
*/ */
opGrpSBBw: function(dst, src) { opGrpSBBw: function(dst, src) {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultValue = this.resultParitySign = dst - src - ((this.resultValue & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultValue & 0xffff; return this.resultZeroCarry & 0xffff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -239,7 +239,7 @@ var X86Grps = {
opGrpANDw: function(dst, src) { opGrpANDw: function(dst, src) {
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xffff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -251,7 +251,7 @@ var X86Grps = {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = dst - src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = dst - src) & 0xffff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -262,7 +262,7 @@ var X86Grps = {
opGrpXORw: function(dst, src) { opGrpXORw: function(dst, src) {
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xffff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -273,7 +273,7 @@ var X86Grps = {
opGrpCMPw: function(dst, src) { opGrpCMPw: function(dst, src) {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.resultValue = this.resultParitySign = dst - src; this.resultZeroCarry = this.resultParitySign = dst - src;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
@ -319,7 +319,7 @@ var X86Grps = {
* @param {number} size * @param {number} size
*/ */
opGrpRotateFlags: function(result, size) { opGrpRotateFlags: function(result, size) {
this.resultValue = (this.resultValue & (this.resultSize - 1)) | ((result & size)? this.resultSize : 0); this.resultZeroCarry = (this.resultZeroCarry & (this.resultSize - 1)) | ((result & size)? this.resultSize : 0);
if ((result ^ (result >> 1)) & (size >> 1)) this.setOF(); else this.clearOF(); if ((result ^ (result >> 1)) & (size >> 1)) this.setOF(); else this.clearOF();
}, },
/** /**
@ -417,9 +417,9 @@ var X86Grps = {
var temp; var temp;
var shift = (src & this.nShiftCountMask) % 0x9; var shift = (src & this.nShiftCountMask) % 0x9;
if (!shift) { if (!shift) {
temp = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 8); temp = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
} else { } else {
temp = (dst << shift) | (((this.resultValue & this.resultSize)? 1 : 0) << (shift - 1)) | (dst >> (9 - shift)); temp = (dst << shift) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << (shift - 1)) | (dst >> (9 - shift));
result = temp & 0xff; result = temp & 0xff;
} }
X86Grps.opGrpRotateFlags.call(this, temp, X86.RESULT.SIZE_BYTE); X86Grps.opGrpRotateFlags.call(this, temp, X86.RESULT.SIZE_BYTE);
@ -440,9 +440,9 @@ var X86Grps = {
var temp; var temp;
var shift = (src & this.nShiftCountMask) % 0x11; var shift = (src & this.nShiftCountMask) % 0x11;
if (!shift) { if (!shift) {
temp = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 16); temp = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else { } else {
temp = (dst << shift) | (((this.resultValue & this.resultSize)? 1 : 0) << (shift - 1)) | (dst >> (17 - shift)); temp = (dst << shift) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << (shift - 1)) | (dst >> (17 - shift));
result = temp & 0xffff; result = temp & 0xffff;
} }
X86Grps.opGrpRotateFlags.call(this, temp, X86.RESULT.SIZE_WORD); X86Grps.opGrpRotateFlags.call(this, temp, X86.RESULT.SIZE_WORD);
@ -461,7 +461,7 @@ var X86Grps = {
var flagsIn = (DEBUG? this.getPS() : 0); var flagsIn = (DEBUG? this.getPS() : 0);
if (src) { if (src) {
var shift = (src & this.nShiftCountMask) % 0x9; var shift = (src & this.nShiftCountMask) % 0x9;
result = (dst >> shift) | (((this.resultValue & this.resultSize)? 1 : 0) << (8 - shift)) | (dst << (9 - shift)); result = (dst >> shift) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << (8 - shift)) | (dst << (9 - shift));
X86Grps.opGrpRotateFlags.call(this, result, X86.RESULT.SIZE_BYTE); X86Grps.opGrpRotateFlags.call(this, result, X86.RESULT.SIZE_BYTE);
result &= 0xff; result &= 0xff;
} }
@ -479,7 +479,7 @@ var X86Grps = {
var flagsIn = (DEBUG? this.getPS() : 0); var flagsIn = (DEBUG? this.getPS() : 0);
if (src) { if (src) {
var shift = (src & this.nShiftCountMask) % 0x11; var shift = (src & this.nShiftCountMask) % 0x11;
result = (dst >> shift) | (((this.resultValue & this.resultSize)? 1 : 0) << (16 - shift)) | (dst << (17 - shift)); result = (dst >> shift) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << (16 - shift)) | (dst << (17 - shift));
X86Grps.opGrpRotateFlags.call(this, result, X86.RESULT.SIZE_WORD); X86Grps.opGrpRotateFlags.call(this, result, X86.RESULT.SIZE_WORD);
result &= 0xffff; result &= 0xffff;
} }
@ -508,9 +508,9 @@ var X86Grps = {
var flagsIn = (DEBUG? this.getPS() : 0); var flagsIn = (DEBUG? this.getPS() : 0);
if (src) { if (src) {
if (src > 8) // this comparison obviates the need to mask with this.nShiftCountMask if (src > 8) // this comparison obviates the need to mask with this.nShiftCountMask
result = this.resultValue = this.resultParitySign = 0; result = this.resultZeroCarry = this.resultParitySign = 0;
else else
result = (this.resultValue = this.resultParitySign = (dst << src)) & 0xff; result = (this.resultZeroCarry = this.resultParitySign = (dst << src)) & 0xff;
this.resultAuxOverflow = 0; this.resultAuxOverflow = 0;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
} }
@ -533,9 +533,9 @@ var X86Grps = {
var flagsIn = (DEBUG? this.getPS() : 0); var flagsIn = (DEBUG? this.getPS() : 0);
if (src) { if (src) {
if (src > 16) // this comparison obviates the need to mask with this.nShiftCountMask if (src > 16) // this comparison obviates the need to mask with this.nShiftCountMask
result = this.resultValue = this.resultParitySign = 0; result = this.resultZeroCarry = this.resultParitySign = 0;
else else
result = (this.resultValue = this.resultParitySign = (dst << src)) & 0xffff; result = (this.resultZeroCarry = this.resultParitySign = (dst << src)) & 0xffff;
this.resultAuxOverflow = 0; this.resultAuxOverflow = 0;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
} }
@ -556,14 +556,14 @@ var X86Grps = {
opGrpSHRb: function(dst, src) { opGrpSHRb: function(dst, src) {
if (src) { // the following comparison obviates the need to mask with this.nShiftCountMask if (src) { // the following comparison obviates the need to mask with this.nShiftCountMask
var temp = (src > 8? 0 : (dst >> (src - 1))); var temp = (src > 8? 0 : (dst >> (src - 1)));
this.resultValue = this.resultParitySign = temp >> 1; this.resultZeroCarry = this.resultParitySign = temp >> 1;
if (temp & 0x01) if (temp & 0x01)
this.resultValue |= X86.RESULT.SIZE_BYTE; this.resultZeroCarry |= X86.RESULT.SIZE_BYTE;
else else
this.resultValue &= ~X86.RESULT.SIZE_BYTE; this.resultZeroCarry &= ~X86.RESULT.SIZE_BYTE;
this.resultAuxOverflow = dst ^ this.resultValue; this.resultAuxOverflow = dst ^ this.resultZeroCarry;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
dst = this.resultValue; dst = this.resultZeroCarry;
} }
return dst & 0xff; return dst & 0xff;
}, },
@ -581,14 +581,14 @@ var X86Grps = {
opGrpSHRw: function(dst, src) { opGrpSHRw: function(dst, src) {
if (src) { // the following comparison obviates the need to mask with this.nShiftCountMask if (src) { // the following comparison obviates the need to mask with this.nShiftCountMask
var temp = (src > 16? 0 : (dst >> (src - 1))); var temp = (src > 16? 0 : (dst >> (src - 1)));
this.resultValue = this.resultParitySign = temp >> 1; this.resultZeroCarry = this.resultParitySign = temp >> 1;
if (temp & 0x01) if (temp & 0x01)
this.resultValue |= X86.RESULT.SIZE_WORD; this.resultZeroCarry |= X86.RESULT.SIZE_WORD;
else else
this.resultValue &= ~X86.RESULT.SIZE_WORD; this.resultZeroCarry &= ~X86.RESULT.SIZE_WORD;
this.resultAuxOverflow = dst ^ this.resultValue; this.resultAuxOverflow = dst ^ this.resultZeroCarry;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
dst = this.resultValue; dst = this.resultZeroCarry;
} }
return dst & 0xffff; return dst & 0xffff;
}, },
@ -607,14 +607,14 @@ var X86Grps = {
if (src) { if (src) {
if (src > 8) src = 9; // this comparison obviates the need to mask with this.nShiftCountMask if (src > 8) src = 9; // this comparison obviates the need to mask with this.nShiftCountMask
var temp = ((dst << 24) >> 24) >> (src - 1); var temp = ((dst << 24) >> 24) >> (src - 1);
this.resultValue = this.resultParitySign = temp >> 1; this.resultZeroCarry = this.resultParitySign = temp >> 1;
if (temp & 0x01) if (temp & 0x01)
this.resultValue |= X86.RESULT.SIZE_BYTE; this.resultZeroCarry |= X86.RESULT.SIZE_BYTE;
else else
this.resultValue &= ~X86.RESULT.SIZE_BYTE; this.resultZeroCarry &= ~X86.RESULT.SIZE_BYTE;
this.resultAuxOverflow = dst ^ this.resultValue; this.resultAuxOverflow = dst ^ this.resultZeroCarry;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
dst = this.resultValue; dst = this.resultZeroCarry;
} }
return dst & 0xff; return dst & 0xff;
}, },
@ -633,14 +633,14 @@ var X86Grps = {
if (src) { if (src) {
if (src > 16) src = 17; // this comparison obviates the need to mask with this.nShiftCountMask if (src > 16) src = 17; // this comparison obviates the need to mask with this.nShiftCountMask
var temp = ((dst << 16) >> 16) >> (src - 1); var temp = ((dst << 16) >> 16) >> (src - 1);
this.resultValue = this.resultParitySign = temp >> 1; this.resultZeroCarry = this.resultParitySign = temp >> 1;
if (temp & 0x01) if (temp & 0x01)
this.resultValue |= X86.RESULT.SIZE_WORD; this.resultZeroCarry |= X86.RESULT.SIZE_WORD;
else else
this.resultValue &= ~X86.RESULT.SIZE_WORD; this.resultZeroCarry &= ~X86.RESULT.SIZE_WORD;
this.resultAuxOverflow = dst ^ this.resultValue; this.resultAuxOverflow = dst ^ this.resultZeroCarry;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
dst = this.resultValue; dst = this.resultZeroCarry;
} }
return dst & 0xffff; return dst & 0xffff;
}, },
@ -652,7 +652,7 @@ var X86Grps = {
*/ */
opGrpTEST8: function(dst, src) { opGrpTEST8: function(dst, src) {
src = this.getIPByte(); src = this.getIPByte();
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
@ -666,7 +666,7 @@ var X86Grps = {
*/ */
opGrpTEST16: function(dst, src) { opGrpTEST16: function(dst, src) {
src = this.getIPWord(); src = this.getIPWord();
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
@ -703,7 +703,7 @@ var X86Grps = {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM);
return (this.resultValue = this.resultParitySign = src - dst) & 0xff; return (this.resultZeroCarry = this.resultParitySign = src - dst) & 0xff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -716,7 +716,7 @@ var X86Grps = {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM);
return (this.resultValue = this.resultParitySign = src - dst) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = src - dst) & 0xffff;
}, },
/** /**
* @this {X86CPU} * @this {X86CPU}
@ -725,8 +725,8 @@ var X86Grps = {
* @return {number} (we return dst unchanged, since it's actually AX that's modified) * @return {number} (we return dst unchanged, since it's actually AX that's modified)
*/ */
opGrpMULb: function(dst, src) { opGrpMULb: function(dst, src) {
this.regEAX = this.regMD16 = (this.resultValue = (src = this.regEAX & 0xff) * dst) & 0xffff; this.regEAX = this.regMD16 = (this.resultZeroCarry = (src = this.regEAX & 0xff) * dst) & 0xffff;
this.resultAuxOverflow = this.resultParitySign = this.resultValue; this.resultAuxOverflow = this.resultParitySign = this.resultZeroCarry;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
/* /*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works, * TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
@ -770,7 +770,7 @@ var X86Grps = {
opGrpIMULb: function(dst, src) { opGrpIMULb: function(dst, src) {
var result = (((src = this.regEAX) << 24) >> 24) * ((dst << 24) >> 24); var result = (((src = this.regEAX) << 24) >> 24) * ((dst << 24) >> 24);
this.regEAX = this.regMD16 = result & 0xffff; this.regEAX = this.regMD16 = result & 0xffff;
this.resultValue = this.resultAuxOverflow = this.resultParitySign = result; this.resultZeroCarry = this.resultAuxOverflow = this.resultParitySign = result;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
/* /*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works, * TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
@ -818,7 +818,7 @@ var X86Grps = {
/* /*
* TODO: Verify that all of the arithmetic flags are "undefined" after DIV, and that this code unnecessary * TODO: Verify that all of the arithmetic flags are "undefined" after DIV, and that this code unnecessary
*/ */
this.resultParitySign = this.resultAuxOverflow = (this.resultValue = uQuotient | X86.RESULT.SIZE_BYTE); this.resultParitySign = this.resultAuxOverflow = (this.resultZeroCarry = uQuotient | X86.RESULT.SIZE_BYTE);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
/* /*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us * Multiply/divide instructions specify only a single operand, which the decoders pass to us
@ -865,7 +865,7 @@ var X86Grps = {
/* /*
* TODO: Verify that all of the arithmetic flags are "undefined" after IDIV, and that this code unnecessary * TODO: Verify that all of the arithmetic flags are "undefined" after IDIV, and that this code unnecessary
*/ */
this.resultParitySign = this.resultAuxOverflow = (this.resultValue = lQuotient | X86.RESULT.SIZE_BYTE); this.resultParitySign = this.resultAuxOverflow = (this.resultZeroCarry = lQuotient | X86.RESULT.SIZE_BYTE);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
/* /*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us * Multiply/divide instructions specify only a single operand, which the decoders pass to us
@ -885,9 +885,9 @@ var X86Grps = {
* @return {number} (we return dst unchanged, since it's actually DX:AX that's modified) * @return {number} (we return dst unchanged, since it's actually DX:AX that's modified)
*/ */
opGrpMULw: function(dst, src) { opGrpMULw: function(dst, src) {
this.regMD16 = this.regEAX = (this.resultValue = (src = this.regEAX) * dst) & 0xffff; this.regMD16 = this.regEAX = (this.resultZeroCarry = (src = this.regEAX) * dst) & 0xffff;
this.regMD32 = this.regEDX = (this.resultValue >> 16) & 0xffff; this.regMD32 = this.regEDX = (this.resultZeroCarry >> 16) & 0xffff;
this.resultAuxOverflow = this.resultParitySign = this.resultValue; this.resultAuxOverflow = this.resultParitySign = this.resultZeroCarry;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
/* /*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works, * TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
@ -932,7 +932,7 @@ var X86Grps = {
var result = (((src = this.regEAX) << 16) >> 16) * ((dst << 16) >> 16); var result = (((src = this.regEAX) << 16) >> 16) * ((dst << 16) >> 16);
this.regEAX = this.regMD16 = result & 0xffff; this.regEAX = this.regMD16 = result & 0xffff;
this.regEDX = this.regMD32 = (result >> 16) & 0xffff; this.regEDX = this.regMD32 = (result >> 16) & 0xffff;
this.resultValue = this.resultAuxOverflow = this.resultParitySign = result; this.resultZeroCarry = this.resultAuxOverflow = this.resultParitySign = result;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
/* /*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works, * TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
@ -986,7 +986,7 @@ var X86Grps = {
/* /*
* TODO: Verify that all of the arithmetic flags are "undefined" after DIV, and that this code unnecessary * TODO: Verify that all of the arithmetic flags are "undefined" after DIV, and that this code unnecessary
*/ */
this.resultParitySign = this.resultAuxOverflow = (this.resultValue = uQuotient | X86.RESULT.SIZE_WORD); this.resultParitySign = this.resultAuxOverflow = (this.resultZeroCarry = uQuotient | X86.RESULT.SIZE_WORD);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
/* /*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us * Multiply/divide instructions specify only a single operand, which the decoders pass to us
@ -1036,7 +1036,7 @@ var X86Grps = {
/* /*
* TODO: Verify that all of the arithmetic flags are "undefined" after IDIV, and that this code unnecessary * TODO: Verify that all of the arithmetic flags are "undefined" after IDIV, and that this code unnecessary
*/ */
this.resultParitySign = this.resultAuxOverflow = (this.resultValue = lQuotient | X86.RESULT.SIZE_WORD); this.resultParitySign = this.resultAuxOverflow = (this.resultZeroCarry = lQuotient | X86.RESULT.SIZE_WORD);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
/* /*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us * Multiply/divide instructions specify only a single operand, which the decoders pass to us
@ -1058,7 +1058,7 @@ var X86Grps = {
opGrpINCb: function(dst, src) { opGrpINCb: function(dst, src) {
this.resultAuxOverflow = dst; this.resultAuxOverflow = dst;
dst = (this.resultParitySign = dst + 1) & 0xff; dst = (this.resultParitySign = dst + 1) & 0xff;
this.resultValue = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 8); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;
@ -1072,7 +1072,7 @@ var X86Grps = {
opGrpDECb: function(dst, src) { opGrpDECb: function(dst, src) {
this.resultAuxOverflow = dst; this.resultAuxOverflow = dst;
dst = (this.resultParitySign = dst - 1) & 0xff; dst = (this.resultParitySign = dst - 1) & 0xff;
this.resultValue = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 8); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;
@ -1086,7 +1086,7 @@ var X86Grps = {
opGrpINCw: function(dst, src) { opGrpINCw: function(dst, src) {
this.resultAuxOverflow = dst; this.resultAuxOverflow = dst;
dst = (this.resultParitySign = dst + 1) & 0xffff; dst = (this.resultParitySign = dst + 1) & 0xffff;
this.resultValue = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;
@ -1100,7 +1100,7 @@ var X86Grps = {
opGrpDECw: function(dst, src) { opGrpDECw: function(dst, src) {
this.resultAuxOverflow = dst; this.resultAuxOverflow = dst;
dst = (this.resultParitySign = dst - 1) & 0xffff; dst = (this.resultParitySign = dst - 1) & 0xffff;
this.resultValue = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;

View file

@ -64,7 +64,7 @@ var X86Help = {
* @return {number} * @return {number}
*/ */
opHelpTESTb: function(dst, src) { opHelpTESTb: function(dst, src) {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
@ -77,7 +77,7 @@ var X86Help = {
* @return {number} * @return {number}
*/ */
opHelpTESTw: function(dst, src) { opHelpTESTw: function(dst, src) {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM); this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
@ -100,7 +100,7 @@ var X86Help = {
*/ */
opHelpIMUL8: function(dst, src) { opHelpIMUL8: function(dst, src) {
var result = ((src << 16) >> 16) * ((this.getIPByte() << 24) >> 24); var result = ((src << 16) >> 16) * ((this.getIPByte() << 24) >> 24);
this.resultValue = this.resultAuxOverflow = this.resultParitySign = result; this.resultZeroCarry = this.resultAuxOverflow = this.resultParitySign = result;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
/* /*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works, * TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
@ -138,7 +138,7 @@ var X86Help = {
*/ */
opHelpIMUL16: function(dst, src) { opHelpIMUL16: function(dst, src) {
var result = ((src << 16) >> 16) * ((this.getIPWord() << 16) >> 16); var result = ((src << 16) >> 16) * ((this.getIPWord() << 16) >> 16);
this.resultValue = this.resultAuxOverflow = this.resultParitySign = result; this.resultZeroCarry = this.resultAuxOverflow = this.resultParitySign = result;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
/* /*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works, * TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,

View file

@ -88,9 +88,8 @@ var X86OpXX = {
opADDALb: function() { opADDALb: function() {
this.regEAX = (this.regEAX & ~0xff) | X86Grps.opGrpADDb.call(this, this.regEAX & 0xff, this.getIPByte()); this.regEAX = (this.regEAX & ~0xff) | X86Grps.opGrpADDb.call(this, this.regEAX & 0xff, this.getIPByte());
/* /*
* BACKTRACK note: I'm going to say this just once, even though it applies to MANY instructions. The * NOTE: Whenever the result is "blended" value (eg, of btiAL and btiMemLo), a new bti should be
* result is a blending of btiAL and btiMemLo, so technically, a new bti should be allocated to reflect * allocated to reflect that fact; however, I'm leaving "perfect" BACKTRACK support for another day.
* that fact; however, I'm leaving perfect BACKTRACKing for another day.
*/ */
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiMemLo; if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiMemLo;
/* /*
@ -465,7 +464,7 @@ var X86OpXX = {
opDAA: function() { opDAA: function() {
var AL = this.regEAX & 0xff; var AL = this.regEAX & 0xff;
var fAuxCarry = this.getAF(); var fAuxCarry = this.getAF();
var fCarry = (this.resultValue & this.resultSize); var fCarry = (this.resultZeroCarry & this.resultSize);
if ((AL & 0xf) > 9 || fAuxCarry) { if ((AL & 0xf) > 9 || fAuxCarry) {
AL += 0x6; AL += 0x6;
fAuxCarry = true; fAuxCarry = true;
@ -474,9 +473,9 @@ var X86OpXX = {
AL += 0x60; AL += 0x60;
fCarry = true; fCarry = true;
} }
this.regEAX = (this.regEAX & ~0xff) | (this.resultValue = this.resultParitySign = (AL & 0xff)); this.regEAX = (this.regEAX & ~0xff) | (this.resultZeroCarry = this.resultParitySign = (AL & 0xff));
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
if (fCarry) this.resultValue |= this.resultSize; if (fCarry) this.resultZeroCarry |= this.resultSize;
if (fAuxCarry) this.setAF(); else this.clearAF(); if (fAuxCarry) this.setAF(); else this.clearAF();
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAA have the same cycle times this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAA have the same cycle times
}, },
@ -564,7 +563,7 @@ var X86OpXX = {
opDAS: function() { opDAS: function() {
var AL = this.regEAX & 0xff; var AL = this.regEAX & 0xff;
var fAuxCarry = this.getAF(); var fAuxCarry = this.getAF();
var fCarry = (this.resultValue & this.resultSize); var fCarry = (this.resultZeroCarry & this.resultSize);
if ((AL & 0xf) > 9 || fAuxCarry) { if ((AL & 0xf) > 9 || fAuxCarry) {
AL -= 0x6; AL -= 0x6;
fAuxCarry = true; fAuxCarry = true;
@ -573,9 +572,9 @@ var X86OpXX = {
AL -= 0x60; AL -= 0x60;
fCarry = true; fCarry = true;
} }
this.regEAX = (this.regEAX & ~0xff) | (this.resultValue = this.resultParitySign = (AL & 0xff)); this.regEAX = (this.regEAX & ~0xff) | (this.resultZeroCarry = this.resultParitySign = (AL & 0xff));
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
if (fCarry) this.resultValue |= this.resultSize; if (fCarry) this.resultZeroCarry |= this.resultSize;
if (fAuxCarry) this.setAF(); else this.clearAF(); if (fAuxCarry) this.setAF(); else this.clearAF();
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAS have the same cycle times this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAS have the same cycle times
}, },
@ -672,9 +671,9 @@ var X86OpXX = {
} else { } else {
fCarry = fAuxCarry = false; fCarry = fAuxCarry = false;
} }
this.regEAX = (this.regEAX & ~0xffff) | (AH << 8) | (this.resultValue = AL); this.regEAX = (this.regEAX & ~0xffff) | (AH << 8) | (this.resultZeroCarry = AL);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
if (fCarry) this.resultValue |= this.resultSize; if (fCarry) this.resultZeroCarry |= this.resultSize;
if (fAuxCarry) this.setAF(); else this.clearAF(); if (fAuxCarry) this.setAF(); else this.clearAF();
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; this.nStepCycles -= this.CYCLES.nOpCyclesAAA;
}, },
@ -774,11 +773,11 @@ var X86OpXX = {
} else { } else {
fCarry = fAuxCarry = false; fCarry = fAuxCarry = false;
} }
this.regEAX = (this.regEAX & ~0xffff) | (AH << 8) | (this.resultValue = AL); this.regEAX = (this.regEAX & ~0xffff) | (AH << 8) | (this.resultZeroCarry = AL);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
if (fCarry) this.resultValue |= this.resultSize; if (fCarry) this.resultZeroCarry |= this.resultSize;
if (fAuxCarry) this.setAF(); else this.clearAF(); if (fAuxCarry) this.setAF(); else this.clearAF();
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and AAS have the same cycle times this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and AAS have the same cycle times
}, },
/** /**
* op=0x40 (INC AX) * op=0x40 (INC AX)
@ -786,9 +785,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCAX: function() { opINCAX: function() {
this.resultAuxOverflow = this.regEAX; this.resultParitySign = (this.resultAuxOverflow = this.regEAX) + 1;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign = this.regEAX + 1) & this.dataMask; if (I386) {
this.resultValue = this.regEAX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEAX) & this.dataMask) >>> 16) | (this.regEAX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEAX = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEAX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -798,9 +802,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCCX: function() { opINCCX: function() {
this.resultAuxOverflow = this.regECX; this.resultParitySign = (this.resultAuxOverflow = this.regECX) + 1;
this.regECX = (this.regECX & ~this.dataMask) | (this.resultParitySign = this.regECX + 1) & this.dataMask; if (I386) {
this.resultValue = this.regECX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regECX = (this.regECX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regECX) & this.dataMask) >>> 16) | (this.regECX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regECX = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regECX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -810,9 +819,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCDX: function() { opINCDX: function() {
this.resultAuxOverflow = this.regEDX; this.resultParitySign = (this.resultAuxOverflow = this.regEDX) + 1;
this.regEDX = (this.regEDX & ~this.dataMask) | (this.resultParitySign = this.regEDX + 1) & this.dataMask; if (I386) {
this.resultValue = this.regEDX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEDX = (this.regEDX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEDX) & this.dataMask) >>> 16) | (this.regEDX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEDX = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEDX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -822,9 +836,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCBX: function() { opINCBX: function() {
this.resultAuxOverflow = this.regEBX; this.resultParitySign = (this.resultAuxOverflow = this.regEBX) + 1;
this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign = this.regEBX + 1) & this.dataMask; if (I386) {
this.resultValue = this.regEBX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEBX) & this.dataMask) >>> 16) | (this.regEBX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEBX = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEBX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -834,9 +853,10 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCSP: function() { opINCSP: function() {
this.resultAuxOverflow = this.getSP(); var regESP;
this.setSP((this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign = this.resultAuxOverflow + 1) & this.dataMask); this.resultParitySign = (this.resultAuxOverflow = this.getSP()) + 1;
this.resultValue = this.getSP() | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.setSP(regESP = (this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign & this.dataMask));
this.resultZeroCarry = (((regESP) & this.dataMask) >>> 16) | (regESP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -846,9 +866,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCBP: function() { opINCBP: function() {
this.resultAuxOverflow = this.regEBP; this.resultParitySign = (this.resultAuxOverflow = this.regEBP) + 1;
this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign = this.regEBP + 1) & this.dataMask; if (I386) {
this.resultValue = this.regEBP | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEBP) & this.dataMask) >>> 16) | (this.regEBP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEBP = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEBP | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -858,9 +883,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCSI: function() { opINCSI: function() {
this.resultAuxOverflow = this.regESI; this.resultParitySign = (this.resultAuxOverflow = this.regESI) + 1;
this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign = this.regESI + 1) & this.dataMask; if (I386) {
this.resultValue = this.regESI | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regESI) & this.dataMask) >>> 16) | (this.regESI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regESI = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regESI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -870,9 +900,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opINCDI: function() { opINCDI: function() {
this.resultAuxOverflow = this.regEDI; this.resultParitySign = (this.resultAuxOverflow = this.regEDI) + 1;
this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign = this.regEDI + 1) & this.dataMask; if (I386) {
this.resultValue = this.regEDI | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEDI) & this.dataMask) >>> 16) | (this.regEDI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEDI = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEDI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
}, },
@ -882,9 +917,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECAX: function() { opDECAX: function() {
this.resultAuxOverflow = this.regEAX; this.resultParitySign = (this.resultAuxOverflow = this.regEAX) - 1;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign = this.regEAX - 1) & this.dataMask; if (I386) {
this.resultValue = this.regEAX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEAX) & this.dataMask) >>> 16) | (this.regEAX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEAX = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEAX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
@ -894,9 +934,9 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECCX: function() { opDECCX: function() {
this.resultAuxOverflow = this.regECX; this.resultParitySign = (this.resultAuxOverflow = this.regECX) - 1;
this.regECX = (this.regECX & ~this.dataMask) | (this.resultParitySign = this.regECX - 1) & this.dataMask; this.regECX = (I386? (this.regECX & ~this.dataMask) | (this.resultParitySign & this.dataMask) : this.resultParitySign & 0xffff);
this.resultValue = this.regECX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.resultZeroCarry = this.regECX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
@ -906,9 +946,9 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECDX: function() { opDECDX: function() {
this.resultAuxOverflow = this.regEDX; this.resultParitySign = (this.resultAuxOverflow = this.regEDX) - 1;
this.regEDX = (this.regEDX & ~this.dataMask) | (this.resultParitySign = this.regEDX - 1) & this.dataMask; this.regEDX = (I386? (this.regEDX & ~this.dataMask) | (this.resultParitySign & this.dataMask) : this.resultParitySign & 0xffff);
this.resultValue = this.regEDX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.resultZeroCarry = this.regEDX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
@ -918,9 +958,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECBX: function() { opDECBX: function() {
this.resultAuxOverflow = this.regEBX; this.resultParitySign = (this.resultAuxOverflow = this.regEBX) - 1;
this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign = this.regEBX - 1) & this.dataMask; if (I386) {
this.resultValue = this.regEBX | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEBX) & this.dataMask) >>> 16) | (this.regEBX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEBX = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEBX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
@ -930,9 +975,10 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECSP: function() { opDECSP: function() {
this.resultAuxOverflow = this.getSP(); var regESP;
this.setSP((this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign = this.resultAuxOverflow - 1) & this.dataMask); this.resultParitySign = (this.resultAuxOverflow = this.getSP()) - 1;
this.resultValue = this.getSP() | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.setSP(regESP = (this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign & this.dataMask));
this.resultZeroCarry = (((regESP) & this.dataMask) >>> 16) | (regESP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
@ -942,9 +988,14 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECBP: function() { opDECBP: function() {
this.resultAuxOverflow = this.regEBP; this.resultParitySign = (this.resultAuxOverflow = this.regEBP) - 1;
this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign = this.regEBP - 1) & this.dataMask; if (I386) {
this.resultValue = this.regEBP | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEBP) & this.dataMask) >>> 16) | (this.regEBP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEBP = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEBP | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
@ -954,21 +1005,31 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECSI: function() { opDECSI: function() {
this.resultAuxOverflow = this.regESI; this.resultParitySign = (this.resultAuxOverflow = this.regESI) - 1;
this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign = this.regESI - 1) & this.dataMask; if (I386) {
this.resultValue = this.regESI | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regESI) & this.dataMask) >>> 16) | (this.regESI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regESI = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regESI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
/** /**`
* op=0x4F (DEC DI) * op=0x4F (DEC DI)
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opDECDI: function() { opDECDI: function() {
this.resultAuxOverflow = this.regEDI; this.resultParitySign = (this.resultAuxOverflow = this.regEDI) - 1;
this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign = this.regEDI - 1) & this.dataMask; if (I386) {
this.resultValue = this.regEDI | (((this.resultValue & this.resultSize)? 1 : 0) << 16); this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
this.resultZeroCarry = (((this.regEDI) & this.dataMask) >>> 16) | (this.regEDI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
} else {
this.regEDI = this.resultParitySign & 0xffff;
this.resultZeroCarry = this.regEDI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
}
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
}, },
@ -1337,8 +1398,6 @@ var X86OpXX = {
* op=0x6C (INSB) (80186/80188 and up) * op=0x6C (INSB) (80186/80188 and up)
* *
* NOTE: Segment overrides are ignored for this instruction, so we must use segES instead of segData. * NOTE: Segment overrides are ignored for this instruction, so we must use segES instead of segData.
* In fact, this is a good thing, because otherwise we would need a separate internal register to track
* the effect of segment overrides on ES (eg, segExtra), because segData tracks overrides for DS only.
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
@ -1370,13 +1429,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -1385,8 +1443,6 @@ var X86OpXX = {
* op=0x6D (INSW) (80186/80188 and up) * op=0x6D (INSW) (80186/80188 and up)
* *
* NOTE: Segment overrides are ignored for this instruction, so we must use segDS instead of segData. * NOTE: Segment overrides are ignored for this instruction, so we must use segDS instead of segData.
* In fact, this is a good thing, because otherwise we would need a separate internal register to track
* the effect of segment overrides on ES (eg, segExtra), because segData tracks overrides for DS only.
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
@ -1420,13 +1476,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -1465,13 +1520,12 @@ var X86OpXX = {
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemLo; if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemLo;
this.bus.checkPortOutputNotify(this.regEDX, b, this.regLIP - nDelta - 1); this.bus.checkPortOutputNotify(this.regEDX, b, this.regLIP - nDelta - 1);
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -1513,13 +1567,12 @@ var X86OpXX = {
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemHi; if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemHi;
this.bus.checkPortOutputNotify(this.regEDX, w >> 8, addrFrom); this.bus.checkPortOutputNotify(this.regEDX, w >> 8, addrFrom);
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2030,8 +2083,8 @@ var X86OpXX = {
*/ */
opXCHGCX: function() { opXCHGCX: function() {
var temp = this.regEAX; var temp = this.regEAX;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regECX & this.dataMask); this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regECX & this.dataMask) : this.regECX);
this.regECX = (this.regECX & ~this.dataMask) | (temp & this.dataMask); this.regECX = (I386? (this.regECX & ~this.dataMask) | (temp & this.dataMask) : temp);
if (BACKTRACK) { if (BACKTRACK) {
temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiCL; this.backTrack.btiCL = temp; temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiCL; this.backTrack.btiCL = temp;
temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiCH; this.backTrack.btiCH = temp; temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiCH; this.backTrack.btiCH = temp;
@ -2045,8 +2098,8 @@ var X86OpXX = {
*/ */
opXCHGDX: function() { opXCHGDX: function() {
var temp = this.regEAX; var temp = this.regEAX;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEDX & this.dataMask); this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEDX & this.dataMask) : this.regEDX);
this.regEDX = (this.regEDX & ~this.dataMask) | (temp & this.dataMask); this.regEDX = (I386? (this.regEDX & ~this.dataMask) | (temp & this.dataMask) : temp);
if (BACKTRACK) { if (BACKTRACK) {
temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiDL; this.backTrack.btiDL = temp; temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiDL; this.backTrack.btiDL = temp;
temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiDH; this.backTrack.btiDH = temp; temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiDH; this.backTrack.btiDH = temp;
@ -2060,8 +2113,8 @@ var X86OpXX = {
*/ */
opXCHGBX: function() { opXCHGBX: function() {
var temp = this.regEAX; var temp = this.regEAX;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEBX & this.dataMask); this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEBX & this.dataMask) : this.regEBX);
this.regEBX = (this.regEBX & ~this.dataMask) | (temp & this.dataMask); this.regEBX = (I386? (this.regEBX & ~this.dataMask) | (temp & this.dataMask) : temp);
if (BACKTRACK) { if (BACKTRACK) {
temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiBL; this.backTrack.btiBL = temp; temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiBL; this.backTrack.btiBL = temp;
temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiBH; this.backTrack.btiBH = temp; temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiBH; this.backTrack.btiBH = temp;
@ -2076,8 +2129,8 @@ var X86OpXX = {
opXCHGSP: function() { opXCHGSP: function() {
var temp = this.regEAX; var temp = this.regEAX;
var regESP = this.getSP(); var regESP = this.getSP();
this.regEAX = (this.regEAX & ~this.dataMask) | (regESP & this.dataMask); this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (regESP & this.dataMask) : regESP);
this.setSP((regESP & ~this.dataMask) | (temp & this.dataMask)); this.setSP((I386? (regESP & ~this.dataMask) | (temp & this.dataMask) : temp));
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiAH = 0; if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiAH = 0;
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
}, },
@ -2088,8 +2141,8 @@ var X86OpXX = {
*/ */
opXCHGBP: function() { opXCHGBP: function() {
var temp = this.regEAX; var temp = this.regEAX;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEBP & this.dataMask); this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEBP & this.dataMask) : this.regEBP);
this.regEBP = (this.regEBP & ~this.dataMask) | (temp & this.dataMask); this.regEBP = (I386? (this.regEBP & ~this.dataMask) | (temp & this.dataMask) : temp);
if (BACKTRACK) { if (BACKTRACK) {
temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiBPLo; this.backTrack.btiBPLo = temp; temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiBPLo; this.backTrack.btiBPLo = temp;
temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiBPHi; this.backTrack.btiBPHi = temp; temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiBPHi; this.backTrack.btiBPHi = temp;
@ -2103,8 +2156,8 @@ var X86OpXX = {
*/ */
opXCHGSI: function() { opXCHGSI: function() {
var temp = this.regEAX; var temp = this.regEAX;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regESI & this.dataMask); this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regESI & this.dataMask) : this.regESI);
this.regESI = (this.regESI & ~this.dataMask) | (temp & this.dataMask); this.regESI = (I386? (this.regESI & ~this.dataMask) | (temp & this.dataMask) : temp);
if (BACKTRACK) { if (BACKTRACK) {
temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiSILo; this.backTrack.btiSILo = temp; temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiSILo; this.backTrack.btiSILo = temp;
temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiSIHi; this.backTrack.btiSIHi = temp; temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiSIHi; this.backTrack.btiSIHi = temp;
@ -2118,8 +2171,8 @@ var X86OpXX = {
*/ */
opXCHGDI: function() { opXCHGDI: function() {
var temp = this.regEAX; var temp = this.regEAX;
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEDI & this.dataMask); this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEDI & this.dataMask) : this.regEDI);
this.regEDI = (this.regEDI & ~this.dataMask) | (temp & this.dataMask); this.regEDI = (I386? (this.regEDI & ~this.dataMask) | (temp & this.dataMask) : temp);
if (BACKTRACK) { if (BACKTRACK) {
temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiDILo; this.backTrack.btiDILo = temp; temp = this.backTrack.btiAL; this.backTrack.btiAL = this.backTrack.btiDILo; this.backTrack.btiDILo = temp;
temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiDIHi; this.backTrack.btiDIHi = temp; temp = this.backTrack.btiAH; this.backTrack.btiAH = this.backTrack.btiDIHi; this.backTrack.btiDIHi = temp;
@ -2317,17 +2370,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
* this.regLIP = this.opLIP;
* TODO: Decide what to do about string instructions with multiple (ie, redundant) }
* SEG prefixes, and whether we should strictly emulate the 8086's failure to restart
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2355,17 +2403,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
* this.regLIP = this.opLIP;
* TODO: Decide what to do about string instructions with multiple (ie, redundant) }
* SEG prefixes, and whether we should strictly emulate the 8086's failure to restart
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2403,17 +2446,12 @@ var X86OpXX = {
* two values are equal, we must continue. * two values are equal, we must continue.
*/ */
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) { if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
* this.regLIP = this.opLIP;
* TODO: Decide what to do about string instructions with multiple (ie, redundant) }
* SEG prefixes, and whether we should strictly emulate the 8086's failure to restart
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2451,17 +2489,12 @@ var X86OpXX = {
* two values are equal, we must continue. * two values are equal, we must continue.
*/ */
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) { if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
* this.regLIP = this.opLIP;
* TODO: Decide what to do about string instructions with multiple (ie, redundant) }
* SEG prefixes, and whether we should strictly emulate the 8086's failure to restart
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2472,7 +2505,7 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opTESTALb: function() { opTESTALb: function() {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = this.regEAX & this.getIPByte(); this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = this.regEAX & this.getIPByte();
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; this.nStepCycles -= this.CYCLES.nOpCyclesAAA;
}, },
@ -2482,7 +2515,7 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opTESTAXw: function() { opTESTAXw: function() {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = this.regEAX & this.getIPWord(); this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = this.regEAX & this.getIPWord();
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; this.nStepCycles -= this.CYCLES.nOpCyclesAAA;
}, },
@ -2490,8 +2523,6 @@ var X86OpXX = {
* op=0xAA (STOSB) * op=0xAA (STOSB)
* *
* NOTES: Segment overrides are ignored for this instruction, so we must use segES instead of segData. * NOTES: Segment overrides are ignored for this instruction, so we must use segES instead of segData.
* In fact, this is a good thing, because otherwise we would need a separate internal register to track
* the effect of segment overrides on ES (eg, segExtra), because segData tracks overrides for DS only.
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
@ -2515,13 +2546,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2530,8 +2560,6 @@ var X86OpXX = {
* op=0xAB (STOSW) * op=0xAB (STOSW)
* *
* NOTES: Segment overrides are ignored for this instruction, so we must use segES instead of segData. * NOTES: Segment overrides are ignored for this instruction, so we must use segES instead of segData.
* In fact, this is a good thing, because otherwise we would need a separate internal register to track
* the effect of segment overrides on ES (eg, segExtra), because segData tracks overrides for DS only.
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
@ -2558,13 +2586,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2591,17 +2618,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
* this.regLIP = this.opLIP;
* TODO: Decide what to do about string instructions with multiple (ie, redundant) }
* SEG prefixes, and whether we should strictly emulate the 8086's failure to restart
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2630,17 +2652,12 @@ var X86OpXX = {
this.nStepCycles -= nCycles; this.nStepCycles -= nCycles;
this.regECX -= nDelta; this.regECX -= nDelta;
if (nReps) { if (nReps) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
* this.regLIP = this.opLIP;
* TODO: Decide what to do about string instructions with multiple (ie, redundant) }
* SEG prefixes, and whether we should strictly emulate the 8086's failure to restart
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2674,13 +2691,12 @@ var X86OpXX = {
* two values are equal, we must continue. * two values are equal, we must continue.
*/ */
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) { if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -2714,13 +2730,12 @@ var X86OpXX = {
* two values are equal, we must continue. * two values are equal, we must continue.
*/ */
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) { if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
/* if (BUGS_8086) {
* We have to back up to the prefix byte(s), not just to the string instruction, this.advanceIP(-2); // this instruction does not support segment overrides
* because if a h/w interrupt is acknowledged before the next repetition begins, this.assert(this.regLIP == this.opLIP);
* the interrupt handler will return us to an invalid state. } else {
*/ this.regLIP = this.opLIP;
this.advanceIP(-2); // this instruction does not support segment overrides }
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT; this.opFlags |= X86.OPFLAG.REPEAT;
} }
} }
@ -3151,7 +3166,7 @@ var X86OpXX = {
var bRemainder = AL % bDivisor; var bRemainder = AL % bDivisor;
this.regEAX = (bQuotient << 8) | bRemainder; this.regEAX = (bQuotient << 8) | bRemainder;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.resultValue = this.resultParitySign = AL; this.resultZeroCarry = this.resultParitySign = AL;
this.nStepCycles -= this.CYCLES.nOpCyclesAAM; this.nStepCycles -= this.CYCLES.nOpCyclesAAM;
}, },
/** /**
@ -3172,7 +3187,7 @@ var X86OpXX = {
*/ */
opAAD: function() { opAAD: function() {
var bMultiplier = this.getIPByte(); var bMultiplier = this.getIPByte();
this.resultValue = this.resultParitySign = this.regEAX = (((this.regEAX >> 8) * bMultiplier) + this.regEAX) & 0xff; this.resultZeroCarry = this.resultParitySign = this.regEAX = (((this.regEAX >> 8) * bMultiplier) + this.regEAX) & 0xff;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= this.CYCLES.nOpCyclesAAD; this.nStepCycles -= this.CYCLES.nOpCyclesAAD;
}, },
@ -3218,7 +3233,7 @@ var X86OpXX = {
*/ */
opLOOPNZ: function() { opLOOPNZ: function() {
var disp = this.getIPDisp(); var disp = this.getIPDisp();
if ((this.regECX = (this.regECX - 1) & this.addrMask) && (this.resultValue & (this.resultSize - 1))) { if ((this.regECX = (this.regECX - 1) & this.addrMask) && (this.resultZeroCarry & (this.resultSize - 1))) {
this.setIP(this.getIP() + disp); this.setIP(this.getIP() + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesLoopNZ; this.nStepCycles -= this.CYCLES.nOpCyclesLoopNZ;
return; return;
@ -3232,7 +3247,7 @@ var X86OpXX = {
*/ */
opLOOPZ: function() { opLOOPZ: function() {
var disp = this.getIPDisp(); var disp = this.getIPDisp();
if ((this.regECX = (this.regECX - 1) & this.addrMask) && !(this.resultValue & (this.resultSize - 1))) { if ((this.regECX = (this.regECX - 1) & this.addrMask) && !(this.resultZeroCarry & (this.resultSize - 1))) {
this.setIP(this.getIP() + disp); this.setIP(this.getIP() + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesLoopZ; this.nStepCycles -= this.CYCLES.nOpCyclesLoopZ;
return; return;
@ -3544,7 +3559,7 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opCLC: function() { opCLC: function() {
this.resultValue &= ~this.resultSize; this.resultZeroCarry &= ~this.resultSize;
this.nStepCycles -= 2; // CLC takes 2 cycles on all CPUs this.nStepCycles -= 2; // CLC takes 2 cycles on all CPUs
}, },
/** /**
@ -3553,7 +3568,7 @@ var X86OpXX = {
* @this {X86CPU} * @this {X86CPU}
*/ */
opSTC: function() { opSTC: function() {
this.resultValue |= this.resultSize; this.resultZeroCarry |= this.resultSize;
this.nStepCycles -= 2; // STC takes 2 cycles on all CPUs this.nStepCycles -= 2; // STC takes 2 cycles on all CPUs
}, },
/** /**

View file

@ -1,5 +1,5 @@
/** /**
* @fileoverview Implements PCjs X86 Segment objects * @fileoverview Implements PCjs X86 Segment Registers
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a> * @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
* @version 1.0 * @version 1.0
* Created 2014-Sep-10 * Created 2014-Sep-10
@ -45,7 +45,7 @@ if (typeof module !== 'undefined') {
* @constructor * @constructor
* @param {X86CPU} cpu * @param {X86CPU} cpu
* @param {number} id * @param {number} id
* @param {string} [sName] segment name * @param {string} [sName] segment register name
* @param {boolean} [fProt] true if segment register used exclusively in protected-mode (eg, segLDT) * @param {boolean} [fProt] true if segment register used exclusively in protected-mode (eg, segLDT)
*/ */
function X86Seg(cpu, id, sName, fProt) function X86Seg(cpu, id, sName, fProt)
@ -81,12 +81,17 @@ function X86Seg(cpu, id, sName, fProt)
* As long as setCSIP() or opHelpINT() are used for all CS changes, fCall is set automatically. * As long as setCSIP() or opHelpINT() are used for all CS changes, fCall is set automatically.
* *
* TODO: Consider making fCall a parameter to load(), instead of a property that must be set prior to * TODO: Consider making fCall a parameter to load(), instead of a property that must be set prior to
* calling load(); the downside (and why I didn't do that in the first place) is that such a parameter * calling load(); the downside is that such a parameter is meaningless for segments other than segCS.
* is meaningless for segments other than segCS.
*/ */
this.awParms = (this.id == X86Seg.ID.CODE? new Array(32) : []); this.awParms = (this.id == X86Seg.ID.CODE? new Array(32) : []);
this.fCall = null; this.fCall = null;
this.fStackSwitch = false; this.fStackSwitch = false;
/*
* The following properties are used for STACK segments only (ie, segSS); we want to make it easier
* for setSS() to set stack lower and upper limits, which requires knowing whether or not the segment is
* marked as EXPDOWN.
*/
this.fExpDown = false;
this.updateMode(fProt); this.updateMode(fProt);
} }
@ -117,6 +122,7 @@ X86Seg.ID = {
*/ */
X86Seg.loadReal = function loadReal(sel, fSuppress) X86Seg.loadReal = function loadReal(sel, fSuppress)
{ {
this.cpu.assert(!(sel & ~0xffff));
this.sel = sel; this.sel = sel;
this.dataSize = this.addrSize = 2; this.dataSize = this.addrSize = 2;
this.dataMask = this.addrMask = 0xffff; this.dataMask = this.addrMask = 0xffff;
@ -152,6 +158,8 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
var addrDTLimit; var addrDTLimit;
var cpu = this.cpu; var cpu = this.cpu;
this.cpu.assert(!(sel & ~0xffff));
if (!(sel & X86.SEL.LDT)) { if (!(sel & X86.SEL.LDT)) {
addrDT = cpu.addrGDT; addrDT = cpu.addrGDT;
addrDTLimit = cpu.addrGDTLimit; addrDTLimit = cpu.addrGDTLimit;
@ -166,8 +174,8 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
* grief here. We avoid that grief by 1) relying on the Debugger setting fSuppress to true, and 2) skipping * grief here. We avoid that grief by 1) relying on the Debugger setting fSuppress to true, and 2) skipping
* segment lookup if the descriptor table being referenced is zero. * segment lookup if the descriptor table being referenced is zero.
* *
* TODO: This could probably be simplified to a test of addrDT; please note, however, that there's nothing * TODO: This could probably be simplified to a test of addrDT; however, there's nothing in the design
* in the design of the CPU that prevents the GDT or LDT being located at physical address zero. * of the CPU that prevents the GDT or LDT being located at physical address zero.
*/ */
if (!fSuppress || addrDT) { if (!fSuppress || addrDT) {
var addrDesc = addrDT + (sel & X86.SEL.MASK); var addrDesc = addrDT + (sel & X86.SEL.MASK);
@ -193,7 +201,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
* *
* @this {X86Seg} * @this {X86Seg}
* @param {number} nIDT * @param {number} nIDT
* @return {number} address from selected veector, or ADDR_INVALID if error (TODO: No error conditions exist yet) * @return {number} address from selected vector, or ADDR_INVALID if error (TODO: No error conditions exist yet)
*/ */
X86Seg.loadIDTReal = function loadIDTReal(nIDT) X86Seg.loadIDTReal = function loadIDTReal(nIDT)
{ {
@ -455,7 +463,7 @@ X86Seg.switchTSS = function switchTSS(selNew, fNest)
offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; offSP = (this.cpl << 2) + X86.TSS.CPL0_SP;
offSS = offSP + 2; offSS = offSP + 2;
} }
cpu.setSS(cpu.getShort(addrNew + offSS)); // TODO: Do we care that cpu.setSS() -- unlike segSS.load() -- will also set X86.OPFLAG.NOINTR? cpu.setSS(cpu.getShort(addrNew + offSS), true);
cpu.setSP(cpu.getShort(addrNew + offSP)); cpu.setSP(cpu.getShort(addrNew + offSP));
cpu.segLDT.load(cpu.getShort(addrNew + X86.TSS.TASK_LDT)); cpu.segLDT.load(cpu.getShort(addrNew + X86.TSS.TASK_LDT));
if (fNest) cpu.setShort(addrNew + X86.TSS.PREV_TSS, selOld); if (fNest) cpu.setShort(addrNew + X86.TSS.PREV_TSS, selOld);
@ -592,7 +600,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
break; break;
} }
regSP = cpu.popWord(); regSP = cpu.popWord();
cpu.setSS(cpu.popWord()); // TODO: Do we care that cpu.setSS() -- unlike segSS.load() -- will also set X86.OPFLAG.NOINTR? cpu.setSS(cpu.popWord(), true);
cpu.setSP(regSP); cpu.setSP(regSP);
this.fStackSwitch = true; this.fStackSwitch = true;
} }
@ -659,7 +667,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
offSS = offSP + 2; offSS = offSP + 2;
regSSPrev = cpu.getSS(); regSSPrev = cpu.getSS();
regSPPrev = cpu.getSP(); regSPPrev = cpu.getSP();
cpu.setSS(cpu.getShort(addrTSS + offSS)); // TODO: Do we care that cpu.setSS() -- unlike segSS.load() -- will also set X86.OPFLAG.NOINTR? cpu.setSS(cpu.getShort(addrTSS + offSS), true);
cpu.setSP(cpu.getShort(addrTSS + offSP)); cpu.setSP(cpu.getShort(addrTSS + offSP));
cpu.pushWord(regSSPrev); cpu.pushWord(regSSPrev);
cpu.pushWord(regSPPrev); cpu.pushWord(regSPPrev);
@ -819,6 +827,7 @@ X86Seg.prototype.updateMode = function(fProt)
if (fProt === undefined) { if (fProt === undefined) {
fProt = !!(this.cpu.regMSW & X86.MSW.PE); fProt = !!(this.cpu.regMSW & X86.MSW.PE);
} }
this.fExpDown = false;
if (fProt) { if (fProt) {
this.load = X86Seg.loadProt; this.load = X86Seg.loadProt;
this.loadIDT = X86Seg.loadIDTProt; this.loadIDT = X86Seg.loadIDTProt;
@ -843,6 +852,7 @@ X86Seg.prototype.updateMode = function(fProt)
if ((this.acc & (X86.DESC.ACC.TYPE.CODE | X86.DESC.ACC.TYPE.EXPDOWN)) == X86.DESC.ACC.TYPE.EXPDOWN) { if ((this.acc & (X86.DESC.ACC.TYPE.CODE | X86.DESC.ACC.TYPE.EXPDOWN)) == X86.DESC.ACC.TYPE.EXPDOWN) {
if (this.checkRead == X86Seg.checkReadProt) this.checkRead = X86Seg.checkReadProtDown; if (this.checkRead == X86Seg.checkReadProt) this.checkRead = X86Seg.checkReadProtDown;
if (this.checkWrite == X86Seg.checkWriteProt) this.checkWrite = X86Seg.checkWriteProtDown; if (this.checkWrite == X86Seg.checkWriteProt) this.checkWrite = X86Seg.checkWriteProtDown;
this.fExpDown = true;
} }
} }
this.cpl = this.sel & X86.SEL.RPL; this.cpl = this.sel & X86.SEL.RPL;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff