Ver código fonte

Added hardware signed and unsigned integer division and modulo. Created simple integer calculator to test. Updated several programs and BDOS to use new division hardware while keeping software calculation as legacy functions.

bart 1 ano atrás
pai
commit
69d109e653

+ 132 - 66
BCC/BDOS/lib/math.c

@@ -1,100 +1,166 @@
 /*
 * Math library
-* Contains functions math operation that are not directly supported by the hardware
+* Contains functions math operation that are not directly supported by the ALU
 */
 
-// Signed Division and Modulo without / and %
-word MATH_divmod(word dividend, word divisor, word* rem)
+// Divide two signed integer numbers using MU
+word MATH_div(word dividend, word divisor)
 {
-    word quotient = 1;
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 1 r2 r5 ; write b to divider and perform signed division\n"
+    "read 1 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    word neg = 1;
-    if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
-        neg = -1;
+// Modulo from division of two signed integer numbers using MU
+word MATH_mod(word dividend, word divisor)
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 3 r2 r5 ; write b to divider and perform signed modulo\n"
+    "read 3 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    // Convert to positive
-    word tempdividend = (dividend < 0) ? -dividend : dividend;
-    word tempdivisor = (divisor < 0) ? -divisor : divisor;
+// Divide two unsigned integer numbers using MU
+word MATH_divU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 2 r2 r5 ; write b to divider and perform unsigned division\n"
+    "read 2 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    if (tempdivisor == tempdividend) {
-        *rem = 0;
-        return 1*neg;
-    }
-    else if (tempdividend < tempdivisor) {
-        if (dividend < 0)
-            *rem = tempdividend*neg;
-        else
-            *rem = tempdividend;
-        return 0;
-    }
-    while (tempdivisor<<1 <= tempdividend)
-    {
-        tempdivisor = tempdivisor << 1;
-        quotient = quotient << 1;
-    }
+// Modulo from division of two unsigned integer numbers using MU
+word MATH_modU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 4 r2 r5 ; write b to divider and perform unsiged modulo\n"
+    "read 4 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    // Call division recursively
-    if(dividend < 0)
-        quotient = quotient*neg + MATH_divmod(-(tempdividend-tempdivisor), divisor, rem);
+// Signed Division and Modulo without / and %
+word MATH_SW_divmod(word dividend, word divisor, word* rem)
+{
+  word quotient = 1;
+
+  word neg = 1;
+  if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
+    neg = -1;
+
+  // Convert to positive
+  word tempdividend = (dividend < 0) ? -dividend : dividend;
+  word tempdivisor = (divisor < 0) ? -divisor : divisor;
+
+  if (tempdivisor == tempdividend) {
+    *rem = 0;
+    return 1*neg;
+  }
+  else if (tempdividend < tempdivisor) {
+    if (dividend < 0)
+      *rem = tempdividend*neg;
     else
-        quotient = quotient*neg + MATH_divmod(tempdividend-tempdivisor, divisor, rem);
-     return quotient;
+      *rem = tempdividend;
+    return 0;
+  }
+  while (tempdivisor<<1 <= tempdividend)
+  {
+    tempdivisor = tempdivisor << 1;
+    quotient = quotient << 1;
+  }
+
+  // Call division recursively
+  if(dividend < 0)
+    quotient = quotient*neg + MATH_SW_divmod(-(tempdividend-tempdivisor), divisor, rem);
+  else
+    quotient = quotient*neg + MATH_SW_divmod(tempdividend-tempdivisor, divisor, rem);
+   return quotient;
 }
 
-word MATH_div(word dividend, word divisor)
+word MATH_SW_div(word dividend, word divisor)
 {
-    word rem = 0;
-    return MATH_divmod(dividend, divisor, &rem);
+  word rem = 0;
+  return MATH_SW_divmod(dividend, divisor, &rem);
 }
 
-word MATH_mod(word dividend, word divisor)
+word MATH_SW_mod(word dividend, word divisor)
 {
-    word rem = 0;
-    MATH_divmod(dividend, divisor, &rem);
-    return rem;
+  word rem = 0;
+  MATH_SW_divmod(dividend, divisor, &rem);
+  return rem;
 }
 
 
 // Unsigned Division and Modulo without / and %
-word MATH_divmodU(word dividend, word divisor, word mod)
+word MATH_SW_divmodU(word dividend, word divisor, word mod)
 {
-    word quotient = 0;
-    word remainder = 0;
+  word quotient = 0;
+  word remainder = 0;
+
+  if(divisor == 0) 
+    return 0;
 
-    if(divisor == 0) 
-        return 0;
+  word i;
+  for(i = 31 ; i >= 0 ; i--)
+  {
+    quotient = quotient << 1;
+    remainder = remainder << 1;
+    remainder = remainder | ((unsigned) (dividend & (1 << i)) >> i);
 
-    word i;
-    for(i = 31 ; i >= 0 ; i--)
+    if((unsigned int) remainder >= (unsigned int) divisor)
     {
-        quotient = quotient << 1;
-        remainder = remainder << 1;
-        remainder = remainder | ((unsigned) (dividend & (1 << i)) >> i);
-
-        if((unsigned int) remainder >= (unsigned int) divisor)
-        {
-            remainder = remainder - divisor;
-            quotient = quotient | 1;
-        }
-
-        if (i == 0)
-            if (mod == 1)
-                return remainder;
-            else
-                return quotient;
+      remainder = remainder - divisor;
+      quotient = quotient | 1;
     }
 
-    return 0;
+    if (i == 0)
+      if (mod == 1)
+        return remainder;
+      else
+        return quotient;
+  }
+
+  return 0;
 }
 
 // Unsigned positive integer division
-word MATH_divU(word dividend, word divisor) 
+word MATH_SW_divU(word dividend, word divisor) 
 {
-    return MATH_divmodU(dividend, divisor, 0);
+  return MATH_SW_divmodU(dividend, divisor, 0);
 }
 
 // Unsigned positive integer modulo
-word MATH_modU(word dividend, word divisor) 
+word MATH_SW_modU(word dividend, word divisor) 
+{
+  return MATH_SW_divmodU(dividend, divisor, 1);
+}
+
+
+// Returns absolute value
+word MATH_abs(word x)
 {
-    return MATH_divmodU(dividend, divisor, 1);
-}
+  if (x >= 0)
+    return x;
+  else
+    return -x;
+}

+ 132 - 66
BCC/BareMetal/lib/math.c

@@ -1,100 +1,166 @@
 /*
 * Math library
-* Contains functions math operation that are not directly supported by the hardware
+* Contains functions math operation that are not directly supported by the ALU
 */
 
-// Signed Division and Modulo without / and %
-word MATH_divmod(word dividend, word divisor, word* rem)
+// Divide two signed integer numbers using MU
+word MATH_div(word dividend, word divisor)
 {
-    word quotient = 1;
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 1 r2 r5 ; write b to divider and perform signed division\n"
+    "read 1 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    word neg = 1;
-    if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
-        neg = -1;
+// Modulo from division of two signed integer numbers using MU
+word MATH_mod(word dividend, word divisor)
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 3 r2 r5 ; write b to divider and perform signed modulo\n"
+    "read 3 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    // Convert to positive
-    word tempdividend = (dividend < 0) ? -dividend : dividend;
-    word tempdivisor = (divisor < 0) ? -divisor : divisor;
+// Divide two unsigned integer numbers using MU
+word MATH_divU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 2 r2 r5 ; write b to divider and perform unsigned division\n"
+    "read 2 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    if (tempdivisor == tempdividend) {
-        *rem = 0;
-        return 1*neg;
-    }
-    else if (tempdividend < tempdivisor) {
-        if (dividend < 0)
-            *rem = tempdividend*neg;
-        else
-            *rem = tempdividend;
-        return 0;
-    }
-    while (tempdivisor<<1 <= tempdividend)
-    {
-        tempdivisor = tempdivisor << 1;
-        quotient = quotient << 1;
-    }
+// Modulo from division of two unsigned integer numbers using MU
+word MATH_modU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 4 r2 r5 ; write b to divider and perform unsiged modulo\n"
+    "read 4 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    // Call division recursively
-    if(dividend < 0)
-        quotient = quotient*neg + MATH_divmod(-(tempdividend-tempdivisor), divisor, rem);
+// Signed Division and Modulo without / and %
+word MATH_SW_divmod(word dividend, word divisor, word* rem)
+{
+  word quotient = 1;
+
+  word neg = 1;
+  if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
+    neg = -1;
+
+  // Convert to positive
+  word tempdividend = (dividend < 0) ? -dividend : dividend;
+  word tempdivisor = (divisor < 0) ? -divisor : divisor;
+
+  if (tempdivisor == tempdividend) {
+    *rem = 0;
+    return 1*neg;
+  }
+  else if (tempdividend < tempdivisor) {
+    if (dividend < 0)
+      *rem = tempdividend*neg;
     else
-        quotient = quotient*neg + MATH_divmod(tempdividend-tempdivisor, divisor, rem);
-     return quotient;
+      *rem = tempdividend;
+    return 0;
+  }
+  while (tempdivisor<<1 <= tempdividend)
+  {
+    tempdivisor = tempdivisor << 1;
+    quotient = quotient << 1;
+  }
+
+  // Call division recursively
+  if(dividend < 0)
+    quotient = quotient*neg + MATH_SW_divmod(-(tempdividend-tempdivisor), divisor, rem);
+  else
+    quotient = quotient*neg + MATH_SW_divmod(tempdividend-tempdivisor, divisor, rem);
+   return quotient;
 }
 
-word MATH_div(word dividend, word divisor)
+word MATH_SW_div(word dividend, word divisor)
 {
-    word rem = 0;
-    return MATH_divmod(dividend, divisor, &rem);
+  word rem = 0;
+  return MATH_SW_divmod(dividend, divisor, &rem);
 }
 
-word MATH_mod(word dividend, word divisor)
+word MATH_SW_mod(word dividend, word divisor)
 {
-    word rem = 0;
-    MATH_divmod(dividend, divisor, &rem);
-    return rem;
+  word rem = 0;
+  MATH_SW_divmod(dividend, divisor, &rem);
+  return rem;
 }
 
 
 // Unsigned Division and Modulo without / and %
-word MATH_divmodU(word dividend, word divisor, word mod)
+word MATH_SW_divmodU(word dividend, word divisor, word mod)
 {
-    word quotient = 0;
-    word remainder = 0;
+  word quotient = 0;
+  word remainder = 0;
+
+  if(divisor == 0) 
+    return 0;
 
-    if(divisor == 0) 
-        return 0;
+  word i;
+  for(i = 31 ; i >= 0 ; i--)
+  {
+    quotient = quotient << 1;
+    remainder = remainder << 1;
+    remainder = remainder | ((unsigned) (dividend & (1 << i)) >> i);
 
-    word i;
-    for(i = 31 ; i >= 0 ; i--)
+    if((unsigned int) remainder >= (unsigned int) divisor)
     {
-        quotient = quotient << 1;
-        remainder = remainder << 1;
-        remainder = remainder | ((dividend & (1 << i)) >> i);
-
-        if((unsigned int) remainder >= (unsigned int) divisor)
-        {
-            remainder = remainder - divisor;
-            quotient = quotient | 1;
-        }
-
-        if (i == 0)
-            if (mod == 1)
-                return remainder;
-            else
-                return quotient;
+      remainder = remainder - divisor;
+      quotient = quotient | 1;
     }
 
-    return 0;
+    if (i == 0)
+      if (mod == 1)
+        return remainder;
+      else
+        return quotient;
+  }
+
+  return 0;
 }
 
 // Unsigned positive integer division
-word MATH_divU(word dividend, word divisor) 
+word MATH_SW_divU(word dividend, word divisor) 
 {
-    return MATH_divmodU(dividend, divisor, 0);
+  return MATH_SW_divmodU(dividend, divisor, 0);
 }
 
 // Unsigned positive integer modulo
-word MATH_modU(word dividend, word divisor) 
+word MATH_SW_modU(word dividend, word divisor) 
+{
+  return MATH_SW_divmodU(dividend, divisor, 1);
+}
+
+
+// Returns absolute value
+word MATH_abs(word x)
 {
-    return MATH_divmodU(dividend, divisor, 1);
-}
+  if (x >= 0)
+    return x;
+  else
+    return -x;
+}

+ 151 - 28
BCC/FPGCbuildTools/asm/lib/math.c

@@ -1,43 +1,166 @@
+/*
+* Math library
+* Contains functions math operation that are not directly supported by the ALU
+*/
+
+// Divide two signed integer numbers using MU
+word MATH_div(word dividend, word divisor)
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 1 r2 r5 ; write b to divider and perform signed division\n"
+    "read 1 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Modulo from division of two signed integer numbers using MU
+word MATH_mod(word dividend, word divisor)
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 3 r2 r5 ; write b to divider and perform signed modulo\n"
+    "read 3 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Divide two unsigned integer numbers using MU
+word MATH_divU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 2 r2 r5 ; write b to divider and perform unsigned division\n"
+    "read 2 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Modulo from division of two unsigned integer numbers using MU
+word MATH_modU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 4 r2 r5 ; write b to divider and perform unsiged modulo\n"
+    "read 4 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Signed Division and Modulo without / and %
+word MATH_SW_divmod(word dividend, word divisor, word* rem)
+{
+  word quotient = 1;
+
+  word neg = 1;
+  if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
+    neg = -1;
+
+  // Convert to positive
+  word tempdividend = (dividend < 0) ? -dividend : dividend;
+  word tempdivisor = (divisor < 0) ? -divisor : divisor;
+
+  if (tempdivisor == tempdividend) {
+    *rem = 0;
+    return 1*neg;
+  }
+  else if (tempdividend < tempdivisor) {
+    if (dividend < 0)
+      *rem = tempdividend*neg;
+    else
+      *rem = tempdividend;
+    return 0;
+  }
+  while (tempdivisor<<1 <= tempdividend)
+  {
+    tempdivisor = tempdivisor << 1;
+    quotient = quotient << 1;
+  }
+
+  // Call division recursively
+  if(dividend < 0)
+    quotient = quotient*neg + MATH_SW_divmod(-(tempdividend-tempdivisor), divisor, rem);
+  else
+    quotient = quotient*neg + MATH_SW_divmod(tempdividend-tempdivisor, divisor, rem);
+   return quotient;
+}
+
+word MATH_SW_div(word dividend, word divisor)
+{
+  word rem = 0;
+  return MATH_SW_divmod(dividend, divisor, &rem);
+}
+
+word MATH_SW_mod(word dividend, word divisor)
+{
+  word rem = 0;
+  MATH_SW_divmod(dividend, divisor, &rem);
+  return rem;
+}
+
+
 // Unsigned Division and Modulo without / and %
-word MATH_divmodU(word dividend, word divisor, word mod)
+word MATH_SW_divmodU(word dividend, word divisor, word mod)
 {
-    word quotient = 0;
-    word remainder = 0;
+  word quotient = 0;
+  word remainder = 0;
+
+  if(divisor == 0) 
+    return 0;
 
-    if(divisor == 0) 
-        return 0;
+  word i;
+  for(i = 31 ; i >= 0 ; i--)
+  {
+    quotient = quotient << 1;
+    remainder = remainder << 1;
+    remainder = remainder | ((unsigned) (dividend & (1 << i)) >> i);
 
-    word i;
-    for(i = 31 ; i >= 0 ; i--)
+    if((unsigned int) remainder >= (unsigned int) divisor)
     {
-        quotient = quotient << 1;
-        remainder = remainder << 1;
-        remainder = remainder | ((dividend & (1 << i)) >> i);
-
-        if((unsigned int) remainder >= (unsigned int) divisor)
-        {
-            remainder = remainder - divisor;
-            quotient = quotient | 1;
-        }
-
-        if (i == 0)
-            if (mod == 1)
-                return remainder;
-            else
-                return quotient;
+      remainder = remainder - divisor;
+      quotient = quotient | 1;
     }
 
-    return 0;
+    if (i == 0)
+      if (mod == 1)
+        return remainder;
+      else
+        return quotient;
+  }
+
+  return 0;
 }
 
 // Unsigned positive integer division
-word MATH_divU(word dividend, word divisor) 
+word MATH_SW_divU(word dividend, word divisor) 
 {
-    return MATH_divmodU(dividend, divisor, 0);
+  return MATH_SW_divmodU(dividend, divisor, 0);
 }
 
 // Unsigned positive integer modulo
-word MATH_modU(word dividend, word divisor) 
+word MATH_SW_modU(word dividend, word divisor) 
 {
-    return MATH_divmodU(dividend, divisor, 1);
-}
+  return MATH_SW_divmodU(dividend, divisor, 1);
+}
+
+
+// Returns absolute value
+word MATH_abs(word x)
+{
+  if (x >= 0)
+    return x;
+  else
+    return -x;
+}

+ 148 - 65
BCC/FPGCbuildTools/bcc/lib/math.c

@@ -1,94 +1,177 @@
-// Division and Modulo without / and %
-word divmod(word dividend, word divisor, word* rem)
+/*
+* Math library
+* Contains functions math operation that are not directly supported by the ALU
+*/
+
+// Divide two signed integer numbers using MU
+word MATH_div(word dividend, word divisor)
 {
-    word quotient = 1;
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 1 r2 r5 ; write b to divider and perform signed division\n"
+    "read 1 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    word neg = 1;
-    if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
-        neg = -1;
+// Modulo from division of two signed integer numbers using MU
+word MATH_mod(word dividend, word divisor)
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 3 r2 r5 ; write b to divider and perform signed modulo\n"
+    "read 3 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    // Convert to positive
-    word tempdividend = (dividend < 0) ? -dividend : dividend;
-    word tempdivisor = (divisor < 0) ? -divisor : divisor;
+// Divide two unsigned integer numbers using MU
+word MATH_divU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 2 r2 r5 ; write b to divider and perform unsigned division\n"
+    "read 2 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
 
-    if (tempdivisor == tempdividend) {
-        *rem = 0;
-        return 1*neg;
-    }
-    else if (tempdividend < tempdivisor) {
-        if (dividend < 0)
-            *rem = tempdividend*neg;
-        else
-            *rem = tempdividend;
-        return 0;
-    }
-    while (tempdivisor<<1 <= tempdividend)
-    {
-        tempdivisor = tempdivisor << 1;
-        quotient = quotient << 1;
-    }
+// Modulo from division of two unsigned integer numbers using MU
+word MATH_modU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 4 r2 r5 ; write b to divider and perform unsiged modulo\n"
+    "read 4 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Signed Division and Modulo without / and %
+word MATH_SW_divmod(word dividend, word divisor, word* rem)
+{
+  word quotient = 1;
+
+  word neg = 1;
+  if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
+    neg = -1;
 
-    // Call division recursively
-    if(dividend < 0)
-        quotient = quotient*neg + divmod(-(tempdividend-tempdivisor), divisor, rem);
+  // Convert to positive
+  word tempdividend = (dividend < 0) ? -dividend : dividend;
+  word tempdivisor = (divisor < 0) ? -divisor : divisor;
+
+  if (tempdivisor == tempdividend) {
+    *rem = 0;
+    return 1*neg;
+  }
+  else if (tempdividend < tempdivisor) {
+    if (dividend < 0)
+      *rem = tempdividend*neg;
     else
-        quotient = quotient*neg + divmod(tempdividend-tempdivisor, divisor, rem);
-     return quotient;
+      *rem = tempdividend;
+    return 0;
+  }
+  while (tempdivisor<<1 <= tempdividend)
+  {
+    tempdivisor = tempdivisor << 1;
+    quotient = quotient << 1;
+  }
+
+  // Call division recursively
+  if(dividend < 0)
+    quotient = quotient*neg + MATH_SW_divmod(-(tempdividend-tempdivisor), divisor, rem);
+  else
+    quotient = quotient*neg + MATH_SW_divmod(tempdividend-tempdivisor, divisor, rem);
+   return quotient;
 }
 
-word division(word dividend, word divisor)
+word MATH_SW_div(word dividend, word divisor)
 {
-    word rem = 0;
-    return divmod(dividend, divisor, &rem);
+  word rem = 0;
+  return MATH_SW_divmod(dividend, divisor, &rem);
 }
 
-word modulo(word dividend, word divisor)
+word MATH_SW_mod(word dividend, word divisor)
 {
-    word rem = 0;
-    divmod(dividend, divisor, &rem);
-    return rem;
+  word rem = 0;
+  MATH_SW_divmod(dividend, divisor, &rem);
+  return rem;
 }
 
+
 // Unsigned Division and Modulo without / and %
-word MATH_divmodU(word dividend, word divisor, word mod)
+word MATH_SW_divmodU(word dividend, word divisor, word mod)
 {
-    word quotient = 0;
-    word remainder = 0;
+  word quotient = 0;
+  word remainder = 0;
+
+  if(divisor == 0) 
+    return 0;
 
-    if(divisor == 0) 
-        return 0;
+  word i;
+  for(i = 31 ; i >= 0 ; i--)
+  {
+    quotient = quotient << 1;
+    remainder = remainder << 1;
+    remainder = remainder | ((unsigned) (dividend & (1 << i)) >> i);
 
-    word i;
-    for(i = 31 ; i >= 0 ; i--)
+    if((unsigned int) remainder >= (unsigned int) divisor)
     {
-        quotient = quotient << 1;
-        remainder = remainder << 1;
-        remainder = remainder | ((unsigned) (dividend & (1 << i)) >> i);
-
-        if((unsigned int) remainder >= (unsigned int) divisor)
-        {
-            remainder = remainder - divisor;
-            quotient = quotient | 1;
-        }
-
-        if (i == 0)
-            if (mod == 1)
-                return remainder;
-            else
-                return quotient;
+      remainder = remainder - divisor;
+      quotient = quotient | 1;
     }
 
-    return 0;
+    if (i == 0)
+      if (mod == 1)
+        return remainder;
+      else
+        return quotient;
+  }
+
+  return 0;
 }
 
 // Unsigned positive integer division
-word MATH_divU(word dividend, word divisor) 
+word MATH_SW_divU(word dividend, word divisor) 
 {
-    return MATH_divmodU(dividend, divisor, 0);
+  return MATH_SW_divmodU(dividend, divisor, 0);
 }
 
 // Unsigned positive integer modulo
-word MATH_modU(word dividend, word divisor) 
+word MATH_SW_modU(word dividend, word divisor) 
+{
+  return MATH_SW_divmodU(dividend, divisor, 1);
+}
+
+
+// Returns absolute value
+word MATH_abs(word x)
 {
-    return MATH_divmodU(dividend, divisor, 1);
-}
+  if (x >= 0)
+    return x;
+  else
+    return -x;
+}
+
+
+word division(word dividend, word divisor)
+{
+    return MATH_divU(dividend, divisor);
+}
+
+word modulo(word dividend, word divisor)
+{
+    return MATH_modU(dividend, divisor);
+}

+ 221 - 0
BCC/userBDOS/ICALC.C

@@ -0,0 +1,221 @@
+// Simple calculator to integers
+
+#define word char
+
+#include "LIB/MATH.C"
+#include "LIB/STDLIB.C"
+#include "LIB/SYS.C"
+
+#define CALC_BUFFER_MAX_LEN 32
+
+#define CALC_STATE_INPUTSTART 0
+#define CALC_STATE_INPUTA 1
+#define CALC_STATE_INPUTB 2
+#define CALC_STATE_INPUTOP 3
+
+// The current number that is being typed
+char CALC_buffer[CALC_BUFFER_MAX_LEN];
+word CALC_buffer_idx = 0;
+
+word CALC_a = 0;
+word CALC_b = 0;
+
+char CALC_state = CALC_STATE_INPUTSTART;
+
+
+
+word calcLoop()
+{
+  if (CALC_state == CALC_STATE_INPUTSTART)
+  {
+    BDOS_PrintConsole("Input A:      ");
+    CALC_state = CALC_STATE_INPUTA;
+  }
+
+
+  if (HID_FifoAvailable())
+  {
+    word c = HID_FifoRead();
+
+    if (CALC_state == CALC_STATE_INPUTOP)
+    {
+      if (c == '+')
+      {
+        BDOS_PrintlnConsole("+");
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintDecConsole(CALC_a + CALC_b);
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
+      else if (c == '-')
+      {
+        BDOS_PrintlnConsole("-");
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintDecConsole(CALC_a - CALC_b);
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
+      else if (c == '*')
+      {
+        BDOS_PrintlnConsole("*");
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintDecConsole(CALC_a * CALC_b);
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
+      else if (c == '/')
+      {
+        BDOS_PrintlnConsole("/");
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintDecConsole( MATH_div(CALC_a, CALC_b) );
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
+      else if (c == '%')
+      {
+        BDOS_PrintlnConsole("%");
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintDecConsole( MATH_mod(CALC_a, CALC_b) );
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
+      else if (c == 'u')
+      {
+        BDOS_PrintlnConsole("u/");
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintDecConsole( MATH_divU(CALC_a, CALC_b) );
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
+      else if (c == 'w')
+      {
+        BDOS_PrintlnConsole("u%");
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintDecConsole( MATH_modU(CALC_a, CALC_b) );
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
+      else if (c == 0x1b) // escape
+      {
+        BDOS_PrintcConsole('\n');
+        return 1;
+      }
+    }
+    // number input, dot or sign
+    else if ( (c >= '0' && c <= '9') || c == '-')
+    {
+      if (CALC_state == CALC_STATE_INPUTA || CALC_state == CALC_STATE_INPUTB)
+      {
+        // add to buffer and print character
+        CALC_buffer[CALC_buffer_idx] = c;
+        CALC_buffer_idx++;
+        CALC_buffer[CALC_buffer_idx] = 0; // terminate
+        BDOS_PrintcConsole(c);
+      }
+    }
+    else if (c == 0x8) // backspace
+    {
+      if (CALC_state == CALC_STATE_INPUTA || CALC_state == CALC_STATE_INPUTB)
+      {
+        // replace last char in buffer by 0 (if not at start)
+        if (CALC_buffer_idx != 0)
+        {
+          CALC_buffer_idx--;
+          CALC_buffer[CALC_buffer_idx] = 0;
+          BDOS_PrintcConsole(c);
+        }
+      }
+    }
+    else if (c == 0xa) // newline/enter
+    {
+      switch(CALC_state)
+      {
+        case CALC_STATE_INPUTA:
+          if (CALC_buffer_idx > 0)
+          {
+            BDOS_PrintcConsole('\n');
+            
+            CALC_a = strToInt(CALC_buffer);
+            CALC_buffer_idx = 0;
+
+            BDOS_PrintConsole("\nInput B:      ");
+            CALC_state = CALC_STATE_INPUTB;
+          }
+          break;
+
+        case CALC_STATE_INPUTB:
+          if (CALC_buffer_idx > 0)
+          {
+            BDOS_PrintcConsole('\n');
+
+            CALC_b = strToInt(CALC_buffer);
+            CALC_buffer_idx = 0;
+
+            BDOS_PrintConsole("Operation:    ");
+            CALC_state = CALC_STATE_INPUTOP;
+          }
+          break;
+      }
+    }
+    else if (c == 0x1b) // escape
+    {
+      BDOS_PrintcConsole('\n');
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+int main() 
+{
+  BDOS_PrintlnConsole("Integer calculator test\n");
+
+  word stop = 0;
+  while (!stop)
+  {
+    stop = calcLoop();
+  }
+
+  return 'q';
+}
+
+void interrupt()
+{
+  // handle all interrupts
+  word i = getIntID();
+  switch(i)
+  {
+    case INTID_TIMER1:
+      timer1Value = 1; // notify ending of timer1
+      break;
+
+    case INTID_TIMER2:
+      break;
+
+    case INTID_UART0:
+      break;
+
+    case INTID_GPU:
+      break;
+
+    case INTID_TIMER3:
+      break;
+
+    case INTID_PS2:
+      break;
+
+    case INTID_UART1:
+      break;
+
+    case INTID_UART2:
+      break;
+  }
+}

+ 1 - 1
BCC/userBDOS/LIB/FP.C

@@ -172,7 +172,7 @@ fixed_point_t FP_Div(fixed_point_t a, fixed_point_t b)
   // r4: a, r5: b
   fixed_point_t retval = 0;
   asm(
-    "load32 0xC02742 r2 ; r2 = addr div_writea\n"
+    "load32 0xC02742 r2 ; r2 = addr fpdiv_writea\n"
     "write 0 r2 r4 ; write a to divider\n"
     "write 1 r2 r5 ; write b to divider and perform division\n"
     "read 1 r2 r2  ; read result to r2\n"

+ 70 - 14
BCC/userBDOS/LIB/MATH.C

@@ -1,10 +1,66 @@
 /*
 * Math library
-* Contains functions math operation that are not directly supported by the hardware
+* Contains functions math operation that are not directly supported by the ALU
 */
 
+// Divide two signed integer numbers using MU
+word MATH_div(word dividend, word divisor)
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 1 r2 r5 ; write b to divider and perform signed division\n"
+    "read 1 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Modulo from division of two signed integer numbers using MU
+word MATH_mod(word dividend, word divisor)
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 3 r2 r5 ; write b to divider and perform signed modulo\n"
+    "read 3 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Divide two unsigned integer numbers using MU
+word MATH_divU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 2 r2 r5 ; write b to divider and perform unsigned division\n"
+    "read 2 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
+// Modulo from division of two unsigned integer numbers using MU
+word MATH_modU(word dividend, word divisor) 
+{
+  word retval = 0;
+  asm(
+    "load32 0xC02744 r2 ; r2 = addr idiv_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 4 r2 r5 ; write b to divider and perform unsiged modulo\n"
+    "read 4 r2 r2  ; read remainder to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+  return retval;
+}
+
 // Signed Division and Modulo without / and %
-word MATH_divmod(word dividend, word divisor, word* rem)
+word MATH_SW_divmod(word dividend, word divisor, word* rem)
 {
   word quotient = 1;
 
@@ -35,28 +91,28 @@ word MATH_divmod(word dividend, word divisor, word* rem)
 
   // Call division recursively
   if(dividend < 0)
-    quotient = quotient*neg + MATH_divmod(-(tempdividend-tempdivisor), divisor, rem);
+    quotient = quotient*neg + MATH_SW_divmod(-(tempdividend-tempdivisor), divisor, rem);
   else
-    quotient = quotient*neg + MATH_divmod(tempdividend-tempdivisor, divisor, rem);
+    quotient = quotient*neg + MATH_SW_divmod(tempdividend-tempdivisor, divisor, rem);
    return quotient;
 }
 
-word MATH_div(word dividend, word divisor)
+word MATH_SW_div(word dividend, word divisor)
 {
   word rem = 0;
-  return MATH_divmod(dividend, divisor, &rem);
+  return MATH_SW_divmod(dividend, divisor, &rem);
 }
 
-word MATH_mod(word dividend, word divisor)
+word MATH_SW_mod(word dividend, word divisor)
 {
   word rem = 0;
-  MATH_divmod(dividend, divisor, &rem);
+  MATH_SW_divmod(dividend, divisor, &rem);
   return rem;
 }
 
 
 // Unsigned Division and Modulo without / and %
-word MATH_divmodU(word dividend, word divisor, word mod)
+word MATH_SW_divmodU(word dividend, word divisor, word mod)
 {
   word quotient = 0;
   word remainder = 0;
@@ -88,15 +144,15 @@ word MATH_divmodU(word dividend, word divisor, word mod)
 }
 
 // Unsigned positive integer division
-word MATH_divU(word dividend, word divisor) 
+word MATH_SW_divU(word dividend, word divisor) 
 {
-  return MATH_divmodU(dividend, divisor, 0);
+  return MATH_SW_divmodU(dividend, divisor, 0);
 }
 
 // Unsigned positive integer modulo
-word MATH_modU(word dividend, word divisor) 
+word MATH_SW_modU(word dividend, word divisor) 
 {
-  return MATH_divmodU(dividend, divisor, 1);
+  return MATH_SW_divmodU(dividend, divisor, 1);
 }
 
 
@@ -107,4 +163,4 @@ word MATH_abs(word x)
     return x;
   else
     return -x;
-}
+}

+ 8 - 1
Documentation/docs/Hardware/Logic/Memory/Map.md

@@ -92,7 +92,14 @@ $C02722 +------------------------+
         | Timer3_ctrl    $C0273E |
         | Unused         $C0273F |
         | PS/2 Keyboard  $C02740 |
-        | BOOT_MODE      $C02741 | $C02741
+        | BOOT_MODE      $C02741 |
+        | FP_div_writea  $C02742 |
+        | FP_div_divb    $C02743 |
+        | I_div_writea   $C02744 |
+        | I_div_divbs    $C02745 |
+        | I_div_divbu    $C02746 |
+        | I_div_mods     $C02747 |
+        | I_div_modu     $C02748 | $C02748
 $C02742 +------------------------+
         |                        |
         |        Nothing         |

BIN
Programmer/flasher_fast.bin


+ 2 - 1
Quartus/FPGC.qsf

@@ -229,7 +229,8 @@ set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW
 set_global_assignment -name SDC_FILE FPGC.sdc
 set_global_assignment -name VERILOG_FILE modules/FPGC.v
-set_global_assignment -name VERILOG_FILE modules/IO/Divider.v
+set_global_assignment -name VERILOG_FILE modules/IO/IDivider.v
+set_global_assignment -name VERILOG_FILE modules/IO/FPDivider.v
 set_global_assignment -name VERILOG_FILE modules/Memory/L1Icache.v
 set_global_assignment -name VERILOG_FILE modules/Memory/L1Dcache.v
 set_global_assignment -name VERILOG_FILE modules/Memory/L2cache.v

BIN
Quartus/FPGC.qws


+ 2 - 14
Quartus/modules/IO/Divider.v → Quartus/modules/IO/FPDivider.v

@@ -1,20 +1,8 @@
 /*
-* 32-bit multicycle divider
+* 32-bit multicycle fixed-point divider
 */
 
-/*
-module Divider(
-    input clk,
-    input reset,
-    input start,
-    input [31:0] data,
-
-    output done,
-    output [31:0] q
-);
-*/
-
-module Divider #(
+module FPDivider #(
     parameter WIDTH=32,  // width of numbers in bits (integer and fractional)
     parameter FBITS=16   // fractional bits within WIDTH
     ) (

+ 134 - 0
Quartus/modules/IO/IDivider.v

@@ -0,0 +1,134 @@
+/*
+* 32-bit multicycle signed or unsigned integer divider
+*/
+
+module IDivider #(
+    parameter DATA_WIDTH = 32
+) (
+    input clk,
+    input rst,
+    input [DATA_WIDTH-1:0] a,
+    input [DATA_WIDTH-1:0] b,
+    input signed_ope,
+    input write_a,
+    input start,
+    input flush,
+    output reg [DATA_WIDTH-1:0] quotient,
+    output reg [DATA_WIDTH-1:0] remainder,
+    output ready
+);
+
+  reg start_prev = 0;
+
+  reg [DATA_WIDTH-1:0] dividend = 0;
+  reg [DATA_WIDTH-1:0] divisor = 0;
+
+
+
+  
+  localparam COUNT_WIDTH = $clog2(DATA_WIDTH + 1);
+
+  reg r_ready = 0;
+  reg r_signed_ope = 0;
+  reg [COUNT_WIDTH-1:0] r_count = 0;
+  reg [DATA_WIDTH-1:0] r_quotient = 0;
+  wire w_dividend_sign;
+  reg r_dividend_sign = 0;
+  wire remainder_sign;
+  reg [DATA_WIDTH:0] r_remainder = 0;
+  reg [DATA_WIDTH-1:0] r_divisor = 0;
+  wire [DATA_WIDTH:0] divisor_ext;
+  wire divisor_sign;
+  wire [DATA_WIDTH:0] rem_quo;
+  wire                diff_sign;
+  wire [DATA_WIDTH:0] sub_add;
+
+  assign ready = r_ready;
+
+  assign divisor_sign = r_divisor[DATA_WIDTH-1] & r_signed_ope;
+  assign divisor_ext = {divisor_sign, r_divisor};
+  assign remainder_sign = r_remainder[DATA_WIDTH];
+
+  assign rem_quo = {r_remainder[DATA_WIDTH-1:0], r_quotient[DATA_WIDTH-1]};
+  assign diff_sign = remainder_sign ^ divisor_sign;
+  assign sub_add = diff_sign ? rem_quo + divisor_ext :
+                               rem_quo - divisor_ext;
+
+  // after process
+  always @(*) begin
+    quotient  = (r_quotient << 1) | 1;
+    remainder = r_remainder[DATA_WIDTH-1:0];
+
+    if (r_remainder == 0) begin
+      // do nothing
+    end else if (r_remainder == divisor_ext) begin
+      quotient  = quotient + 1;
+      remainder = remainder - r_divisor;
+    end else if (r_remainder == -divisor_ext) begin
+      quotient  = quotient - 1;
+      remainder = remainder + r_divisor;
+    end else if (remainder_sign ^ r_dividend_sign) begin
+      if (diff_sign) begin
+        quotient  = quotient - 1;
+        remainder = remainder + r_divisor;
+      end else begin
+        quotient  = quotient + 1;
+        remainder = remainder - r_divisor;
+      end
+    end
+  end
+
+  assign w_dividend_sign = dividend[DATA_WIDTH-1] & signed_ope;
+
+  always @(posedge clk)
+  begin
+      start_prev <= start;
+      if (write_a)
+      begin
+        dividend <= a;
+      end
+      if (start && !start_prev)
+      begin
+          divisor <= b;
+      end
+  end
+
+  always @(posedge clk) begin
+    if (rst) begin
+      r_quotient      <= 0;
+      r_dividend_sign <= 0;
+      r_remainder     <= 0;
+      r_divisor       <= 0;
+      r_count         <= 0;
+      r_ready         <= 1'b1;
+      r_signed_ope    <= 1'b0;
+    end else begin
+      if (flush) begin
+        r_count         <= 0;
+        r_ready         <= 1'b1;
+      end else if (start && !start_prev) // use b for this first cycle, as divisor are latched during this cycle
+      begin
+        // RISC-V's div by 0 spec
+        if (b == 0) begin
+            r_quotient  <= 1;
+            r_remainder <= {w_dividend_sign, dividend};
+        end else begin
+            r_quotient  <= dividend;
+            r_remainder <= {(DATA_WIDTH+1){w_dividend_sign}};
+            r_ready     <= 1'b0;
+        end
+        r_count         <= 0;
+        r_dividend_sign <= w_dividend_sign;
+        r_divisor       <= b;
+        r_signed_ope    <= signed_ope;
+      end else if (~ready) begin
+        r_quotient  <= {r_quotient[DATA_WIDTH-2:0], ~diff_sign};
+        r_remainder <= sub_add[DATA_WIDTH:0];
+        r_count     <= r_count + 1;
+        if (r_count == DATA_WIDTH - 1) begin
+          r_ready <= 1'b1;
+        end
+      end
+    end
+  end
+endmodule

+ 77 - 19
Quartus/modules/Memory/MemoryUnit.v

@@ -161,8 +161,13 @@ localparam
     A_PS2 = 36,
     A_BOOTMODE = 37,
     A_VRAMPX = 38,
-    A_DIVWA = 39,
-    A_DIVSTART = 40;
+    A_FPDIVWA = 39,
+    A_FPDIVSTART = 40,
+    A_IDIVWA = 41,
+    A_IDIVSTARTS = 42,
+    A_IDIVSTARTU = 43,
+    A_IDIVMODS = 44,
+    A_IDIVMODU = 45;
 
 //------------
 //SPI0 (flash) TODO: move this to a separate module
@@ -527,26 +532,53 @@ Keyboard PS2Keyboard (
 );
 
 
-wire [31:0] div_input;
-wire div_write_a;
-wire div_busy;
+wire [31:0] fpdiv_input;
+wire fpdiv_write_a;
+wire fpdiv_busy;
+wire fpdiv_start;
 
-wire [31:0] div_val;
+wire [31:0] fpdiv_val;
 
 
-Divider divider(
+FPDivider fpdivider(
 .clk        (clk), 
 .rst        (reset),
-.start      (div_start),  // start calculation
-.write_a    (div_write_a),
-.busy       (div_busy),   // calculation in progress
-//.done       (div_done),   // calculation is complete (high for one tick)
+.start      (fpdiv_start),  // start calculation
+.write_a    (fpdiv_write_a),
+.busy       (fpdiv_busy),   // calculation in progress
+//.done       (fpdiv_done),   // calculation is complete (high for one tick)
 //.valid      (valid),  // result is valid
 //.dbz        (dbz),    // divide by zero
 //.ovf        (ovf),    // overflow
 .a_in       (bus_data),   // dividend (numerator)
 .b          (bus_data),   // divisor (denominator)
-.val        (div_val)  // result value: quotient
+.val        (fpdiv_val)  // result value: quotient
+);
+
+
+
+wire [31:0] idiv_input;
+wire idiv_write_a;
+wire idiv_ready;
+wire idiv_start;
+wire idiv_signed;
+
+wire [31:0] idiv_q;
+wire [31:0] idiv_r;
+
+
+IDivider idivider(
+.clk        (clk), 
+.rst        (reset),
+.start      (idiv_start),  // start calculation
+.write_a    (idiv_write_a),
+.ready      (idiv_ready),   // !calculation in progress
+.flush      (1'b0),
+.signed_ope (idiv_signed), // signed or unsiged
+.a          (bus_data),   // dividend (numerator)
+.b          (bus_data),   // divisor (denominator)
+.quotient   (idiv_q),  // result value: quotient
+.remainder  (idiv_r)
 );
 
 
@@ -632,8 +664,19 @@ assign OST3_trigger     = (bus_addr == 27'hC0273E && bus_we);
 //assign SNES_start       = bus_addr == 27'hC0273F && bus_start;
 
 //Divider
-assign div_write_a      = (bus_addr == 27'hC02742 && bus_we);
-assign div_start        = (bus_addr == 27'hC02743 && bus_we);
+assign fpdiv_write_a      = (bus_addr == 27'hC02742 && bus_we);
+assign fpdiv_start        = (bus_addr == 27'hC02743 && bus_we);
+
+assign idiv_write_a      = (bus_addr == 27'hC02744 && bus_we);
+assign idiv_start        = (
+                            (bus_addr == 27'hC02745 ||
+                                bus_addr == 27'hC02746 || 
+                                bus_addr == 27'hC02747 || 
+                                bus_addr == 27'hC02748
+                            ) 
+                            && bus_we
+                           );
+assign idiv_signed       = ((bus_addr == 27'hC02745 || bus_addr == 27'hC02747) && bus_we);
 
 
 reg [5:0] a_sel;
@@ -680,8 +723,13 @@ begin
     //if (bus_addr == 27'hC0273F) a_sel = A_SNESPAD;
     if (bus_addr == 27'hC02740) a_sel = A_PS2;
     if (bus_addr == 27'hC02741) a_sel = A_BOOTMODE;
-    if (bus_addr == 27'hC02742) a_sel = A_DIVWA;
-    if (bus_addr == 27'hC02743) a_sel = A_DIVSTART;
+    if (bus_addr == 27'hC02742) a_sel = A_FPDIVWA;
+    if (bus_addr == 27'hC02743) a_sel = A_FPDIVSTART;
+    if (bus_addr == 27'hC02744) a_sel = A_IDIVWA;
+    if (bus_addr == 27'hC02745) a_sel = A_IDIVSTARTS;
+    if (bus_addr == 27'hC02746) a_sel = A_IDIVSTARTU;
+    if (bus_addr == 27'hC02747) a_sel = A_IDIVMODS;
+    if (bus_addr == 27'hC02748) a_sel = A_IDIVMODU;
     if (bus_addr >= 27'hD00000 && bus_addr < 27'hD12C00) a_sel = A_VRAMPX;
 end
 
@@ -729,7 +777,11 @@ begin
         A_PS2:          bus_q_wire = {24'd0, PS2_scanCode};
         A_BOOTMODE:     bus_q_wire = {31'd0, boot_mode};
         A_VRAMPX:       bus_q_wire = VRAMpx_cpu_q;
-        A_DIVSTART:     bus_q_wire = div_val;
+        A_FPDIVSTART:   bus_q_wire = fpdiv_val;
+        A_IDIVSTARTS:   bus_q_wire = idiv_q;
+        A_IDIVSTARTU:   bus_q_wire = idiv_q;
+        A_IDIVMODS:     bus_q_wire = idiv_r;
+        A_IDIVMODU:     bus_q_wire = idiv_r;
         default:        bus_q_wire = 32'd0;
     endcase
 end
@@ -933,9 +985,15 @@ begin
                     bus_done <= 1'b1;
                 end
 
-                A_DIVSTART:
+                A_FPDIVSTART:
+                begin
+                    if (!fpdiv_busy)
+                        if (!bus_done_next) bus_done_next <= 1'b1;
+                end
+
+                A_IDIVSTARTS, A_IDIVSTARTU, A_IDIVMODS, A_IDIVMODU:
                 begin
-                    if (!div_busy)
+                    if (idiv_ready)
                         if (!bus_done_next) bus_done_next <= 1'b1;
                 end
 

BIN
Quartus/output_files/output_file.jic


+ 2 - 14
Verilog/modules/IO/Divider.v → Verilog/modules/IO/FPDivider.v

@@ -1,20 +1,8 @@
 /*
-* 32-bit multicycle divider
+* 32-bit multicycle fixed-point divider
 */
 
-/*
-module Divider(
-    input clk,
-    input reset,
-    input start,
-    input [31:0] data,
-
-    output done,
-    output [31:0] q
-);
-*/
-
-module Divider #(
+module FPDivider #(
     parameter WIDTH=32,  // width of numbers in bits (integer and fractional)
     parameter FBITS=16   // fractional bits within WIDTH
     ) (

+ 134 - 0
Verilog/modules/IO/IDivider.v

@@ -0,0 +1,134 @@
+/*
+* 32-bit multicycle signed or unsigned integer divider
+*/
+
+module IDivider #(
+    parameter DATA_WIDTH = 32
+) (
+    input clk,
+    input rst,
+    input [DATA_WIDTH-1:0] a,
+    input [DATA_WIDTH-1:0] b,
+    input signed_ope,
+    input write_a,
+    input start,
+    input flush,
+    output reg [DATA_WIDTH-1:0] quotient,
+    output reg [DATA_WIDTH-1:0] remainder,
+    output ready
+);
+
+  reg start_prev = 0;
+
+  reg [DATA_WIDTH-1:0] dividend = 0;
+  reg [DATA_WIDTH-1:0] divisor = 0;
+
+
+
+  
+  localparam COUNT_WIDTH = $clog2(DATA_WIDTH + 1);
+
+  reg r_ready = 0;
+  reg r_signed_ope = 0;
+  reg [COUNT_WIDTH-1:0] r_count = 0;
+  reg [DATA_WIDTH-1:0] r_quotient = 0;
+  wire w_dividend_sign;
+  reg r_dividend_sign = 0;
+  wire remainder_sign;
+  reg [DATA_WIDTH:0] r_remainder = 0;
+  reg [DATA_WIDTH-1:0] r_divisor = 0;
+  wire [DATA_WIDTH:0] divisor_ext;
+  wire divisor_sign;
+  wire [DATA_WIDTH:0] rem_quo;
+  wire                diff_sign;
+  wire [DATA_WIDTH:0] sub_add;
+
+  assign ready = r_ready;
+
+  assign divisor_sign = r_divisor[DATA_WIDTH-1] & r_signed_ope;
+  assign divisor_ext = {divisor_sign, r_divisor};
+  assign remainder_sign = r_remainder[DATA_WIDTH];
+
+  assign rem_quo = {r_remainder[DATA_WIDTH-1:0], r_quotient[DATA_WIDTH-1]};
+  assign diff_sign = remainder_sign ^ divisor_sign;
+  assign sub_add = diff_sign ? rem_quo + divisor_ext :
+                               rem_quo - divisor_ext;
+
+  // after process
+  always @(*) begin
+    quotient  = (r_quotient << 1) | 1;
+    remainder = r_remainder[DATA_WIDTH-1:0];
+
+    if (r_remainder == 0) begin
+      // do nothing
+    end else if (r_remainder == divisor_ext) begin
+      quotient  = quotient + 1;
+      remainder = remainder - r_divisor;
+    end else if (r_remainder == -divisor_ext) begin
+      quotient  = quotient - 1;
+      remainder = remainder + r_divisor;
+    end else if (remainder_sign ^ r_dividend_sign) begin
+      if (diff_sign) begin
+        quotient  = quotient - 1;
+        remainder = remainder + r_divisor;
+      end else begin
+        quotient  = quotient + 1;
+        remainder = remainder - r_divisor;
+      end
+    end
+  end
+
+  assign w_dividend_sign = dividend[DATA_WIDTH-1] & signed_ope;
+
+  always @(posedge clk)
+  begin
+      start_prev <= start;
+      if (write_a)
+      begin
+        dividend <= a;
+      end
+      if (start && !start_prev)
+      begin
+          divisor <= b;
+      end
+  end
+
+  always @(posedge clk) begin
+    if (rst) begin
+      r_quotient      <= 0;
+      r_dividend_sign <= 0;
+      r_remainder     <= 0;
+      r_divisor       <= 0;
+      r_count         <= 0;
+      r_ready         <= 1'b1;
+      r_signed_ope    <= 1'b0;
+    end else begin
+      if (flush) begin
+        r_count         <= 0;
+        r_ready         <= 1'b1;
+      end else if (start && !start_prev) // use b for this first cycle, as divisor are latched during this cycle
+      begin
+        // RISC-V's div by 0 spec
+        if (b == 0) begin
+            r_quotient  <= 1;
+            r_remainder <= {w_dividend_sign, dividend};
+        end else begin
+            r_quotient  <= dividend;
+            r_remainder <= {(DATA_WIDTH+1){w_dividend_sign}};
+            r_ready     <= 1'b0;
+        end
+        r_count         <= 0;
+        r_dividend_sign <= w_dividend_sign;
+        r_divisor       <= b;
+        r_signed_ope    <= signed_ope;
+      end else if (~ready) begin
+        r_quotient  <= {r_quotient[DATA_WIDTH-2:0], ~diff_sign};
+        r_remainder <= sub_add[DATA_WIDTH:0];
+        r_count     <= r_count + 1;
+        if (r_count == DATA_WIDTH - 1) begin
+          r_ready <= 1'b1;
+        end
+      end
+    end
+  end
+endmodule

+ 77 - 19
Verilog/modules/Memory/MemoryUnit.v

@@ -161,8 +161,13 @@ localparam
     A_PS2 = 36,
     A_BOOTMODE = 37,
     A_VRAMPX = 38,
-    A_DIVWA = 39,
-    A_DIVSTART = 40;
+    A_FPDIVWA = 39,
+    A_FPDIVSTART = 40,
+    A_IDIVWA = 41,
+    A_IDIVSTARTS = 42,
+    A_IDIVSTARTU = 43,
+    A_IDIVMODS = 44,
+    A_IDIVMODU = 45;
 
 //------------
 //SPI0 (flash) TODO: move this to a separate module
@@ -527,26 +532,53 @@ Keyboard PS2Keyboard (
 );
 
 
-wire [31:0] div_input;
-wire div_write_a;
-wire div_busy;
+wire [31:0] fpdiv_input;
+wire fpdiv_write_a;
+wire fpdiv_busy;
+wire fpdiv_start;
 
-wire [31:0] div_val;
+wire [31:0] fpdiv_val;
 
 
-Divider divider(
+FPDivider fpdivider(
 .clk        (clk), 
 .rst        (reset),
-.start      (div_start),  // start calculation
-.write_a    (div_write_a),
-.busy       (div_busy),   // calculation in progress
-//.done       (div_done),   // calculation is complete (high for one tick)
+.start      (fpdiv_start),  // start calculation
+.write_a    (fpdiv_write_a),
+.busy       (fpdiv_busy),   // calculation in progress
+//.done       (fpdiv_done),   // calculation is complete (high for one tick)
 //.valid      (valid),  // result is valid
 //.dbz        (dbz),    // divide by zero
 //.ovf        (ovf),    // overflow
 .a_in       (bus_data),   // dividend (numerator)
 .b          (bus_data),   // divisor (denominator)
-.val        (div_val)  // result value: quotient
+.val        (fpdiv_val)  // result value: quotient
+);
+
+
+
+wire [31:0] idiv_input;
+wire idiv_write_a;
+wire idiv_ready;
+wire idiv_start;
+wire idiv_signed;
+
+wire [31:0] idiv_q;
+wire [31:0] idiv_r;
+
+
+IDivider idivider(
+.clk        (clk), 
+.rst        (reset),
+.start      (idiv_start),  // start calculation
+.write_a    (idiv_write_a),
+.ready      (idiv_ready),   // !calculation in progress
+.flush      (1'b0),
+.signed_ope (idiv_signed), // signed or unsiged
+.a          (bus_data),   // dividend (numerator)
+.b          (bus_data),   // divisor (denominator)
+.quotient   (idiv_q),  // result value: quotient
+.remainder  (idiv_r)
 );
 
 
@@ -632,8 +664,19 @@ assign OST3_trigger     = (bus_addr == 27'hC0273E && bus_we);
 //assign SNES_start       = bus_addr == 27'hC0273F && bus_start;
 
 //Divider
-assign div_write_a      = (bus_addr == 27'hC02742 && bus_we);
-assign div_start        = (bus_addr == 27'hC02743 && bus_we);
+assign fpdiv_write_a      = (bus_addr == 27'hC02742 && bus_we);
+assign fpdiv_start        = (bus_addr == 27'hC02743 && bus_we);
+
+assign idiv_write_a      = (bus_addr == 27'hC02744 && bus_we);
+assign idiv_start        = (
+                            (bus_addr == 27'hC02745 ||
+                                bus_addr == 27'hC02746 || 
+                                bus_addr == 27'hC02747 || 
+                                bus_addr == 27'hC02748
+                            ) 
+                            && bus_we
+                           );
+assign idiv_signed       = ((bus_addr == 27'hC02745 || bus_addr == 27'hC02747) && bus_we);
 
 
 reg [5:0] a_sel;
@@ -680,8 +723,13 @@ begin
     //if (bus_addr == 27'hC0273F) a_sel = A_SNESPAD;
     if (bus_addr == 27'hC02740) a_sel = A_PS2;
     if (bus_addr == 27'hC02741) a_sel = A_BOOTMODE;
-    if (bus_addr == 27'hC02742) a_sel = A_DIVWA;
-    if (bus_addr == 27'hC02743) a_sel = A_DIVSTART;
+    if (bus_addr == 27'hC02742) a_sel = A_FPDIVWA;
+    if (bus_addr == 27'hC02743) a_sel = A_FPDIVSTART;
+    if (bus_addr == 27'hC02744) a_sel = A_IDIVWA;
+    if (bus_addr == 27'hC02745) a_sel = A_IDIVSTARTS;
+    if (bus_addr == 27'hC02746) a_sel = A_IDIVSTARTU;
+    if (bus_addr == 27'hC02747) a_sel = A_IDIVMODS;
+    if (bus_addr == 27'hC02748) a_sel = A_IDIVMODU;
     if (bus_addr >= 27'hD00000 && bus_addr < 27'hD12C00) a_sel = A_VRAMPX;
 end
 
@@ -729,7 +777,11 @@ begin
         A_PS2:          bus_q_wire = {24'd0, PS2_scanCode};
         A_BOOTMODE:     bus_q_wire = {31'd0, boot_mode};
         A_VRAMPX:       bus_q_wire = VRAMpx_cpu_q;
-        A_DIVSTART:     bus_q_wire = div_val;
+        A_FPDIVSTART:   bus_q_wire = fpdiv_val;
+        A_IDIVSTARTS:   bus_q_wire = idiv_q;
+        A_IDIVSTARTU:   bus_q_wire = idiv_q;
+        A_IDIVMODS:     bus_q_wire = idiv_r;
+        A_IDIVMODU:     bus_q_wire = idiv_r;
         default:        bus_q_wire = 32'd0;
     endcase
 end
@@ -933,9 +985,15 @@ begin
                     bus_done <= 1'b1;
                 end
 
-                A_DIVSTART:
+                A_FPDIVSTART:
+                begin
+                    if (!fpdiv_busy)
+                        if (!bus_done_next) bus_done_next <= 1'b1;
+                end
+
+                A_IDIVSTARTS, A_IDIVSTARTU, A_IDIVMODS, A_IDIVMODU:
                 begin
-                    if (!div_busy)
+                    if (idiv_ready)
                         if (!bus_done_next) bus_done_next <= 1'b1;
                 end
 

+ 2 - 1
Verilog/testbench/FPGC_tb.v

@@ -45,7 +45,8 @@
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/UARTrx.v"
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/SimpleSPI.v"
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/LEDvisualizer.v"
-`include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/Divider.v"
+`include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/FPDivider.v"
+`include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/IDivider.v"
 
 // gpu
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/GPU/FSX.v"

+ 14 - 23
Verilog/testbench/divider_tb.v

@@ -8,7 +8,7 @@
 
 // Includes
 // Memory
-`include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/Divider.v"
+`include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/IDivider.v"
 
 
 // Define testmodule
@@ -19,39 +19,30 @@ reg clk = 1'b0;
 reg reset = 1'b0;
 reg start = 1'b0;
 reg write_a = 1'b0;
-
-wire busy;
-wire done;
-wire valid;
-wire dbz;
-wire ovf;
+reg signed_ope = 1'b0;
+wire ready;
 
 
 reg signed [31:0] a = 0;
 reg signed [31:0] b = 0;
 
-wire signed [31:0] val;
-
-wire signed [15:0] val_int;
-assign val_int = val [31:16];
+wire signed [31:0] quotient;
+wire signed [31:0] remainder;
 
-Divider divider(
+IDivider divider(
 .clk    (clk), 
 .rst    (reset),
 .start(start),  // start calculation
 .write_a(write_a),
-.busy(busy),   // calculation in progress
-.done(done),   // calculation is complete (high for one tick)
-.valid(valid),  // result is valid
-.dbz(dbz),    // divide by zero
-.ovf(ovf),    // overflow
-.a_in(a),   // dividend (numerator)
+.ready (ready),
+.flush(1'b0),
+.signed_ope(signed_ope),   // calculation in progress
+.a(a),   // dividend (numerator)
 .b(b),   // divisor (denominator)
-.val(val)  // result value: quotient
+.quotient(quotient),  // result value: quotient
+.remainder(remainder)
 );
 
-
-
 initial
 begin
     // dump everything for GTKwave
@@ -86,7 +77,7 @@ begin
         #10;
     end
 
-    a = 17 << 16;
+    a = 17;
     write_a = 1;
     repeat(1)
     begin
@@ -105,7 +96,7 @@ begin
     end
 
     a = 0;
-    b = 3 << 16;
+    b = 3;
     start = 1;