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=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

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. * 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;

View file

@ -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.

View file

@ -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