From 70dbab69efde91b05c50b527d51d7ddda6970633 Mon Sep 17 00:00:00 2001 From: Peter De Wachter Date: Fri, 2 Oct 2015 00:21:50 +0200 Subject: [PATCH] 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. --- src/fp-test/.gitignore | 1 + src/fp-test/Makefile | 3 ++- src/fp-test/idiv.c | 50 ++++++++++++++++++++++++++++++++++++++++++ src/risc-fp.c | 25 +++++++++++++++++++++ src/risc-fp.h | 3 +++ src/risc.c | 10 ++++----- 6 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 src/fp-test/idiv.c diff --git a/src/fp-test/.gitignore b/src/fp-test/.gitignore index 1e38598..158856a 100644 --- a/src/fp-test/.gitignore +++ b/src/fp-test/.gitignore @@ -4,3 +4,4 @@ div flr flt mul +idiv diff --git a/src/fp-test/Makefile b/src/fp-test/Makefile index f686956..b1e5c0c 100644 --- a/src/fp-test/Makefile +++ b/src/fp-test/Makefile @@ -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 $< > $@ diff --git a/src/fp-test/idiv.c b/src/fp-test/idiv.c new file mode 100644 index 0000000..77923a1 --- /dev/null +++ b/src/fp-test/idiv.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#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; +} diff --git a/src/risc-fp.c b/src/risc-fp.c index 7a65fdc..9be028a 100644 --- a/src/risc-fp.c +++ b/src/risc-fp.c @@ -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; +} diff --git a/src/risc-fp.h b/src/risc-fp.h index 5cfedff..97ce59a 100644 --- a/src/risc-fp.h +++ b/src/risc-fp.h @@ -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 diff --git a/src/risc.c b/src/risc.c index f08f484..72d199f 100644 --- a/src/risc.c +++ b/src/risc.c @@ -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; }