Browse Source

div/rem bug fixes.

eos20
Christopher Celio 14 years ago
parent
commit
79e238eff7
  1. 25
      pk/int.c
  2. 56
      softint/divu.c
  3. 50
      softint/remu.c

25
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))

56
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;
}

50
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;
}

Loading…
Cancel
Save