Fixed 16-bit unsigned division overflow detection
This commit is contained in:
parent
a22bf5dc85
commit
8c67a50f92
4 changed files with 43 additions and 37 deletions
|
|
@ -22902,10 +22902,10 @@ DIVAXW EAX=00000001 EDX=00004000 PS=0000 #DE EAX=00000001 EDX=00004000 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00004001 PS=0000 #DE EAX=00000001 EDX=00004001 PS=0000
|
DIVAXW EAX=00000001 EDX=00004001 PS=0000 #DE EAX=00000001 EDX=00004001 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00007FFE PS=0000 #DE EAX=00000001 EDX=00007FFE PS=0000
|
DIVAXW EAX=00000001 EDX=00007FFE PS=0000 #DE EAX=00000001 EDX=00007FFE PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00007FFF PS=0000 #DE EAX=00000001 EDX=00007FFF PS=0000
|
DIVAXW EAX=00000001 EDX=00007FFF PS=0000 #DE EAX=00000001 EDX=00007FFF PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00008000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=00008000 PS=0000 #DE EAX=00000001 EDX=00008000 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00008001 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=00008001 PS=0000 #DE EAX=00000001 EDX=00008001 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 #DE EAX=00000001 EDX=0000FFFE PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=0000FFFF PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=0000FFFF PS=0000 #DE EAX=00000001 EDX=0000FFFF PS=0000
|
||||||
DIVAXW EAX=00000002 EDX=00000000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000002 EDX=00000000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
||||||
DIVAXW EAX=00000002 EDX=00000001 PS=0000 EAX=00008001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000002 EDX=00000001 PS=0000 EAX=00008001 EDX=00000000 PS=0000
|
||||||
DIVAXW EAX=00000002 EDX=00000002 PS=0000 #DE EAX=00000002 EDX=00000002 PS=0000
|
DIVAXW EAX=00000002 EDX=00000002 PS=0000 #DE EAX=00000002 EDX=00000002 PS=0000
|
||||||
|
|
@ -23190,10 +23190,10 @@ DIVAXW EAX=00000001 EDX=00004000 PS=0000 #DE EAX=00000001 EDX=00004000 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00004001 PS=0000 #DE EAX=00000001 EDX=00004001 PS=0000
|
DIVAXW EAX=00000001 EDX=00004001 PS=0000 #DE EAX=00000001 EDX=00004001 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00007FFE PS=0000 #DE EAX=00000001 EDX=00007FFE PS=0000
|
DIVAXW EAX=00000001 EDX=00007FFE PS=0000 #DE EAX=00000001 EDX=00007FFE PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00007FFF PS=0000 #DE EAX=00000001 EDX=00007FFF PS=0000
|
DIVAXW EAX=00000001 EDX=00007FFF PS=0000 #DE EAX=00000001 EDX=00007FFF PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00008000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=00008000 PS=0000 #DE EAX=00000001 EDX=00008000 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=00008001 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=00008001 PS=0000 #DE EAX=00000001 EDX=00008001 PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 #DE EAX=00000001 EDX=0000FFFE PS=0000
|
||||||
DIVAXW EAX=00000001 EDX=0000FFFF PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000001 EDX=0000FFFF PS=0000 #DE EAX=00000001 EDX=0000FFFF PS=0000
|
||||||
DIVAXW EAX=00000002 EDX=00000000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000002 EDX=00000000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
|
||||||
DIVAXW EAX=00000002 EDX=00000001 PS=0000 EAX=00008001 EDX=00000000 PS=0000
|
DIVAXW EAX=00000002 EDX=00000001 PS=0000 EAX=00008001 EDX=00000000 PS=0000
|
||||||
DIVAXW EAX=00000002 EDX=00000002 PS=0000 #DE EAX=00000002 EDX=00000002 PS=0000
|
DIVAXW EAX=00000002 EDX=00000002 PS=0000 #DE EAX=00000002 EDX=00000002 PS=0000
|
||||||
|
|
|
||||||
|
|
@ -911,14 +911,13 @@ X86.fnDIVw = function(dst, src)
|
||||||
* to force JavaScript to create a floating-point value that won't suffer from 32-bit-math side-effects.
|
* to force JavaScript to create a floating-point value that won't suffer from 32-bit-math side-effects.
|
||||||
*/
|
*/
|
||||||
src = (this.regEDX & 0xffff) * 0x10000 + (this.regEAX & 0xffff);
|
src = (this.regEDX & 0xffff) * 0x10000 + (this.regEAX & 0xffff);
|
||||||
var result = (src / dst)|0;
|
var result = (src / dst);
|
||||||
if (result >= 0x10000) {
|
if (result >= 0x10000) {
|
||||||
X86.fnDIVOverflow.call(this);
|
X86.fnDIVOverflow.call(this);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
this.regMDLo = (result & 0xffff);
|
this.regMDLo = (result & 0xffff);
|
||||||
this.regMDHi = (src % dst) & 0xffff;
|
this.regMDHi = (src % dst) & 0xffff;
|
||||||
this.fMDSet = true;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!X86.fnDIV32.call(this, this.regEAX, this.regEDX, dst)) {
|
if (!X86.fnDIV32.call(this, this.regEAX, this.regEDX, dst)) {
|
||||||
|
|
@ -927,9 +926,10 @@ X86.fnDIVw = function(dst, src)
|
||||||
}
|
}
|
||||||
this.regMDLo |= 0;
|
this.regMDLo |= 0;
|
||||||
this.regMDHi |= 0;
|
this.regMDHi |= 0;
|
||||||
this.fMDSet = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fMDSet = true;
|
||||||
|
|
||||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesDivWR : this.cycleCounts.nOpCyclesDivWM);
|
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesDivWR : this.cycleCounts.nOpCyclesDivWM);
|
||||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||||
return dst;
|
return dst;
|
||||||
|
|
@ -1035,7 +1035,6 @@ X86.fnIDIVw = function(dst, src)
|
||||||
|
|
||||||
this.regMDLo = (result & 0xffff);
|
this.regMDLo = (result & 0xffff);
|
||||||
this.regMDHi = (src % div) & 0xffff;
|
this.regMDHi = (src % div) & 0xffff;
|
||||||
this.fMDSet = true;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!X86.fnIDIV32.call(this, this.regEAX, this.regEDX, dst)) {
|
if (!X86.fnIDIV32.call(this, this.regEAX, this.regEDX, dst)) {
|
||||||
|
|
@ -1044,9 +1043,10 @@ X86.fnIDIVw = function(dst, src)
|
||||||
}
|
}
|
||||||
this.regMDLo |= 0;
|
this.regMDLo |= 0;
|
||||||
this.regMDHi |= 0;
|
this.regMDHi |= 0;
|
||||||
this.fMDSet = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fMDSet = true;
|
||||||
|
|
||||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIDivWR : this.cycleCounts.nOpCyclesIDivWM);
|
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIDivWR : this.cycleCounts.nOpCyclesIDivWM);
|
||||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||||
return dst;
|
return dst;
|
||||||
|
|
@ -1171,7 +1171,6 @@ X86.fnIMULb = function(dst, src)
|
||||||
var result = (((this.regEAX << 24) >> 24) * ((dst << 24) >> 24))|0;
|
var result = (((this.regEAX << 24) >> 24) * ((dst << 24) >> 24))|0;
|
||||||
|
|
||||||
this.regMDLo = result & 0xffff;
|
this.regMDLo = result & 0xffff;
|
||||||
this.fMDSet = true;
|
|
||||||
|
|
||||||
if (result > 127 || result < -128) {
|
if (result > 127 || result < -128) {
|
||||||
this.setCF(); this.setOF();
|
this.setCF(); this.setOF();
|
||||||
|
|
@ -1179,6 +1178,8 @@ X86.fnIMULb = function(dst, src)
|
||||||
this.clearCF(); this.clearOF();
|
this.clearCF(); this.clearOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fMDSet = true;
|
||||||
|
|
||||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulBR : this.cycleCounts.nOpCyclesIMulBM);
|
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulBR : this.cycleCounts.nOpCyclesIMulBM);
|
||||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||||
return dst;
|
return dst;
|
||||||
|
|
@ -1212,7 +1213,6 @@ X86.fnIMULw = function(dst, src)
|
||||||
var result = (((src << 16) >> 16) * ((dst << 16) >> 16))|0;
|
var result = (((src << 16) >> 16) * ((dst << 16) >> 16))|0;
|
||||||
this.regMDLo = result & 0xffff;
|
this.regMDLo = result & 0xffff;
|
||||||
this.regMDHi = (result >> 16) & 0xffff;
|
this.regMDHi = (result >> 16) & 0xffff;
|
||||||
this.fMDSet = true;
|
|
||||||
fOverflow = (result > 32767 || result < -32768);
|
fOverflow = (result > 32767 || result < -32768);
|
||||||
} else {
|
} else {
|
||||||
X86.fnIMUL32.call(this, dst, this.regEAX);
|
X86.fnIMUL32.call(this, dst, this.regEAX);
|
||||||
|
|
@ -1225,6 +1225,8 @@ X86.fnIMULw = function(dst, src)
|
||||||
this.clearCF(); this.clearOF();
|
this.clearCF(); this.clearOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fMDSet = true;
|
||||||
|
|
||||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulWR : this.cycleCounts.nOpCyclesIMulWM);
|
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulWR : this.cycleCounts.nOpCyclesIMulWM);
|
||||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||||
return dst;
|
return dst;
|
||||||
|
|
@ -1957,7 +1959,6 @@ X86.fnMOVxx = function(dst, src)
|
||||||
X86.fnMULb = function(dst, src)
|
X86.fnMULb = function(dst, src)
|
||||||
{
|
{
|
||||||
this.regMDLo = ((this.regEAX & 0xff) * dst) & 0xffff;
|
this.regMDLo = ((this.regEAX & 0xff) * dst) & 0xffff;
|
||||||
this.fMDSet = true;
|
|
||||||
|
|
||||||
if (this.regMDLo & 0xff00) {
|
if (this.regMDLo & 0xff00) {
|
||||||
this.setCF(); this.setOF();
|
this.setCF(); this.setOF();
|
||||||
|
|
@ -1965,6 +1966,8 @@ X86.fnMULb = function(dst, src)
|
||||||
this.clearCF(); this.clearOF();
|
this.clearCF(); this.clearOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fMDSet = true;
|
||||||
|
|
||||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulBR : this.cycleCounts.nOpCyclesMulBM);
|
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulBR : this.cycleCounts.nOpCyclesMulBM);
|
||||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||||
return dst;
|
return dst;
|
||||||
|
|
@ -1984,24 +1987,22 @@ X86.fnMUL32 = function(dst, src)
|
||||||
if (!(dst & ~0xffff) && !(src & ~0xffff)) {
|
if (!(dst & ~0xffff) && !(src & ~0xffff)) {
|
||||||
this.regMDLo = (dst * src)|0;
|
this.regMDLo = (dst * src)|0;
|
||||||
this.regMDHi = 0;
|
this.regMDHi = 0;
|
||||||
this.fMDSet = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
var srcLo = src & 0xffff;
|
||||||
|
var srcHi = src >>> 16;
|
||||||
|
var dstLo = dst & 0xffff;
|
||||||
|
var dstHi = dst >>> 16;
|
||||||
|
|
||||||
var srcLo = src & 0xffff;
|
var mul00 = srcLo * dstLo;
|
||||||
var srcHi = src >>> 16;
|
var mul16 = ((mul00 >>> 16) + (srcHi * dstLo));
|
||||||
var dstLo = dst & 0xffff;
|
var mul32 = mul16 >>> 16;
|
||||||
var dstHi = dst >>> 16;
|
mul16 = ((mul16 & 0xffff) + (srcLo * dstHi));
|
||||||
|
mul32 += ((mul16 >>> 16) + (srcHi * dstHi));
|
||||||
|
|
||||||
var mul00 = srcLo * dstLo;
|
this.regMDLo = (mul16 << 16) | (mul00 & 0xffff);
|
||||||
var mul16 = ((mul00 >>> 16) + (srcHi * dstLo));
|
this.regMDHi = mul32|0;
|
||||||
var mul32 = mul16 >>> 16;
|
}
|
||||||
mul16 = ((mul16 & 0xffff) + (srcLo * dstHi));
|
|
||||||
mul32 += ((mul16 >>> 16) + (srcHi * dstHi));
|
|
||||||
|
|
||||||
this.regMDLo = (mul16 << 16) | (mul00 & 0xffff);
|
|
||||||
this.regMDHi = mul32|0;
|
|
||||||
this.fMDSet = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2021,14 +2022,13 @@ X86.fnMULw = function(dst, src)
|
||||||
var result = (src * dst)|0;
|
var result = (src * dst)|0;
|
||||||
this.regMDLo = result & 0xffff;
|
this.regMDLo = result & 0xffff;
|
||||||
this.regMDHi = (result >> 16) & 0xffff;
|
this.regMDHi = (result >> 16) & 0xffff;
|
||||||
this.fMDSet = true;
|
|
||||||
} else {
|
} else {
|
||||||
X86.fnMUL32.call(this, dst, this.regEAX);
|
X86.fnMUL32.call(this, dst, this.regEAX);
|
||||||
if (this.stepping == X86.STEPPING_80386_B1) {
|
if (this.stepping == X86.STEPPING_80386_B1) {
|
||||||
if (this.regEAX == 0x0417A000 && dst == 0x00000081) {
|
if (this.regEAX == 0x0417A000 && dst == 0x00000081) {
|
||||||
/*
|
/*
|
||||||
* Normally, the result should be 0x20FE7A000 (ie, regMDHi should be 0x2).
|
* Normally, the result should be 0x20FE7A000 (ie, regMDHi should be 0x2).
|
||||||
* I'm not sure what a typical failure looked like, so I'll just set regMDHi to 0.
|
* I'm not sure what a typical B1 stepping failure looked like, so I'll set regMDHi to 0.
|
||||||
*
|
*
|
||||||
* If you want a B1 stepping without this 32-bit multiplication flaw, select the B2 stepping.
|
* If you want a B1 stepping without this 32-bit multiplication flaw, select the B2 stepping.
|
||||||
*/
|
*/
|
||||||
|
|
@ -2044,6 +2044,8 @@ X86.fnMULw = function(dst, src)
|
||||||
this.clearCF(); this.clearOF();
|
this.clearCF(); this.clearOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fMDSet = true;
|
||||||
|
|
||||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulWR : this.cycleCounts.nOpCyclesMulWM);
|
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulWR : this.cycleCounts.nOpCyclesMulWM);
|
||||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||||
return dst;
|
return dst;
|
||||||
|
|
|
||||||
|
|
@ -4169,7 +4169,9 @@ X86.opGRP3b = function()
|
||||||
{
|
{
|
||||||
this.fMDSet = false;
|
this.fMDSet = false;
|
||||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp3b, X86.fnSRCNone);
|
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp3b, X86.fnSRCNone);
|
||||||
if (this.fMDSet) this.regEAX = (this.regEAX & ~this.maskData) | (this.regMDLo & this.maskData);
|
if (this.fMDSet) {
|
||||||
|
this.regEAX = (this.regEAX & ~this.maskData) | (this.regMDLo & this.maskData);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -4184,7 +4186,7 @@ X86.opGRP3b = function()
|
||||||
* return value back into AX or DX, undoing fnMULw's update of DX:AX. And since fnMULw doesn't
|
* return value back into AX or DX, undoing fnMULw's update of DX:AX. And since fnMULw doesn't
|
||||||
* know what the target is (only the target's value), it cannot easily work around the problem.
|
* 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
|
* A simple, albeit kludgy, solution is for fnMULw to always save its result in a special
|
||||||
* "register" (eg, regMDLo/regMDHi), 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
|
* 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.
|
* it's not such a bad work-around after all.
|
||||||
|
|
|
||||||
|
|
@ -793,6 +793,8 @@ strPS: db "PS=",0
|
||||||
strDE: db "#DE ",0 ; when this is displayed, it indicates a Divide Error exception
|
strDE: db "#DE ",0 ; when this is displayed, it indicates a Divide Error exception
|
||||||
achSize db "BWD"
|
achSize db "BWD"
|
||||||
|
|
||||||
|
ALLOPS equ 1
|
||||||
|
|
||||||
tableOps:
|
tableOps:
|
||||||
defOp "ADD",add,al,dl,none,TYPE_ARITH
|
defOp "ADD",add,al,dl,none,TYPE_ARITH
|
||||||
defOp "ADD",add,ax,dx,none,TYPE_ARITH
|
defOp "ADD",add,ax,dx,none,TYPE_ARITH
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue