aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Celio <celio@eecs.berkeley.edu>2012-09-10 17:51:35 -0700
committerChristopher Celio <celio@eecs.berkeley.edu>2012-09-10 17:51:35 -0700
commit79e238eff793adf04017519e10b30cc212f4c4bb (patch)
treed4f5b584e68c321a2ca6e56ff5724fbc9b480e0b
parentdd32a44bc07fe36d8c777e745b0b509ce2e55a2c (diff)
downloadpk-79e238eff793adf04017519e10b30cc212f4c4bb.zip
pk-79e238eff793adf04017519e10b30cc212f4c4bb.tar.gz
pk-79e238eff793adf04017519e10b30cc212f4c4bb.tar.bz2
div/rem bug fixes.
-rw-r--r--pk/int.c25
-rwxr-xr-xsoftint/divu.c56
-rwxr-xr-xsoftint/remu.c50
3 files changed, 96 insertions, 35 deletions
diff --git a/pk/int.c b/pk/int.c
index 1424e73..d7ced91 100644
--- a/pk/int.c
+++ b/pk/int.c
@@ -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;
}