Fixed 16-bit unsigned division overflow detection

This commit is contained in:
Jeff Parsons 2015-10-31 07:31:32 -07:00
commit 8c67a50f92
4 changed files with 43 additions and 37 deletions

View file

@ -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=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=00008000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
DIVAXW EAX=00000001 EDX=00008001 PS=0000 EAX=00000001 EDX=00000000 PS=0000
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 EAX=00000001 EDX=00000000 PS=0000
DIVAXW EAX=00000001 EDX=0000FFFF 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 #DE EAX=00000001 EDX=00008001 PS=0000
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 #DE EAX=00000001 EDX=0000FFFE 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=00000001 PS=0000 EAX=00008001 EDX=00000000 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=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=00008000 PS=0000 EAX=00000001 EDX=00000000 PS=0000
DIVAXW EAX=00000001 EDX=00008001 PS=0000 EAX=00000001 EDX=00000000 PS=0000
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 EAX=00000001 EDX=00000000 PS=0000
DIVAXW EAX=00000001 EDX=0000FFFF 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 #DE EAX=00000001 EDX=00008001 PS=0000
DIVAXW EAX=00000001 EDX=0000FFFE PS=0000 #DE EAX=00000001 EDX=0000FFFE 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=00000001 PS=0000 EAX=00008001 EDX=00000000 PS=0000
DIVAXW EAX=00000002 EDX=00000002 PS=0000 #DE EAX=00000002 EDX=00000002 PS=0000

View file

@ -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.
*/
src = (this.regEDX & 0xffff) * 0x10000 + (this.regEAX & 0xffff);
var result = (src / dst)|0;
var result = (src / dst);
if (result >= 0x10000) {
X86.fnDIVOverflow.call(this);
return dst;
}
this.regMDLo = (result & 0xffff);
this.regMDHi = (src % dst) & 0xffff;
this.fMDSet = true;
}
else {
if (!X86.fnDIV32.call(this, this.regEAX, this.regEDX, dst)) {
@ -927,9 +926,10 @@ X86.fnDIVw = function(dst, src)
}
this.regMDLo |= 0;
this.regMDHi |= 0;
this.fMDSet = true;
}
this.fMDSet = true;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesDivWR : this.cycleCounts.nOpCyclesDivWM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
@ -1035,7 +1035,6 @@ X86.fnIDIVw = function(dst, src)
this.regMDLo = (result & 0xffff);
this.regMDHi = (src % div) & 0xffff;
this.fMDSet = true;
}
else {
if (!X86.fnIDIV32.call(this, this.regEAX, this.regEDX, dst)) {
@ -1044,9 +1043,10 @@ X86.fnIDIVw = function(dst, src)
}
this.regMDLo |= 0;
this.regMDHi |= 0;
this.fMDSet = true;
}
this.fMDSet = true;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIDivWR : this.cycleCounts.nOpCyclesIDivWM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
@ -1171,7 +1171,6 @@ X86.fnIMULb = function(dst, src)
var result = (((this.regEAX << 24) >> 24) * ((dst << 24) >> 24))|0;
this.regMDLo = result & 0xffff;
this.fMDSet = true;
if (result > 127 || result < -128) {
this.setCF(); this.setOF();
@ -1179,6 +1178,8 @@ X86.fnIMULb = function(dst, src)
this.clearCF(); this.clearOF();
}
this.fMDSet = true;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulBR : this.cycleCounts.nOpCyclesIMulBM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
@ -1212,7 +1213,6 @@ X86.fnIMULw = function(dst, src)
var result = (((src << 16) >> 16) * ((dst << 16) >> 16))|0;
this.regMDLo = result & 0xffff;
this.regMDHi = (result >> 16) & 0xffff;
this.fMDSet = true;
fOverflow = (result > 32767 || result < -32768);
} else {
X86.fnIMUL32.call(this, dst, this.regEAX);
@ -1225,6 +1225,8 @@ X86.fnIMULw = function(dst, src)
this.clearCF(); this.clearOF();
}
this.fMDSet = true;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesIMulWR : this.cycleCounts.nOpCyclesIMulWM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
@ -1957,7 +1959,6 @@ X86.fnMOVxx = function(dst, src)
X86.fnMULb = function(dst, src)
{
this.regMDLo = ((this.regEAX & 0xff) * dst) & 0xffff;
this.fMDSet = true;
if (this.regMDLo & 0xff00) {
this.setCF(); this.setOF();
@ -1965,6 +1966,8 @@ X86.fnMULb = function(dst, src)
this.clearCF(); this.clearOF();
}
this.fMDSet = true;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulBR : this.cycleCounts.nOpCyclesMulBM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
@ -1984,24 +1987,22 @@ X86.fnMUL32 = function(dst, src)
if (!(dst & ~0xffff) && !(src & ~0xffff)) {
this.regMDLo = (dst * src)|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 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));
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.regMDLo = (mul16 << 16) | (mul00 & 0xffff);
this.regMDHi = mul32|0;
this.fMDSet = true;
this.regMDLo = (mul16 << 16) | (mul00 & 0xffff);
this.regMDHi = mul32|0;
}
};
/**
@ -2021,14 +2022,13 @@ X86.fnMULw = function(dst, src)
var result = (src * dst)|0;
this.regMDLo = result & 0xffff;
this.regMDHi = (result >> 16) & 0xffff;
this.fMDSet = true;
} else {
X86.fnMUL32.call(this, dst, this.regEAX);
if (this.stepping == X86.STEPPING_80386_B1) {
if (this.regEAX == 0x0417A000 && dst == 0x00000081) {
/*
* 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.
*/
@ -2044,6 +2044,8 @@ X86.fnMULw = function(dst, src)
this.clearCF(); this.clearOF();
}
this.fMDSet = true;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.cycleCounts.nOpCyclesMulWR : this.cycleCounts.nOpCyclesMulWM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;

View file

@ -4169,7 +4169,9 @@ X86.opGRP3b = function()
{
this.fMDSet = false;
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
* 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
* 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.

View file

@ -793,6 +793,8 @@ strPS: db "PS=",0
strDE: db "#DE ",0 ; when this is displayed, it indicates a Divide Error exception
achSize db "BWD"
ALLOPS equ 1
tableOps:
defOp "ADD",add,al,dl,none,TYPE_ARITH
defOp "ADD",add,ax,dx,none,TYPE_ARITH