Baby steps
This commit is contained in:
parent
13c50f7bd0
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
|
|
@ -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;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue