Emulate illegal DIVs

The RISC5 architecture requires divisors to be positive. This commit
emulates what happens if you try to divide by zero or by a negative
integer.
This commit is contained in:
Peter De Wachter 2015-10-02 00:21:50 +02:00
parent 85ee2e5282
commit 70dbab69ef
6 changed files with 86 additions and 6 deletions

View File

@ -4,3 +4,4 @@ div
flr
flt
mul
idiv

View File

@ -1,6 +1,6 @@
CFLAGS = -Wall -Wextra -O3 -march=native
TESTS = add flr flt mul div
TESTS = add flr flt mul div idiv
VPATH = $(VERILOG)
@ -19,6 +19,7 @@ flr: flr.c $(RISC_FP) numbers.inc FPAdder.inc
flt: flt.c $(RISC_FP) numbers.inc FPAdder.inc
mul: mul.c $(RISC_FP) numbers.inc FPMultiplier.inc
div: div.c $(RISC_FP) numbers.inc FPDivider.inc
idiv: idiv.c $(RISC_FP) numbers.inc Divider.inc
numbers.inc: numbers.py
python3 $< > $@

50
src/fp-test/idiv.c Normal file
View File

@ -0,0 +1,50 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "../risc-fp.h"
#include "numbers.inc"
#include "Divider.inc"
static bool clk __attribute__((unused));
static struct idiv v_idiv(uint32_t in_x, uint32_t in_y, bool signed_div) {
x = in_x;
y = in_y;
u = signed_div;
run = 0;
cycle();
run = 1;
do {
cycle();
} while (stall());
return (struct idiv){ quot(), rem() };
}
int main() {
int count = 0;
int errors = 0;
for (int s = 0; s < 2; s++) {
for (int i = 0; i < numbers_cnt; i++) {
for (int j = 0; j < numbers_cnt; j++) {
struct idiv v = v_idiv(numbers[i], numbers[j], s);
struct idiv e = idiv(numbers[i], numbers[j], s);
bool error = v.quot != e.quot || v.rem != e.rem;
if (error && errors < 20) {
printf("idiv (signed=%d): 0x%x %d => v (%d,%d) | emu (%d,%d)\n",
s, numbers[i], numbers[j],
v.quot, v.rem, e.quot, e.rem);
}
errors += error;
count += 1;
}
if ((i % 500) == 0) {
int p = count * 100LL / numbers_cnt / numbers_cnt / 2;
printf("idiv: %d%% (%d errors)\n", p, errors);
}
}
}
printf("idiv: errors: %d tests: %d\n", errors, count);
return errors != 0;
}

View File

@ -123,3 +123,28 @@ uint32_t fp_div(uint32_t x, uint32_t y) {
}
}
struct idiv idiv(uint32_t x, uint32_t y, bool signed_div) {
bool sign = ((int32_t)x < 0) & signed_div;
uint32_t x0 = sign ? -x : x;
uint64_t RQ = x0;
for (int S = 0; S < 32; ++S) {
uint32_t w0 = (uint32_t)(RQ >> 31);
uint32_t w1 = w0 - y;
if ((int32_t)w1 < 0) {
RQ = ((uint64_t)w0 << 32) | ((RQ & 0x7FFFFFFFU) << 1);
} else {
RQ = ((uint64_t)w1 << 32) | ((RQ & 0x7FFFFFFFU) << 1) | 1;
}
}
struct idiv d = { (uint32_t)RQ, (uint32_t)(RQ >> 32) };
if (sign) {
d.quot = -d.quot;
if (d.rem) {
d.quot -= 1;
d.rem = y - d.rem;
}
}
return d;
}

View File

@ -8,4 +8,7 @@ uint32_t fp_add(uint32_t x, uint32_t y, bool u, bool v);
uint32_t fp_mul(uint32_t x, uint32_t y);
uint32_t fp_div(uint32_t x, uint32_t y);
struct idiv { uint32_t quot, rem; };
struct idiv idiv(uint32_t x, uint32_t y, bool signed_div);
#endif // RISC_FP_H

View File

@ -238,11 +238,7 @@ static void risc_single_step(struct RISC *risc) {
break;
}
case DIV: {
if ((int32_t)c_val <= 0) {
fprintf(stderr, "ERROR: PC 0x%08X: divisor %d is not positive\n", risc->PC*4 - 4, c_val);
a_val = 0xDEADBEEF;
risc->H = 0xDEADBEEF;
} else {
if ((int32_t)c_val > 0) {
if ((ir & ubit) == 0) {
a_val = (int32_t)b_val / (int32_t)c_val;
risc->H = (int32_t)b_val % (int32_t)c_val;
@ -254,6 +250,10 @@ static void risc_single_step(struct RISC *risc) {
a_val = b_val / c_val;
risc->H = b_val % c_val;
}
} else {
struct idiv q = idiv(b_val, c_val, ir & ubit);
a_val = q.quot;
risc->H = q.rem;
}
break;
}