mirror of
https://github.com/libretro/oberon-risc-emu.git
synced 2025-03-03 08:29:34 +00:00
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:
parent
85ee2e5282
commit
70dbab69ef
1
src/fp-test/.gitignore
vendored
1
src/fp-test/.gitignore
vendored
@ -4,3 +4,4 @@ div
|
||||
flr
|
||||
flt
|
||||
mul
|
||||
idiv
|
||||
|
@ -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
50
src/fp-test/idiv.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
10
src/risc.c
10
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user