Baby steps
This commit is contained in:
parent
13c50f7bd0
commit
2cd13b2058
11 changed files with 2808 additions and 2743 deletions
|
|
@ -106,6 +106,16 @@ var BACKTRACK = !COMPILED;
|
|||
*/
|
||||
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}
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*
|
||||
* this.resultSize (must be set to one of: SIZE_BYTE or SIZE_WORD)
|
||||
* this.resultValue
|
||||
* this.resultZeroCarry
|
||||
* this.resultParitySign
|
||||
* this.resultAuxOverflow
|
||||
*
|
||||
|
|
|
|||
|
|
@ -813,7 +813,7 @@ X86CPU.prototype.resetRegs = function()
|
|||
this.regEBX = 0;
|
||||
this.regECX = 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.regESI = 0;
|
||||
this.regEDI = 0;
|
||||
|
|
@ -1356,9 +1356,9 @@ X86CPU.prototype.getCS = function()
|
|||
X86CPU.prototype.setCS = function(sel)
|
||||
{
|
||||
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.opFlags |= this.OPFLAG_NOINTR8086;
|
||||
if (!BUGS_8086) this.opFlags |= this.OPFLAG_NOINTR8086;
|
||||
if (PREFETCH) this.flushPrefetch(this.regLIP);
|
||||
};
|
||||
|
||||
|
|
@ -1381,8 +1381,8 @@ X86CPU.prototype.getDS = function()
|
|||
*/
|
||||
X86CPU.prototype.setDS = function(sel)
|
||||
{
|
||||
this.segDS.load(sel & 0xffff);
|
||||
this.opFlags |= this.OPFLAG_NOINTR8086;
|
||||
this.segDS.load(sel);
|
||||
if (!BUGS_8086) this.opFlags |= this.OPFLAG_NOINTR8086;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1401,14 +1401,20 @@ X86CPU.prototype.getSS = function()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} sel
|
||||
* @param {boolean} [fInterruptable]
|
||||
*/
|
||||
X86CPU.prototype.setSS = function(sel)
|
||||
X86CPU.prototype.setSS = function(sel, fInterruptable)
|
||||
{
|
||||
var regESP = this.getSP();
|
||||
this.regLSP = this.segSS.load(sel & 0xffff) + regESP;
|
||||
this.regLSPLimit = this.segSS.base + this.segSS.limit;
|
||||
this.regLSPLimitLow = this.segSS.base; // TODO: Set this to the actual low limit
|
||||
this.opFlags |= X86.OPFLAG.NOINTR;
|
||||
this.regLSP = this.segSS.load(sel) + regESP;
|
||||
if (this.segSS.fExpDown) {
|
||||
this.regLSPLimit = this.segSS.base + this.segSS.addrMask;
|
||||
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)
|
||||
{
|
||||
this.segES.load(sel & 0xffff);
|
||||
this.opFlags |= this.OPFLAG_NOINTR8086;
|
||||
this.segES.load(sel);
|
||||
if (!BUGS_8086) this.opFlags |= this.OPFLAG_NOINTR8086;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1546,6 +1552,10 @@ X86CPU.prototype.advanceIP = function(inc)
|
|||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1557,7 +1567,12 @@ X86CPU.prototype.getSP = function()
|
|||
*/
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
this.resultValue &= ~this.resultSize;
|
||||
this.resultZeroCarry &= ~this.resultSize;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1716,7 +1731,7 @@ X86CPU.prototype.clearAF = 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()
|
||||
{
|
||||
this.resultValue |= this.resultSize;
|
||||
this.resultZeroCarry |= this.resultSize;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1800,7 +1815,7 @@ X86CPU.prototype.setAF = 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)
|
||||
{
|
||||
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.PF)) this.resultParitySign |= 0x1;
|
||||
|
|
@ -2608,7 +2623,10 @@ X86CPU.prototype.popWord = function()
|
|||
{
|
||||
var w = (I386? this.opMem.getWord(this.regLSP) : this.getShort(this.regLSP));
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -2622,7 +2640,10 @@ X86CPU.prototype.pushWord = function(w)
|
|||
{
|
||||
this.assert((w & this.dataMask) == w);
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
@ -2904,6 +2925,19 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
|
|||
if (opPrefixes) {
|
||||
this.opPrefixes |= opPrefixes;
|
||||
} 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.regEA = this.regEAWrite = X86.ADDR_INVALID;
|
||||
this.segData = this.segDS;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ var X86Grps = {
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
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}
|
||||
|
|
@ -59,7 +59,7 @@ var X86Grps = {
|
|||
opGrpORb: function(dst, src) {
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
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
|
||||
|
|
@ -72,10 +72,10 @@ var X86Grps = {
|
|||
*/
|
||||
opGrpADCb: function(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.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
|
||||
|
|
@ -88,10 +88,10 @@ var X86Grps = {
|
|||
*/
|
||||
opGrpSBBb: function(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.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}
|
||||
|
|
@ -102,7 +102,7 @@ var X86Grps = {
|
|||
opGrpANDb: function(dst, src) {
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
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}
|
||||
|
|
@ -114,7 +114,7 @@ var X86Grps = {
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
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}
|
||||
|
|
@ -125,7 +125,7 @@ var X86Grps = {
|
|||
opGrpXORb: function(dst, src) {
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
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}
|
||||
|
|
@ -136,7 +136,7 @@ var X86Grps = {
|
|||
opGrpCMPb: function(dst, src) {
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
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)
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* value, but sadly, we cannot do that in JavaScript.
|
||||
* conjunction with bit-wise operators can omit that one-line transformation, allowing us to set SIZE_DWORD to a
|
||||
* 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
|
||||
* 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.resultSize = X86.RESULT.SIZE_WORD;
|
||||
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}
|
||||
|
|
@ -196,7 +196,7 @@ var X86Grps = {
|
|||
opGrpORw: function(dst, src) {
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
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
|
||||
|
|
@ -209,10 +209,10 @@ var X86Grps = {
|
|||
*/
|
||||
opGrpADCw: function(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.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
|
||||
|
|
@ -225,10 +225,10 @@ var X86Grps = {
|
|||
*/
|
||||
opGrpSBBw: function(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.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}
|
||||
|
|
@ -239,7 +239,7 @@ var X86Grps = {
|
|||
opGrpANDw: function(dst, src) {
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
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}
|
||||
|
|
@ -251,7 +251,7 @@ var X86Grps = {
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
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}
|
||||
|
|
@ -262,7 +262,7 @@ var X86Grps = {
|
|||
opGrpXORw: function(dst, src) {
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
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}
|
||||
|
|
@ -273,7 +273,7 @@ var X86Grps = {
|
|||
opGrpCMPw: function(dst, src) {
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
@ -319,7 +319,7 @@ var X86Grps = {
|
|||
* @param {number} 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();
|
||||
},
|
||||
/**
|
||||
|
|
@ -417,9 +417,9 @@ var X86Grps = {
|
|||
var temp;
|
||||
var shift = (src & this.nShiftCountMask) % 0x9;
|
||||
if (!shift) {
|
||||
temp = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 8);
|
||||
temp = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
|
||||
} 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;
|
||||
}
|
||||
X86Grps.opGrpRotateFlags.call(this, temp, X86.RESULT.SIZE_BYTE);
|
||||
|
|
@ -440,9 +440,9 @@ var X86Grps = {
|
|||
var temp;
|
||||
var shift = (src & this.nShiftCountMask) % 0x11;
|
||||
if (!shift) {
|
||||
temp = dst | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
temp = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} 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;
|
||||
}
|
||||
X86Grps.opGrpRotateFlags.call(this, temp, X86.RESULT.SIZE_WORD);
|
||||
|
|
@ -461,7 +461,7 @@ var X86Grps = {
|
|||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
if (src) {
|
||||
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);
|
||||
result &= 0xff;
|
||||
}
|
||||
|
|
@ -479,7 +479,7 @@ var X86Grps = {
|
|||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
if (src) {
|
||||
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);
|
||||
result &= 0xffff;
|
||||
}
|
||||
|
|
@ -508,9 +508,9 @@ var X86Grps = {
|
|||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
if (src) {
|
||||
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
|
||||
result = (this.resultValue = this.resultParitySign = (dst << src)) & 0xff;
|
||||
result = (this.resultZeroCarry = this.resultParitySign = (dst << src)) & 0xff;
|
||||
this.resultAuxOverflow = 0;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
}
|
||||
|
|
@ -533,9 +533,9 @@ var X86Grps = {
|
|||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
if (src) {
|
||||
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
|
||||
result = (this.resultValue = this.resultParitySign = (dst << src)) & 0xffff;
|
||||
result = (this.resultZeroCarry = this.resultParitySign = (dst << src)) & 0xffff;
|
||||
this.resultAuxOverflow = 0;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
}
|
||||
|
|
@ -556,14 +556,14 @@ var X86Grps = {
|
|||
opGrpSHRb: function(dst, src) {
|
||||
if (src) { // the following comparison obviates the need to mask with this.nShiftCountMask
|
||||
var temp = (src > 8? 0 : (dst >> (src - 1)));
|
||||
this.resultValue = this.resultParitySign = temp >> 1;
|
||||
this.resultZeroCarry = this.resultParitySign = temp >> 1;
|
||||
if (temp & 0x01)
|
||||
this.resultValue |= X86.RESULT.SIZE_BYTE;
|
||||
this.resultZeroCarry |= X86.RESULT.SIZE_BYTE;
|
||||
else
|
||||
this.resultValue &= ~X86.RESULT.SIZE_BYTE;
|
||||
this.resultAuxOverflow = dst ^ this.resultValue;
|
||||
this.resultZeroCarry &= ~X86.RESULT.SIZE_BYTE;
|
||||
this.resultAuxOverflow = dst ^ this.resultZeroCarry;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
dst = this.resultValue;
|
||||
dst = this.resultZeroCarry;
|
||||
}
|
||||
return dst & 0xff;
|
||||
},
|
||||
|
|
@ -581,14 +581,14 @@ var X86Grps = {
|
|||
opGrpSHRw: function(dst, src) {
|
||||
if (src) { // the following comparison obviates the need to mask with this.nShiftCountMask
|
||||
var temp = (src > 16? 0 : (dst >> (src - 1)));
|
||||
this.resultValue = this.resultParitySign = temp >> 1;
|
||||
this.resultZeroCarry = this.resultParitySign = temp >> 1;
|
||||
if (temp & 0x01)
|
||||
this.resultValue |= X86.RESULT.SIZE_WORD;
|
||||
this.resultZeroCarry |= X86.RESULT.SIZE_WORD;
|
||||
else
|
||||
this.resultValue &= ~X86.RESULT.SIZE_WORD;
|
||||
this.resultAuxOverflow = dst ^ this.resultValue;
|
||||
this.resultZeroCarry &= ~X86.RESULT.SIZE_WORD;
|
||||
this.resultAuxOverflow = dst ^ this.resultZeroCarry;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
dst = this.resultValue;
|
||||
dst = this.resultZeroCarry;
|
||||
}
|
||||
return dst & 0xffff;
|
||||
},
|
||||
|
|
@ -607,14 +607,14 @@ var X86Grps = {
|
|||
if (src) {
|
||||
if (src > 8) src = 9; // this comparison obviates the need to mask with this.nShiftCountMask
|
||||
var temp = ((dst << 24) >> 24) >> (src - 1);
|
||||
this.resultValue = this.resultParitySign = temp >> 1;
|
||||
this.resultZeroCarry = this.resultParitySign = temp >> 1;
|
||||
if (temp & 0x01)
|
||||
this.resultValue |= X86.RESULT.SIZE_BYTE;
|
||||
this.resultZeroCarry |= X86.RESULT.SIZE_BYTE;
|
||||
else
|
||||
this.resultValue &= ~X86.RESULT.SIZE_BYTE;
|
||||
this.resultAuxOverflow = dst ^ this.resultValue;
|
||||
this.resultZeroCarry &= ~X86.RESULT.SIZE_BYTE;
|
||||
this.resultAuxOverflow = dst ^ this.resultZeroCarry;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
dst = this.resultValue;
|
||||
dst = this.resultZeroCarry;
|
||||
}
|
||||
return dst & 0xff;
|
||||
},
|
||||
|
|
@ -633,14 +633,14 @@ var X86Grps = {
|
|||
if (src) {
|
||||
if (src > 16) src = 17; // this comparison obviates the need to mask with this.nShiftCountMask
|
||||
var temp = ((dst << 16) >> 16) >> (src - 1);
|
||||
this.resultValue = this.resultParitySign = temp >> 1;
|
||||
this.resultZeroCarry = this.resultParitySign = temp >> 1;
|
||||
if (temp & 0x01)
|
||||
this.resultValue |= X86.RESULT.SIZE_WORD;
|
||||
this.resultZeroCarry |= X86.RESULT.SIZE_WORD;
|
||||
else
|
||||
this.resultValue &= ~X86.RESULT.SIZE_WORD;
|
||||
this.resultAuxOverflow = dst ^ this.resultValue;
|
||||
this.resultZeroCarry &= ~X86.RESULT.SIZE_WORD;
|
||||
this.resultAuxOverflow = dst ^ this.resultZeroCarry;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
dst = this.resultValue;
|
||||
dst = this.resultZeroCarry;
|
||||
}
|
||||
return dst & 0xffff;
|
||||
},
|
||||
|
|
@ -652,7 +652,7 @@ var X86Grps = {
|
|||
*/
|
||||
opGrpTEST8: function(dst, src) {
|
||||
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.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
|
|
@ -666,7 +666,7 @@ var X86Grps = {
|
|||
*/
|
||||
opGrpTEST16: function(dst, src) {
|
||||
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.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
|
|
@ -703,7 +703,7 @@ var X86Grps = {
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
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}
|
||||
|
|
@ -716,7 +716,7 @@ var X86Grps = {
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
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}
|
||||
|
|
@ -725,8 +725,8 @@ var X86Grps = {
|
|||
* @return {number} (we return dst unchanged, since it's actually AX that's modified)
|
||||
*/
|
||||
opGrpMULb: function(dst, src) {
|
||||
this.regEAX = this.regMD16 = (this.resultValue = (src = this.regEAX & 0xff) * dst) & 0xffff;
|
||||
this.resultAuxOverflow = this.resultParitySign = this.resultValue;
|
||||
this.regEAX = this.regMD16 = (this.resultZeroCarry = (src = this.regEAX & 0xff) * dst) & 0xffff;
|
||||
this.resultAuxOverflow = this.resultParitySign = this.resultZeroCarry;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
/*
|
||||
* 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) {
|
||||
var result = (((src = this.regEAX) << 24) >> 24) * ((dst << 24) >> 24);
|
||||
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;
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
opGrpMULw: function(dst, src) {
|
||||
this.regMD16 = this.regEAX = (this.resultValue = (src = this.regEAX) * dst) & 0xffff;
|
||||
this.regMD32 = this.regEDX = (this.resultValue >> 16) & 0xffff;
|
||||
this.resultAuxOverflow = this.resultParitySign = this.resultValue;
|
||||
this.regMD16 = this.regEAX = (this.resultZeroCarry = (src = this.regEAX) * dst) & 0xffff;
|
||||
this.regMD32 = this.regEDX = (this.resultZeroCarry >> 16) & 0xffff;
|
||||
this.resultAuxOverflow = this.resultParitySign = this.resultZeroCarry;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
/*
|
||||
* 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);
|
||||
this.regEAX = this.regMD16 = result & 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;
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
/*
|
||||
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
|
||||
|
|
@ -1058,7 +1058,7 @@ var X86Grps = {
|
|||
opGrpINCb: function(dst, src) {
|
||||
this.resultAuxOverflow = dst;
|
||||
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.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
|
||||
return dst;
|
||||
|
|
@ -1072,7 +1072,7 @@ var X86Grps = {
|
|||
opGrpDECb: function(dst, src) {
|
||||
this.resultAuxOverflow = dst;
|
||||
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.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
|
||||
return dst;
|
||||
|
|
@ -1086,7 +1086,7 @@ var X86Grps = {
|
|||
opGrpINCw: function(dst, src) {
|
||||
this.resultAuxOverflow = dst;
|
||||
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.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
|
||||
return dst;
|
||||
|
|
@ -1100,7 +1100,7 @@ var X86Grps = {
|
|||
opGrpDECw: function(dst, src) {
|
||||
this.resultAuxOverflow = dst;
|
||||
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.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
|
||||
return dst;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ var X86Help = {
|
|||
* @return {number}
|
||||
*/
|
||||
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.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
|
|
@ -77,7 +77,7 @@ var X86Help = {
|
|||
* @return {number}
|
||||
*/
|
||||
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.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
|
|
@ -100,7 +100,7 @@ var X86Help = {
|
|||
*/
|
||||
opHelpIMUL8: function(dst, src) {
|
||||
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;
|
||||
/*
|
||||
* 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) {
|
||||
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;
|
||||
/*
|
||||
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
|
||||
|
|
|
|||
|
|
@ -88,9 +88,8 @@ var X86OpXX = {
|
|||
opADDALb: function() {
|
||||
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
|
||||
* result is a blending of btiAL and btiMemLo, so technically, a new bti should be allocated to reflect
|
||||
* that fact; however, I'm leaving perfect BACKTRACKing for another day.
|
||||
* NOTE: Whenever the result is "blended" value (eg, of btiAL and btiMemLo), a new bti should be
|
||||
* allocated to reflect that fact; however, I'm leaving "perfect" BACKTRACK support for another day.
|
||||
*/
|
||||
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiMemLo;
|
||||
/*
|
||||
|
|
@ -465,7 +464,7 @@ var X86OpXX = {
|
|||
opDAA: function() {
|
||||
var AL = this.regEAX & 0xff;
|
||||
var fAuxCarry = this.getAF();
|
||||
var fCarry = (this.resultValue & this.resultSize);
|
||||
var fCarry = (this.resultZeroCarry & this.resultSize);
|
||||
if ((AL & 0xf) > 9 || fAuxCarry) {
|
||||
AL += 0x6;
|
||||
fAuxCarry = true;
|
||||
|
|
@ -474,9 +473,9 @@ var X86OpXX = {
|
|||
AL += 0x60;
|
||||
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;
|
||||
if (fCarry) this.resultValue |= this.resultSize;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
if (fAuxCarry) this.setAF(); else this.clearAF();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAA have the same cycle times
|
||||
},
|
||||
|
|
@ -564,7 +563,7 @@ var X86OpXX = {
|
|||
opDAS: function() {
|
||||
var AL = this.regEAX & 0xff;
|
||||
var fAuxCarry = this.getAF();
|
||||
var fCarry = (this.resultValue & this.resultSize);
|
||||
var fCarry = (this.resultZeroCarry & this.resultSize);
|
||||
if ((AL & 0xf) > 9 || fAuxCarry) {
|
||||
AL -= 0x6;
|
||||
fAuxCarry = true;
|
||||
|
|
@ -573,9 +572,9 @@ var X86OpXX = {
|
|||
AL -= 0x60;
|
||||
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;
|
||||
if (fCarry) this.resultValue |= this.resultSize;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
if (fAuxCarry) this.setAF(); else this.clearAF();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAS have the same cycle times
|
||||
},
|
||||
|
|
@ -672,9 +671,9 @@ var X86OpXX = {
|
|||
} else {
|
||||
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;
|
||||
if (fCarry) this.resultValue |= this.resultSize;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
if (fAuxCarry) this.setAF(); else this.clearAF();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA;
|
||||
},
|
||||
|
|
@ -774,11 +773,11 @@ var X86OpXX = {
|
|||
} else {
|
||||
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;
|
||||
if (fCarry) this.resultValue |= this.resultSize;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
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)
|
||||
|
|
@ -786,9 +785,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCAX: function() {
|
||||
this.resultAuxOverflow = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign = this.regEAX + 1) & this.dataMask;
|
||||
this.resultValue = this.regEAX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEAX) + 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -798,9 +802,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCCX: function() {
|
||||
this.resultAuxOverflow = this.regECX;
|
||||
this.regECX = (this.regECX & ~this.dataMask) | (this.resultParitySign = this.regECX + 1) & this.dataMask;
|
||||
this.resultValue = this.regECX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regECX) + 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -810,9 +819,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCDX: function() {
|
||||
this.resultAuxOverflow = this.regEDX;
|
||||
this.regEDX = (this.regEDX & ~this.dataMask) | (this.resultParitySign = this.regEDX + 1) & this.dataMask;
|
||||
this.resultValue = this.regEDX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDX) + 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -822,9 +836,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCBX: function() {
|
||||
this.resultAuxOverflow = this.regEBX;
|
||||
this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign = this.regEBX + 1) & this.dataMask;
|
||||
this.resultValue = this.regEBX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBX) + 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -834,9 +853,10 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCSP: function() {
|
||||
this.resultAuxOverflow = this.getSP();
|
||||
this.setSP((this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign = this.resultAuxOverflow + 1) & this.dataMask);
|
||||
this.resultValue = this.getSP() | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
var regESP;
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.getSP()) + 1;
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -846,9 +866,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCBP: function() {
|
||||
this.resultAuxOverflow = this.regEBP;
|
||||
this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign = this.regEBP + 1) & this.dataMask;
|
||||
this.resultValue = this.regEBP | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBP) + 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -858,9 +883,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCSI: function() {
|
||||
this.resultAuxOverflow = this.regESI;
|
||||
this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign = this.regESI + 1) & this.dataMask;
|
||||
this.resultValue = this.regESI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regESI) + 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -870,9 +900,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opINCDI: function() {
|
||||
this.resultAuxOverflow = this.regEDI;
|
||||
this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign = this.regEDI + 1) & this.dataMask;
|
||||
this.resultValue = this.regEDI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDI) + 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -882,9 +917,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opDECAX: function() {
|
||||
this.resultAuxOverflow = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign = this.regEAX - 1) & this.dataMask;
|
||||
this.resultValue = this.regEAX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEAX) - 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -894,9 +934,9 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opDECCX: function() {
|
||||
this.resultAuxOverflow = this.regECX;
|
||||
this.regECX = (this.regECX & ~this.dataMask) | (this.resultParitySign = this.regECX - 1) & this.dataMask;
|
||||
this.resultValue = this.regECX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regECX) - 1;
|
||||
this.regECX = (I386? (this.regECX & ~this.dataMask) | (this.resultParitySign & this.dataMask) : this.resultParitySign & 0xffff);
|
||||
this.resultZeroCarry = this.regECX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -906,9 +946,9 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opDECDX: function() {
|
||||
this.resultAuxOverflow = this.regEDX;
|
||||
this.regEDX = (this.regEDX & ~this.dataMask) | (this.resultParitySign = this.regEDX - 1) & this.dataMask;
|
||||
this.resultValue = this.regEDX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDX) - 1;
|
||||
this.regEDX = (I386? (this.regEDX & ~this.dataMask) | (this.resultParitySign & this.dataMask) : this.resultParitySign & 0xffff);
|
||||
this.resultZeroCarry = this.regEDX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -918,9 +958,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opDECBX: function() {
|
||||
this.resultAuxOverflow = this.regEBX;
|
||||
this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign = this.regEBX - 1) & this.dataMask;
|
||||
this.resultValue = this.regEBX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBX) - 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -930,9 +975,10 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opDECSP: function() {
|
||||
this.resultAuxOverflow = this.getSP();
|
||||
this.setSP((this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign = this.resultAuxOverflow - 1) & this.dataMask);
|
||||
this.resultValue = this.getSP() | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
var regESP;
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.getSP()) - 1;
|
||||
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.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -942,9 +988,14 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opDECBP: function() {
|
||||
this.resultAuxOverflow = this.regEBP;
|
||||
this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign = this.regEBP - 1) & this.dataMask;
|
||||
this.resultValue = this.regEBP | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBP) - 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -954,21 +1005,31 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opDECSI: function() {
|
||||
this.resultAuxOverflow = this.regESI;
|
||||
this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign = this.regESI - 1) & this.dataMask;
|
||||
this.resultValue = this.regESI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regESI) - 1;
|
||||
if (I386) {
|
||||
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.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
},
|
||||
/**
|
||||
/**`
|
||||
* op=0x4F (DEC DI)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
opDECDI: function() {
|
||||
this.resultAuxOverflow = this.regEDI;
|
||||
this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign = this.regEDI - 1) & this.dataMask;
|
||||
this.resultValue = this.regEDI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDI) - 1;
|
||||
if (I386) {
|
||||
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.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)
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
|
|
@ -1370,13 +1429,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -1385,8 +1443,6 @@ var X86OpXX = {
|
|||
* op=0x6D (INSW) (80186/80188 and up)
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
|
|
@ -1420,13 +1476,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -1465,13 +1520,12 @@ var X86OpXX = {
|
|||
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemLo;
|
||||
this.bus.checkPortOutputNotify(this.regEDX, b, this.regLIP - nDelta - 1);
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -1513,13 +1567,12 @@ var X86OpXX = {
|
|||
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemHi;
|
||||
this.bus.checkPortOutputNotify(this.regEDX, w >> 8, addrFrom);
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2030,8 +2083,8 @@ var X86OpXX = {
|
|||
*/
|
||||
opXCHGCX: function() {
|
||||
var temp = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regECX & this.dataMask);
|
||||
this.regECX = (this.regECX & ~this.dataMask) | (temp & this.dataMask);
|
||||
this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regECX & this.dataMask) : this.regECX);
|
||||
this.regECX = (I386? (this.regECX & ~this.dataMask) | (temp & this.dataMask) : temp);
|
||||
if (BACKTRACK) {
|
||||
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;
|
||||
|
|
@ -2045,8 +2098,8 @@ var X86OpXX = {
|
|||
*/
|
||||
opXCHGDX: function() {
|
||||
var temp = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEDX & this.dataMask);
|
||||
this.regEDX = (this.regEDX & ~this.dataMask) | (temp & this.dataMask);
|
||||
this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEDX & this.dataMask) : this.regEDX);
|
||||
this.regEDX = (I386? (this.regEDX & ~this.dataMask) | (temp & this.dataMask) : temp);
|
||||
if (BACKTRACK) {
|
||||
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;
|
||||
|
|
@ -2060,8 +2113,8 @@ var X86OpXX = {
|
|||
*/
|
||||
opXCHGBX: function() {
|
||||
var temp = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEBX & this.dataMask);
|
||||
this.regEBX = (this.regEBX & ~this.dataMask) | (temp & this.dataMask);
|
||||
this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEBX & this.dataMask) : this.regEBX);
|
||||
this.regEBX = (I386? (this.regEBX & ~this.dataMask) | (temp & this.dataMask) : temp);
|
||||
if (BACKTRACK) {
|
||||
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;
|
||||
|
|
@ -2076,8 +2129,8 @@ var X86OpXX = {
|
|||
opXCHGSP: function() {
|
||||
var temp = this.regEAX;
|
||||
var regESP = this.getSP();
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (regESP & this.dataMask);
|
||||
this.setSP((regESP & ~this.dataMask) | (temp & this.dataMask));
|
||||
this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (regESP & this.dataMask) : regESP);
|
||||
this.setSP((I386? (regESP & ~this.dataMask) | (temp & this.dataMask) : temp));
|
||||
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiAH = 0;
|
||||
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
|
||||
},
|
||||
|
|
@ -2088,8 +2141,8 @@ var X86OpXX = {
|
|||
*/
|
||||
opXCHGBP: function() {
|
||||
var temp = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEBP & this.dataMask);
|
||||
this.regEBP = (this.regEBP & ~this.dataMask) | (temp & this.dataMask);
|
||||
this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEBP & this.dataMask) : this.regEBP);
|
||||
this.regEBP = (I386? (this.regEBP & ~this.dataMask) | (temp & this.dataMask) : temp);
|
||||
if (BACKTRACK) {
|
||||
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;
|
||||
|
|
@ -2103,8 +2156,8 @@ var X86OpXX = {
|
|||
*/
|
||||
opXCHGSI: function() {
|
||||
var temp = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regESI & this.dataMask);
|
||||
this.regESI = (this.regESI & ~this.dataMask) | (temp & this.dataMask);
|
||||
this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regESI & this.dataMask) : this.regESI);
|
||||
this.regESI = (I386? (this.regESI & ~this.dataMask) | (temp & this.dataMask) : temp);
|
||||
if (BACKTRACK) {
|
||||
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;
|
||||
|
|
@ -2118,8 +2171,8 @@ var X86OpXX = {
|
|||
*/
|
||||
opXCHGDI: function() {
|
||||
var temp = this.regEAX;
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regEDI & this.dataMask);
|
||||
this.regEDI = (this.regEDI & ~this.dataMask) | (temp & this.dataMask);
|
||||
this.regEAX = (I386? (this.regEAX & ~this.dataMask) | (this.regEDI & this.dataMask) : this.regEDI);
|
||||
this.regEDI = (I386? (this.regEDI & ~this.dataMask) | (temp & this.dataMask) : temp);
|
||||
if (BACKTRACK) {
|
||||
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;
|
||||
|
|
@ -2317,17 +2370,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*
|
||||
* 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);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2355,17 +2403,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*
|
||||
* 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);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2403,17 +2446,12 @@ var X86OpXX = {
|
|||
* two values are equal, we must continue.
|
||||
*/
|
||||
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*
|
||||
* 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);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2451,17 +2489,12 @@ var X86OpXX = {
|
|||
* two values are equal, we must continue.
|
||||
*/
|
||||
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*
|
||||
* 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);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2472,7 +2505,7 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
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.nStepCycles -= this.CYCLES.nOpCyclesAAA;
|
||||
},
|
||||
|
|
@ -2482,7 +2515,7 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
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.nStepCycles -= this.CYCLES.nOpCyclesAAA;
|
||||
},
|
||||
|
|
@ -2490,8 +2523,6 @@ var X86OpXX = {
|
|||
* op=0xAA (STOSB)
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
|
|
@ -2515,13 +2546,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2530,8 +2560,6 @@ var X86OpXX = {
|
|||
* op=0xAB (STOSW)
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
|
|
@ -2558,13 +2586,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2591,17 +2618,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*
|
||||
* 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);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2630,17 +2652,12 @@ var X86OpXX = {
|
|||
this.nStepCycles -= nCycles;
|
||||
this.regECX -= nDelta;
|
||||
if (nReps) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*
|
||||
* 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);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2674,13 +2691,12 @@ var X86OpXX = {
|
|||
* two values are equal, we must continue.
|
||||
*/
|
||||
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -2714,13 +2730,12 @@ var X86OpXX = {
|
|||
* two values are equal, we must continue.
|
||||
*/
|
||||
if (nReps && this.getZF() == (this.opPrefixes & X86.OPFLAG.REPZ)) {
|
||||
/*
|
||||
* We have to back up to the prefix byte(s), not just to the string instruction,
|
||||
* because if a h/w interrupt is acknowledged before the next repetition begins,
|
||||
* the interrupt handler will return us to an invalid state.
|
||||
*/
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
if (BUGS_8086) {
|
||||
this.advanceIP(-2); // this instruction does not support segment overrides
|
||||
this.assert(this.regLIP == this.opLIP);
|
||||
} else {
|
||||
this.regLIP = this.opLIP;
|
||||
}
|
||||
this.opFlags |= X86.OPFLAG.REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
@ -3151,7 +3166,7 @@ var X86OpXX = {
|
|||
var bRemainder = AL % bDivisor;
|
||||
this.regEAX = (bQuotient << 8) | bRemainder;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
this.resultValue = this.resultParitySign = AL;
|
||||
this.resultZeroCarry = this.resultParitySign = AL;
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAM;
|
||||
},
|
||||
/**
|
||||
|
|
@ -3172,7 +3187,7 @@ var X86OpXX = {
|
|||
*/
|
||||
opAAD: function() {
|
||||
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.nStepCycles -= this.CYCLES.nOpCyclesAAD;
|
||||
},
|
||||
|
|
@ -3218,7 +3233,7 @@ var X86OpXX = {
|
|||
*/
|
||||
opLOOPNZ: function() {
|
||||
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.nStepCycles -= this.CYCLES.nOpCyclesLoopNZ;
|
||||
return;
|
||||
|
|
@ -3232,7 +3247,7 @@ var X86OpXX = {
|
|||
*/
|
||||
opLOOPZ: function() {
|
||||
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.nStepCycles -= this.CYCLES.nOpCyclesLoopZ;
|
||||
return;
|
||||
|
|
@ -3544,7 +3559,7 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opCLC: function() {
|
||||
this.resultValue &= ~this.resultSize;
|
||||
this.resultZeroCarry &= ~this.resultSize;
|
||||
this.nStepCycles -= 2; // CLC takes 2 cycles on all CPUs
|
||||
},
|
||||
/**
|
||||
|
|
@ -3553,7 +3568,7 @@ var X86OpXX = {
|
|||
* @this {X86CPU}
|
||||
*/
|
||||
opSTC: function() {
|
||||
this.resultValue |= this.resultSize;
|
||||
this.resultZeroCarry |= this.resultSize;
|
||||
this.nStepCycles -= 2; // STC takes 2 cycles on all CPUs
|
||||
},
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
* @version 1.0
|
||||
* Created 2014-Sep-10
|
||||
|
|
@ -45,7 +45,7 @@ if (typeof module !== 'undefined') {
|
|||
* @constructor
|
||||
* @param {X86CPU} cpu
|
||||
* @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)
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
* is meaningless for segments other than segCS.
|
||||
* calling load(); the downside is that such a parameter is meaningless for segments other than segCS.
|
||||
*/
|
||||
this.awParms = (this.id == X86Seg.ID.CODE? new Array(32) : []);
|
||||
this.fCall = null;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +122,7 @@ X86Seg.ID = {
|
|||
*/
|
||||
X86Seg.loadReal = function loadReal(sel, fSuppress)
|
||||
{
|
||||
this.cpu.assert(!(sel & ~0xffff));
|
||||
this.sel = sel;
|
||||
this.dataSize = this.addrSize = 2;
|
||||
this.dataMask = this.addrMask = 0xffff;
|
||||
|
|
@ -152,6 +158,8 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
|
|||
var addrDTLimit;
|
||||
var cpu = this.cpu;
|
||||
|
||||
this.cpu.assert(!(sel & ~0xffff));
|
||||
|
||||
if (!(sel & X86.SEL.LDT)) {
|
||||
addrDT = cpu.addrGDT;
|
||||
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
|
||||
* 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
|
||||
* in the design of the CPU that prevents the GDT or LDT being located at physical address zero.
|
||||
* TODO: This could probably be simplified to a test of addrDT; however, there's nothing in the design
|
||||
* of the CPU that prevents the GDT or LDT being located at physical address zero.
|
||||
*/
|
||||
if (!fSuppress || addrDT) {
|
||||
var addrDesc = addrDT + (sel & X86.SEL.MASK);
|
||||
|
|
@ -193,7 +201,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
|
|||
*
|
||||
* @this {X86Seg}
|
||||
* @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)
|
||||
{
|
||||
|
|
@ -455,7 +463,7 @@ X86Seg.switchTSS = function switchTSS(selNew, fNest)
|
|||
offSP = (this.cpl << 2) + X86.TSS.CPL0_SP;
|
||||
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.segLDT.load(cpu.getShort(addrNew + X86.TSS.TASK_LDT));
|
||||
if (fNest) cpu.setShort(addrNew + X86.TSS.PREV_TSS, selOld);
|
||||
|
|
@ -592,7 +600,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
break;
|
||||
}
|
||||
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);
|
||||
this.fStackSwitch = true;
|
||||
}
|
||||
|
|
@ -659,7 +667,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
offSS = offSP + 2;
|
||||
regSSPrev = cpu.getSS();
|
||||
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.pushWord(regSSPrev);
|
||||
cpu.pushWord(regSPPrev);
|
||||
|
|
@ -819,6 +827,7 @@ X86Seg.prototype.updateMode = function(fProt)
|
|||
if (fProt === undefined) {
|
||||
fProt = !!(this.cpu.regMSW & X86.MSW.PE);
|
||||
}
|
||||
this.fExpDown = false;
|
||||
if (fProt) {
|
||||
this.load = X86Seg.loadProt;
|
||||
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.checkRead == X86Seg.checkReadProt) this.checkRead = X86Seg.checkReadProtDown;
|
||||
if (this.checkWrite == X86Seg.checkWriteProt) this.checkWrite = X86Seg.checkWriteProtDown;
|
||||
this.fExpDown = true;
|
||||
}
|
||||
}
|
||||
this.cpl = this.sel & X86.SEL.RPL;
|
||||
|
|
|
|||
Loading…
Reference in a new issue