diff options
author | Christopher Celio <celio@eecs.berkeley.edu> | 2012-09-10 17:51:35 -0700 |
---|---|---|
committer | Christopher Celio <celio@eecs.berkeley.edu> | 2012-09-10 17:51:35 -0700 |
commit | 79e238eff793adf04017519e10b30cc212f4c4bb (patch) | |
tree | d4f5b584e68c321a2ca6e56ff5724fbc9b480e0b | |
parent | dd32a44bc07fe36d8c777e745b0b509ce2e55a2c (diff) | |
download | pk-79e238eff793adf04017519e10b30cc212f4c4bb.zip pk-79e238eff793adf04017519e10b30cc212f4c4bb.tar.gz pk-79e238eff793adf04017519e10b30cc212f4c4bb.tar.bz2 |
div/rem bug fixes.
-rw-r--r-- | pk/int.c | 25 | ||||
-rwxr-xr-x | softint/divu.c | 56 | ||||
-rwxr-xr-x | softint/remu.c | 50 |
3 files changed, 96 insertions, 35 deletions
@@ -31,7 +31,26 @@ int emulate_int(trapframe_t* tf) { if(noisy) printk("emulating div\n"); - XRD = softint_divu(xrs1, xrs2); + + int num_negative = 0; + + if ((signed long) xrs1 < 0) + { + xrs1 = -xrs1; + num_negative++; + } + + if ((signed long) xrs2 < 0) + { + xrs2 = -xrs2; + num_negative++; + } + + unsigned long res = softint_divu(xrs1, xrs2); + if (num_negative == 1) + XRD = -res; + else + XRD = res; } else if(IS_INSN(DIVU)) { @@ -49,6 +68,10 @@ int emulate_int(trapframe_t* tf) { if(noisy) printk("emulating rem\n"); + + if ((signed long) xrs1 < 0) {xrs1 = -xrs1;} + if ((signed long) xrs2 < 0) {xrs2 = -xrs2;} + XRD = softint_remu(xrs1, xrs2); } else if(IS_INSN(REMU)) diff --git a/softint/divu.c b/softint/divu.c index 1779a0b..cf74876 100755 --- a/softint/divu.c +++ b/softint/divu.c @@ -4,42 +4,62 @@ long
softint_divu( long rs1, long rs2 )
{
- // only designed to work for mabi=32
// quotient = dividend / divisor + remainder
- unsigned long long dividend = rs1;
- unsigned long long divisor = rs2;
+ unsigned long dividend = rs1;
+ unsigned long divisor = rs2;
+ int msb = (sizeof(long) << 3) - 1;
if (divisor == 0) return -1;
- unsigned long long temp_dividend = dividend;
- unsigned long long temp_divisor = divisor;
+ unsigned long temp_dividend = dividend;
+ unsigned long temp_divisor = divisor;
- unsigned long long quotient = 0;
+ unsigned long quotient = 0;
- for (int i=0; i <= 32; i++)
+ for (int i=0; i <= msb; i++)
{
- unsigned long long temp_quotient = 1;
+ unsigned long temp_quotient = 1;
if (temp_divisor == temp_dividend) { quotient += 1; break;}
else if (temp_dividend < temp_divisor) { quotient += 0; break; }
- while (temp_divisor <= temp_dividend && temp_quotient != 0)
- {
- temp_divisor = temp_divisor << 1;
- temp_quotient = temp_quotient << 1;
- }
- temp_divisor = temp_divisor >> 1;
- temp_quotient = temp_quotient >> 1;
-
-
+ // check for corner-case when (msb of dividend)==1
+ if ((temp_dividend & (1 << msb)) == (1 << msb))
+ {
+ int hi = msb, lo = 0;
+ for (int i=msb; i >= 0; i--)
+ {
+ unsigned int mask = 1 << i;
+ if ((mask & temp_divisor) == mask)
+ {
+ lo = i;
+ break;
+ }
+ }
+ temp_divisor = temp_divisor << (hi - lo - 1);
+ temp_quotient = temp_quotient << (hi - lo - 1);
+ }
+ else
+ {
+ while (temp_divisor <= temp_dividend)
+ {
+ temp_divisor = temp_divisor << 1;
+ temp_quotient = temp_quotient << 1;
+ }
+
+ temp_divisor = temp_divisor >> 1;
+ temp_quotient = temp_quotient >> 1;
+ }
+
+
temp_dividend = temp_dividend - temp_divisor;
temp_divisor = divisor;
quotient += temp_quotient;
}
- return (long) quotient;
+ return quotient;
}
diff --git a/softint/remu.c b/softint/remu.c index b7afc54..eca4781 100755 --- a/softint/remu.c +++ b/softint/remu.c @@ -4,35 +4,53 @@ long
softint_remu( long rs1, long rs2 )
{
- // only designed to work for mabi=32
// quotient = dividend / divisor + remainder
-
- unsigned long long dividend = rs1;
- unsigned long long divisor = rs2;
+ unsigned long dividend = rs1;
+ unsigned long divisor = rs2;
+
+ int msb = (sizeof(long) << 3) - 1;
if (divisor == 0) { return dividend; }
- long long temp_dividend = dividend;
- long long temp_divisor = divisor;
+ unsigned long temp_dividend = dividend;
+ unsigned long temp_divisor = divisor;
- for (int i=0; i <= 32; i++)
+ for (int i=0; i <= msb; i++)
{
if (temp_divisor == temp_dividend) { return 0; }
- else if (temp_dividend < temp_divisor) { return (long) temp_dividend; }
-
-
- while (temp_divisor <= temp_dividend && temp_divisor != 0)
- {
- temp_divisor = temp_divisor << 1;
+ else if (temp_dividend < temp_divisor) { return temp_dividend; }
+
+
+ // check for corner-case when (msb of dividend)==1
+ if ((temp_dividend & (1 << msb)) == (1 << msb))
+ {
+ int hi = msb, lo = 0;
+ for (int i=msb; i >= 0; i--)
+ {
+ unsigned int mask = 1 << i;
+ if ((mask & temp_divisor) == mask)
+ {
+ lo = i;
+ break;
+ }
+ }
+ temp_divisor = temp_divisor << (hi - lo - 1);
+ }
+ else
+ {
+ while ( (unsigned long) temp_divisor <= (unsigned long) temp_dividend)
+ {
+ temp_divisor = temp_divisor << 1;
+ }
+
+ temp_divisor = temp_divisor >> 1;
}
- temp_divisor = temp_divisor >> 1;
-
temp_dividend = temp_dividend - temp_divisor;
temp_divisor = divisor;
}
- return (long) temp_dividend;
+ return temp_dividend;
}
|