32-bit multiplication
This commit is contained in:
parent
061cb7ea08
commit
d68f1bd985
6 changed files with 157 additions and 63 deletions
|
|
@ -1969,7 +1969,7 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* traceLog(prop, dst, src, flagsIn, flagsOut, result)
|
||||
* traceLog(prop, dst, src, flagsIn, flagsOut, resultLo, resultHi)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string} prop
|
||||
|
|
@ -1977,15 +1977,16 @@ if (DEBUGGER) {
|
|||
* @param {number} src
|
||||
* @param {number|null} flagsIn
|
||||
* @param {number|null} flagsOut
|
||||
* @param {number} result
|
||||
* @param {number} resultLo
|
||||
* @param {number} [resultHi]
|
||||
*/
|
||||
Debugger.prototype.traceLog = function(prop, dst, src, flagsIn, flagsOut, result)
|
||||
Debugger.prototype.traceLog = function(prop, dst, src, flagsIn, flagsOut, resultLo, resultHi)
|
||||
{
|
||||
if (DEBUG) {
|
||||
if (this.traceEnabled !== undefined && this.traceEnabled[prop]) {
|
||||
var trace = Debugger.TRACE[prop];
|
||||
var len = (trace.size >> 2);
|
||||
var s = this.hexOffset(this.cpu.opLIP - this.cpu.segCS.base, this.cpu.getCS()) + " " + Debugger.INS_NAMES[trace.ins] + "(" + str.toHex(dst, len) + "," + str.toHex(src, len) + "," + (flagsIn === null? "-" : str.toHexWord(flagsIn)) + ") " + str.toHex(result, len) + "," + (flagsOut === null? "-" : str.toHexWord(flagsOut));
|
||||
var s = this.hexOffset(this.cpu.opLIP - this.cpu.segCS.base, this.cpu.getCS()) + " " + Debugger.INS_NAMES[trace.ins] + "(" + str.toHex(dst, len) + "," + str.toHex(src, len) + "," + (flagsIn === null? "-" : str.toHexWord(flagsIn)) + ") " + str.toHex(resultLo, len) + "," + (flagsOut === null? "-" : str.toHexWord(flagsOut));
|
||||
if (!this.aTraceBuffer.length) this.aTraceBuffer = new Array(Debugger.TRACE_LIMIT);
|
||||
this.aTraceBuffer[this.iTraceBuffer++] = s;
|
||||
if (this.iTraceBuffer >= this.aTraceBuffer.length) {
|
||||
|
|
|
|||
|
|
@ -1000,7 +1000,9 @@ X86CPU.prototype.resetRegs = function()
|
|||
* instructions perform calculations that must be propagated to specific registers (eg, AX and/or DX), which
|
||||
* the ModRM decoder functions don't know about. We initialize them here mainly for documentation purposes.
|
||||
*/
|
||||
this.regMD16 = this.regMD32 = -1;
|
||||
this.fMDSet = false; // regMDHi and/or regMDLo are invalid unless fMDSet is true
|
||||
this.regMDLo = this.regMDHi = 0;
|
||||
this.regXX = 0; // internal register for segment register and control register moves
|
||||
|
||||
/*
|
||||
* Another internal "register" we occasionally need is an interim copy of bModRM, set inside selected opcode
|
||||
|
|
@ -2438,7 +2440,7 @@ X86CPU.prototype.setPS = function(regPS, cpl)
|
|||
};
|
||||
|
||||
/**
|
||||
* traceLog(prop, dst, src, flagsIn, flagsOut, result)
|
||||
* traceLog(prop, dst, src, flagsIn, flagsOut, resultLo, resultHi)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {string} prop
|
||||
|
|
@ -2446,12 +2448,13 @@ X86CPU.prototype.setPS = function(regPS, cpl)
|
|||
* @param {number} src
|
||||
* @param {number|null} flagsIn
|
||||
* @param {number|null} flagsOut
|
||||
* @param {number} result
|
||||
* @param {number} resultLo
|
||||
* @param {number} [resultHi]
|
||||
*/
|
||||
X86CPU.prototype.traceLog = function(prop, dst, src, flagsIn, flagsOut, result)
|
||||
X86CPU.prototype.traceLog = function(prop, dst, src, flagsIn, flagsOut, resultLo, resultHi)
|
||||
{
|
||||
if (DEBUG && this.dbg) {
|
||||
this.dbg.traceLog(prop, dst, src, flagsIn, flagsOut, result);
|
||||
this.dbg.traceLog(prop, dst, src, flagsIn, flagsOut, resultLo, resultHi);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -490,14 +490,15 @@ X86.fnDIVb = function DIVb(dst, src)
|
|||
X86.fnDIVOverflow.call(this);
|
||||
return dst;
|
||||
}
|
||||
this.regMD16 = this.regEAX = (uQuotient & 0xff) | (((this.regEAX % dst) & 0xff) << 8);
|
||||
this.fMDSet = true;
|
||||
this.regMDLo = this.regEAX = (uQuotient & 0xff) | (((this.regEAX % dst) & 0xff) << 8);
|
||||
/*
|
||||
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
|
||||
* via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
|
||||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('DIVB', src, dst, null, this.getPS(), this.regMD16);
|
||||
if (DEBUG && DEBUGGER) this.traceLog('DIVB', src, dst, null, this.getPS(), this.regMDLo);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesDivBR : this.cycleCounts.nOpCyclesDivBM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
@ -533,15 +534,16 @@ X86.fnDIVw = function DIVw(dst, src)
|
|||
X86.fnDIVOverflow.call(this);
|
||||
return dst;
|
||||
}
|
||||
this.regMD16 = this.regEAX = (uQuotient & 0xffff);
|
||||
this.regMD32 = this.regEDX = (src % dst) & 0xffff;
|
||||
this.fMDSet = true;
|
||||
this.regMDLo = this.regEAX = (uQuotient & 0xffff);
|
||||
this.regMDHi = this.regEDX = (src % dst) & 0xffff;
|
||||
/*
|
||||
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
|
||||
* via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
|
||||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('DIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
|
||||
if (DEBUG && DEBUGGER) this.traceLog('DIVW', src, dst, null, this.getPS(), this.regMDLo | (this.regMDHi << 16));
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesDivWR : this.cycleCounts.nOpCyclesDivWM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
@ -593,14 +595,15 @@ X86.fnIDIVb = function IDIVb(dst, src)
|
|||
X86.fnDIVOverflow.call(this);
|
||||
return dst;
|
||||
}
|
||||
this.regMD16 = this.regEAX = (lQuotient & 0xff) | (((((this.regEAX << 16) >> 16) % ((dst << 24) >> 24)) & 0xff) << 8);
|
||||
this.fMDSet = true;
|
||||
this.regMDLo = this.regEAX = (lQuotient & 0xff) | (((((this.regEAX << 16) >> 16) % ((dst << 24) >> 24)) & 0xff) << 8);
|
||||
/*
|
||||
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
|
||||
* via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
|
||||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IDIVB', src, dst, null, this.getPS(), this.regMD16);
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IDIVB', src, dst, null, this.getPS(), this.regMDLo);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIDivBR : this.cycleCounts.nOpCyclesIDivBM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
@ -641,15 +644,16 @@ X86.fnIDIVw = function IDIVw(dst, src)
|
|||
X86.fnDIVOverflow.call(this);
|
||||
return dst;
|
||||
}
|
||||
this.regMD16 = this.regEAX = (lQuotient & 0xffff);
|
||||
this.regMD32 = this.regEDX = (src % lDivisor) & 0xffff;
|
||||
this.fMDSet = true;
|
||||
this.regMDLo = this.regEAX = (lQuotient & 0xffff);
|
||||
this.regMDHi = this.regEDX = (src % lDivisor) & 0xffff;
|
||||
/*
|
||||
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
|
||||
* via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
|
||||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IDIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IDIVW', src, dst, null, this.getPS(), this.regMDLo | (this.regMDHi << 16));
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIDivWR : this.cycleCounts.nOpCyclesIDivWM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
@ -751,7 +755,8 @@ X86.fnIMULn = function IMULn(dst, src)
|
|||
X86.fnIMULb = function IMULb(dst, src)
|
||||
{
|
||||
var result = (((src = this.regEAX) << 24) >> 24) * ((dst << 24) >> 24);
|
||||
this.regEAX = this.regMD16 = result & 0xffff;
|
||||
this.fMDSet = true;
|
||||
this.regEAX = this.regMDLo = result & 0xffff;
|
||||
if (result > 127 || result < -128) {
|
||||
this.setCF(); this.setOF();
|
||||
} else {
|
||||
|
|
@ -763,7 +768,7 @@ X86.fnIMULb = function IMULb(dst, src)
|
|||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IMULB', src, dst, null, this.getPS(), this.regMD16);
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IMULB', src, dst, null, this.getPS(), this.regMDLo);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulBR : this.cycleCounts.nOpCyclesIMulBM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
@ -793,8 +798,9 @@ X86.fnIMULb = function IMULb(dst, src)
|
|||
X86.fnIMULw = function IMULw(dst, src)
|
||||
{
|
||||
var result = (((src = this.regEAX) << 16) >> 16) * ((dst << 16) >> 16);
|
||||
this.regEAX = this.regMD16 = result & 0xffff;
|
||||
this.regEDX = this.regMD32 = (result >> 16) & 0xffff;
|
||||
this.fMDSet = true;
|
||||
this.regEAX = this.regMDLo = result & 0xffff;
|
||||
this.regEDX = this.regMDHi = (result >> 16) & 0xffff;
|
||||
if (result > 32767 || result < -32768) {
|
||||
this.setCF(); this.setOF();
|
||||
} else {
|
||||
|
|
@ -806,7 +812,7 @@ X86.fnIMULw = function IMULw(dst, src)
|
|||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IMULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
|
||||
if (DEBUG && DEBUGGER) this.traceLog('IMULW', src, dst, null, this.getPS(), this.regMDLo | (this.regMDHi << 16));
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulWR : this.cycleCounts.nOpCyclesIMulWM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
@ -1362,16 +1368,16 @@ X86.fnMOVn = function MOVn(dst, src)
|
|||
};
|
||||
|
||||
/**
|
||||
* fnMOVMD16(dst, src)
|
||||
* fnMOVxx(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (current value, ignored)
|
||||
* @param {number} src (new value)
|
||||
* @return {number} dst (src is overridden, replaced with regMD16, as specified by opMOVwsr())
|
||||
* @return {number} dst (src is overridden, replaced with regXX, as specified by opMOVwsr())
|
||||
*/
|
||||
X86.fnMOVMD16 = function MOVMD16(dst, src)
|
||||
X86.fnMOVxx = function MOVxx(dst, src)
|
||||
{
|
||||
return X86.fnMOV.call(this, dst, this.regMD16);
|
||||
return X86.fnMOV.call(this, dst, this.regXX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1384,24 +1390,96 @@ X86.fnMOVMD16 = function MOVMD16(dst, src)
|
|||
*/
|
||||
X86.fnMULb = function MULb(dst, src)
|
||||
{
|
||||
this.regEAX = this.regMD16 = ((src = this.regEAX & 0xff) * dst) & 0xffff;
|
||||
if (this.regEAX & 0xff00) {
|
||||
this.fMDSet = true;
|
||||
this.regMDLo = ((src = this.regEAX & 0xff) * dst) & 0xffff;
|
||||
|
||||
if (this.regMDLo & 0xff00) {
|
||||
this.setCF(); this.setOF();
|
||||
} else {
|
||||
this.clearCF(); this.clearOF();
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
|
||||
* via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
|
||||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('MULB', src, dst, null, this.getPS(), this.regMD16);
|
||||
if (DEBUG && DEBUGGER) this.traceLog('MULB', src, dst, null, this.getPS(), this.regMDLo);
|
||||
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulBR : this.cycleCounts.nOpCyclesMulBM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnMUL32(dst, src)
|
||||
*
|
||||
* This sets regMDHi:regMDLo to the 64-bit result of dst * src, both of which are treated as unsigned.
|
||||
*
|
||||
* TODO: Some potential optimizations include:
|
||||
*
|
||||
* 1) Early outs if either parameter is zero, since the result will obviously be zero
|
||||
* 2) Using "normal" JavaScript multiplication if both parameters are < 32767
|
||||
*
|
||||
* Refer to: http://stackoverflow.com/questions/13597364/32-bit-signed-multiplication-with-a-64-bit-result-in-javascript
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (any 32-bit number, treated as unsigned)
|
||||
* @param {number} src (any 32-bit number, treated as unsigned)
|
||||
*/
|
||||
X86.fnMUL32 = function MUL32(dst, src)
|
||||
{
|
||||
var srcLo = src & 0xffff;
|
||||
var srcHi = src >>> 16;
|
||||
var dstLo = dst & 0xffff;
|
||||
var dstHi = dst >>> 16;
|
||||
|
||||
var mul00 = srcLo * dstLo;
|
||||
var mul16 = ((mul00 >>> 16) + (srcHi * dstLo));
|
||||
var mul32 = mul16 >>> 16;
|
||||
mul16 = ((mul16 & 0xffff) + (srcLo * dstHi));
|
||||
mul32 += ((mul16 >>> 16) + (srcHi * dstHi));
|
||||
|
||||
this.fMDSet = true;
|
||||
this.regMDLo = (mul16 << 16) | (mul00 & 0xffff);
|
||||
this.regMDHi = mul32|0;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnIMUL32(dst, src)
|
||||
*
|
||||
* This sets regMDHi:regMDLo to the 64-bit result of dst * src, either of which may be signed or unsigned.
|
||||
*
|
||||
* TODO: Some potential optimizations include:
|
||||
*
|
||||
* 1) Early outs if either parameter is zero, since the result will obviously be zero
|
||||
* 2) Using "normal" JavaScript multiplication if both parameters are >= -32768 && <= 32767
|
||||
*
|
||||
* Refer to: http://stackoverflow.com/questions/13597364/32-bit-signed-multiplication-with-a-64-bit-result-in-javascript
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (any 32-bit number, treated as signed)
|
||||
* @param {number} src (any 32-bit number, treated as signed)
|
||||
*/
|
||||
X86.fnIMUL32 = function IMUL32(dst, src)
|
||||
{
|
||||
var fNeg = false;
|
||||
if (src < 0) {
|
||||
src = -src|0;
|
||||
fNeg = !fNeg;
|
||||
}
|
||||
if (dst < 0) {
|
||||
dst = -dst|0;
|
||||
fNeg = !fNeg;
|
||||
}
|
||||
X86.fnMUL32.call(this, dst, src);
|
||||
if (fNeg) {
|
||||
this.regMDLo = (~this.regMDLo + 1)|0;
|
||||
this.regMDHi = (~this.regMDHi + (this.regMDLo? 0 : 1))|0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* fnMULw(dst, src)
|
||||
*
|
||||
|
|
@ -1412,21 +1490,35 @@ X86.fnMULb = function MULb(dst, src)
|
|||
*/
|
||||
X86.fnMULw = function MULw(dst, src)
|
||||
{
|
||||
var result = (src = this.regEAX) * dst;
|
||||
this.regMD16 = this.regEAX = result & 0xffff;
|
||||
this.regMD32 = this.regEDX = (result >> 16) & 0xffff;
|
||||
if (this.regEDX) {
|
||||
if (this.dataSize == 2) {
|
||||
src = this.regEAX & 0xffff;
|
||||
var result = src * dst;
|
||||
this.fMDSet = true;
|
||||
this.regMDLo = result & 0xffff;
|
||||
this.regMDHi = (result >> 16) & 0xffff;
|
||||
} else {
|
||||
X86.fnMUL32.call(this, dst, this.regEAX);
|
||||
}
|
||||
|
||||
if (this.regMDHi) {
|
||||
this.setCF(); this.setOF();
|
||||
} else {
|
||||
this.clearCF(); this.clearOF();
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
|
||||
* via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
|
||||
* However, src is technically an output, and dst is merely an input (which is why we must return
|
||||
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
|
||||
*/
|
||||
if (DEBUG && DEBUGGER) this.traceLog('MULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
|
||||
if (DEBUG && DEBUGGER) {
|
||||
if (this.dataSize == 2) {
|
||||
this.traceLog('MULW', src, dst, null, this.getPS(), this.regMDLo | (this.regMDHi << 16));
|
||||
} else {
|
||||
this.traceLog('MULD', src, dst, null, this.getPS(), this.regMDLo, this.regMDHi);
|
||||
}
|
||||
}
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulWR : this.cycleCounts.nOpCyclesMulWM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
|
|
|
|||
|
|
@ -201,8 +201,8 @@ X86.opCLTS = function CLTS()
|
|||
* op=0x0F,0x20 (MOV reg,creg)
|
||||
*
|
||||
* NOTE: Since the ModRM decoders deal only with general-purpose registers, we must move
|
||||
* the appropriate control register into a special variable (regMD16), which our helper function
|
||||
* (fnMOVMD16) will use to replace the decoder's src operand.
|
||||
* the appropriate control register into a special variable (regXX), which our helper function
|
||||
* (fnMOVxx) will use to replace the decoder's src operand.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
|
|
@ -221,16 +221,16 @@ X86.opMOVrc = function MOVrc()
|
|||
var reg = (bModRM & 0x38) >> 3;
|
||||
switch(reg) {
|
||||
case 0x0:
|
||||
this.regMD16 = this.regCR0;
|
||||
this.regXX = this.regCR0;
|
||||
break;
|
||||
case 0x1:
|
||||
this.regMD16 = this.regCR1;
|
||||
this.regXX = this.regCR1;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regMD16 = this.regCR2;
|
||||
this.regXX = this.regCR2;
|
||||
break;
|
||||
case 0x3:
|
||||
this.regMD16 = this.regCR3;
|
||||
this.regXX = this.regCR3;
|
||||
break;
|
||||
default:
|
||||
X86.opUndefined.call(this);
|
||||
|
|
@ -242,7 +242,7 @@ X86.opMOVrc = function MOVrc()
|
|||
*
|
||||
* this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
*/
|
||||
this.aOpModRegWord[bModRM].call(this, X86.fnMOVMD16);
|
||||
this.aOpModRegWord[bModRM].call(this, X86.fnMOVxx);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2057,8 +2057,8 @@ X86.opMOVrw = function MOVrw()
|
|||
* op=0x8C (MOV word,sreg)
|
||||
*
|
||||
* NOTE: Since the ModRM decoders deal only with general-purpose registers, we must move
|
||||
* the appropriate segment register into a special variable (regMD16), which our helper function
|
||||
* (fnMOVMD16) will use to replace the decoder's src operand.
|
||||
* the appropriate segment register into a special variable (regXX), which our helper function
|
||||
* (fnMOVxx) will use to replace the decoder's src operand.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
|
|
@ -2068,27 +2068,27 @@ X86.opMOVwsr = function MOVwsr()
|
|||
var reg = (bModRM & 0x38) >> 3;
|
||||
switch (reg) {
|
||||
case 0x0:
|
||||
this.regMD16 = this.segES.sel;
|
||||
this.regXX = this.segES.sel;
|
||||
break;
|
||||
case 0x1:
|
||||
this.regMD16 = this.segCS.sel;
|
||||
this.regXX = this.segCS.sel;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regMD16 = this.segSS.sel;
|
||||
this.regXX = this.segSS.sel;
|
||||
break;
|
||||
case 0x3:
|
||||
this.regMD16 = this.segDS.sel;
|
||||
this.regXX = this.segDS.sel;
|
||||
break;
|
||||
case 0x4:
|
||||
if (I386 && this.model >= X86.MODEL_80386) {
|
||||
this.regMD16 = this.segFS.sel;
|
||||
this.regXX = this.segFS.sel;
|
||||
break;
|
||||
}
|
||||
X86.opInvalid.call(this);
|
||||
break;
|
||||
case 0x5:
|
||||
if (I386 && this.model >= X86.MODEL_80386) {
|
||||
this.regMD16 = this.segGS.sel;
|
||||
this.regXX = this.segGS.sel;
|
||||
break;
|
||||
}
|
||||
/* falls through */
|
||||
|
|
@ -2100,7 +2100,7 @@ X86.opMOVwsr = function MOVwsr()
|
|||
* Like other MOV operations, the destination does not need to be read, just written.
|
||||
*/
|
||||
this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
this.aOpModMemWord[bModRM].call(this, X86.fnMOVMD16);
|
||||
this.aOpModMemWord[bModRM].call(this, X86.fnMOVxx);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2207,8 +2207,6 @@ X86.opMOVsrw = function MOVsrw()
|
|||
this.setDS(this.regEDI);
|
||||
this.regEDI = temp;
|
||||
break;
|
||||
default:
|
||||
break; // there IS no other case, but JavaScript inspections don't know that
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -3841,7 +3839,7 @@ X86.opCMC = function CMC()
|
|||
* know what the target is (only the target's value), it cannot easily work around the problem.
|
||||
*
|
||||
* A simple, albeit kludgy, solution is for fnMULb to always save its result in a special
|
||||
* "register" (eg, regMD16), which we will then put back into regEAX if it's been updated.
|
||||
* "register" (eg, regMDLo), which we will then put back into regEAX if it's been updated.
|
||||
* This also relieves us from having to decode any part of the ModRM byte, so maybe it's not
|
||||
* such a bad work-around after all.
|
||||
*
|
||||
|
|
@ -3851,9 +3849,9 @@ X86.opCMC = function CMC()
|
|||
*/
|
||||
X86.opGRP3b = function GRP3b()
|
||||
{
|
||||
this.regMD16 = -1;
|
||||
this.fMDSet = false;
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp3b, X86.fnSrcNone);
|
||||
if (this.regMD16 >= 0) this.regEAX = this.regMD16;
|
||||
if (this.fMDSet) this.regEAX = (this.regEAX & ~this.dataMask) | (this.regMDLo & this.dataMask);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -3869,7 +3867,7 @@ X86.opGRP3b = function GRP3b()
|
|||
* know what the target is (only the target's value), it cannot easily work around the problem.
|
||||
*
|
||||
* A simple, albeit kludgey, solution is for fnMULw to always save its result in a special
|
||||
* "register" (eg, regMD16/regMD32), which we will then put back into regEAX/regEDX if it's been
|
||||
* "register" (eg, regMDLo/regMDHi), which we will then put back into regEAX/regEDX if it's been
|
||||
* updated. This also relieves us from having to decode any part of the ModRM byte, so maybe
|
||||
* it's not such a bad work-around after all.
|
||||
*
|
||||
|
|
@ -3877,11 +3875,11 @@ X86.opGRP3b = function GRP3b()
|
|||
*/
|
||||
X86.opGRP3w = function GRP3w()
|
||||
{
|
||||
this.regMD16 = -1;
|
||||
this.fMDSet = false;
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp3w, X86.fnSrcNone);
|
||||
if (this.regMD16 >= 0) {
|
||||
this.regEAX = this.regMD16;
|
||||
this.regEDX = this.regMD32;
|
||||
if (this.fMDSet) {
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.regMDLo & this.dataMask);
|
||||
this.regEDX = (this.regEDX & ~this.dataMask) | (this.regMDHi & this.dataMask);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
start: mov eax,0x44332211
|
||||
mov edx,0x88776655
|
||||
shrd eax,edx,4
|
||||
mul edx
|
||||
|
||||
call dword 0xf000:start
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue