From e55c3fde14fc2a63fba16033804e6fdb9840169d Mon Sep 17 00:00:00 2001 From: supersurviveur Date: Fri, 14 Nov 2025 19:08:41 +0100 Subject: [PATCH] Reduces LUT needed by mul extension --- Makefile | 2 +- bench/tests/op/div.s | 69 ++++++--- bench/tests/op/divu.s | 59 ++++++-- bench/tests/op/divuw.s | 59 ++++++-- bench/tests/op/divw.s | 69 ++++++--- bench/tests/op/mul.s | 54 +++++-- bench/tests/op/mulh.s | 57 +++++-- bench/tests/op/mulhsu.s | 58 ++++++-- bench/tests/op/mulhu.s | 60 ++++++-- bench/tests/op/mulw.s | 54 +++++-- bench/tests/op/rem.s | 71 ++++++--- bench/tests/op/remu.s | 66 +++++--- bench/tests/op/remuw.s | 71 ++++++--- bench/tests/op/remw.s | 71 ++++++--- src/main/scala/projet/Alu.scala | 190 ++++++++++++++++++------ src/main/scala/projet/Constants.scala | 5 + src/main/scala/projet/ControlUnit.scala | 6 + src/main/scala/projet/Divider.scala | 82 ++++++++++ src/main/scala/projet/Rv64i.scala | 38 +++-- src/main/scala/projet/Utils.scala | 15 ++ src/main/scala/projet/op/OpM.scala | 4 + src/test/scala/projet/ZzTopCommon.scala | 4 +- 22 files changed, 923 insertions(+), 241 deletions(-) create mode 100644 src/main/scala/projet/Constants.scala create mode 100644 src/main/scala/projet/Divider.scala create mode 100644 src/main/scala/projet/Utils.scala diff --git a/Makefile b/Makefile index 3e309af..1c67da7 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ OBJCOPY := $(PREFIX)objcopy OBTOMEM := common/objtomem.awk ## Flags -ASFLAGS :=-march=rv64i -mabi=lp64 -ffreestanding -nostdlib -T $(BENCH_DIR)/link.ld +ASFLAGS :=-march=rv64im -mabi=lp64 -ffreestanding -nostdlib -T $(BENCH_DIR)/link.ld CFLAGS :=$(ASFLAGS) ELFFLAGS :=$(ASFLAGS) $(MEM_DIR)/crt.o -Os -fno-unroll-loops ODFLAGS :=-j .text -j .rodata -j .data -s diff --git a/bench/tests/op/div.s b/bench/tests/op/div.s index 344269d..ac3806b 100644 --- a/bench/tests/op/div.s +++ b/bench/tests/op/div.s @@ -1,25 +1,60 @@ -# expected: ffffffffffffffff, ffffffffffffffff, dead0, 1, 8000000000000000, 7 .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) - li x8, (-324) - li x9, 0x8000000000000000 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, -123456 # -123456 + li x6, 0xdead0 # duplicate of x2 + li x7, -765432 # -765432 + li x8, 123456 # 123456 + li x9, -234567 # -234567 + li x10, 0x7fffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min negative 64b - # Div by 0 - div x31, x2, x3 - div x31, x5, x3 - - # Basic divisions + # 1. DIV : a / 1 div x31, x2, x4 + # expected: 00000000000dead0 + + # 2. DIV : a / a div x31, x2, x6 + # expected: 0000000000000001 - # Overflow - div x31, x9, x5 + # 3. DIV : negative / positive + div x31, x5, x8 + # expected: ffffffffffffffff - # Signed / signed + # 4. DIV : negative / positive div x31, x7, x8 + # expected: fffffffffffffffa + + # 5. DIV : positive / negative + div x31, x8, x7 + # expected: 0000000000000000 + + # 6. DIV : negative / negative + div x31, x7, x9 + # expected: 0000000000000003 + + # 7. DIV : max / 2 + li x12, 2 + div x31, x10, x12 + # expected: 3fffffffffffffff + + # 8. DIV : min / -1 + li x12, -1 # -1 + div x31, x11, x12 + # expected: 8000000000000000 + + # 9. DIV : min / 1 + div x31, x11, x4 + # expected: 8000000000000000 + + # 10. DIV : 0 / any + div x31, x3, x2 + # expected: 0000000000000000 + + # 11. DIV : any / 0 + div x31, x2, x0 + # expected: ffffffffffffffff + div x31, x7, x0 + # expected: ffffffffffffffff diff --git a/bench/tests/op/divu.s b/bench/tests/op/divu.s index dabe844..27dd519 100644 --- a/bench/tests/op/divu.s +++ b/bench/tests/op/divu.s @@ -1,14 +1,55 @@ -# expected: ffffffffffffffff, dead0, 1 .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x6, 0xdead0 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, 123456 # 123456 + li x6, 0xdead0 # duplicate of x2 + li x7, 765432 # 765432 + li x8, 123456 # 123456 + li x9, 234567 # 234567 + li x10, 0x7fffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min negative 64b (treated as unsigned = 0x8000...) - # Div by 0 - divu x31, x2, x3 - - # Basic divisions + # 1. DIVU : a / 1 divu x31, x2, x4 + # expected: 00000000000dead0 + + # 2. DIVU : a / a divu x31, x2, x6 + # expected: 0000000000000001 + + # 3. DIVU : smaller / larger + divu x31, x5, x8 + # expected: 0000000000000001 + + # 4. DIVU : larger / smaller + divu x31, x7, x8 + # expected: 0000000000000006 + + # 5. DIVU : any / any + divu x31, x8, x7 + # expected: 0000000000000000 + + # 6. DIVU : larger / larger + divu x31, x7, x9 + # expected: 0000000000000003 + + # 7. DIVU : max / 2 + li x12, 2 + divu x31, x10, x12 + # expected: 3fffffffffffffff + + # 8. DIVU : min / 1 + divu x31, x11, x4 + # expected: 8000000000000000 + + # 9. DIVU : 0 / any + divu x31, x3, x2 + # expected: 0000000000000000 + + # 10. DIVU : any / 0 + divu x31, x2, x0 + # expected: ffffffffffffffff + divu x31, x7, x0 + # expected: ffffffffffffffff diff --git a/bench/tests/op/divuw.s b/bench/tests/op/divuw.s index 25a763d..dee2053 100644 --- a/bench/tests/op/divuw.s +++ b/bench/tests/op/divuw.s @@ -1,14 +1,55 @@ -# expected: ffffffffffffffff, dead0, 1 .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x6, 0xdead0 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, -123456 # 0xfffe1dc0 (4294843840) + li x6, 0xdead0 # duplicate of x2 + li x7, -765432 # 0xffed32b8 (4294201864) + li x8, 123456 # 123456 + li x9, -234567 # 0xfffc7239 (4294732729) + li x10, 0xffffffff # max unsigned 32b (4294967295) + li x11, 0x80000000 # 2147483648 - # Div by 0 - divuw x31, x2, x3 - - # Basic divisions + # 1. DIVUW : a / 1 divuw x31, x2, x4 + # expected: 000000000000dead0 + + # 2. DIVUW : a / a divuw x31, x2, x6 + # expected: 0000000000000001 + + # 3. DIVUW : unsigned(0xfffe1dc0) / 123456 + divuw x31, x5, x8 + # expected: 00000000000087e4 + + # 4. DIVUW : unsigned(0xffed32b8) / 123456 + divuw x31, x7, x8 + # expected: 00000000000087df + + # 5. DIVUW : unsigned(123456) / unsigned(0xffed32b8) + divuw x31, x8, x7 + # expected: 0000000000000000 + + # 6. DIVUW : unsigned(x7) / unsigned(x9) + divuw x31, x7, x9 + # expected: 0000000000000000 + + # 7. DIVUW : max32 / 2 + li x12, 2 + divuw x31, x10, x12 + # expected: 000000007fffffff + + # 8. DIVUW : min32 / 1 + divuw x31, x11, x4 + # expected: ffffffff80000000 + + # 9. DIVUW : 0 / any + divuw x31, x0, x2 + # expected: 0000000000000000 + + # 10. DIVUW : any / 0 + divuw x31, x2, x0 + # expected: ffffffffffffffff + divuw x31, x7, x0 + # expected: ffffffffffffffff diff --git a/bench/tests/op/divw.s b/bench/tests/op/divw.s index 66a198c..b312084 100644 --- a/bench/tests/op/divw.s +++ b/bench/tests/op/divw.s @@ -1,25 +1,60 @@ -# expected: ffffffffffffffff, ffffffffffffffff, dead0, 1, ffffffff80000000, 7 .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) - li x8, (-324) - li x9, 0x80000000 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, -123456 # -123456 + li x6, 0xdead0 # duplicate of x2 + li x7, -765432 # -765432 + li x8, 123456 # 123456 + li x9, -234567 # -234567 + li x10, 0x7fffffff # max positive 32b + li x11, 0x80000000 # min negative 32b - # Div by 0 - divw x31, x2, x3 - divw x31, x5, x3 - - # Basic divisions + # 1. DIVW : a / 1 divw x31, x2, x4 + # expected: 000000000000dead0 + + # 2. DIVW : a / a divw x31, x2, x6 + # expected: 0000000000000001 - # Overflow - divw x31, x9, x5 + # 3. DIVW : negative / positive + divw x31, x5, x8 + # expected: ffffffffffffffff - # Signed / signed + # 4. DIVW : negative / positive divw x31, x7, x8 + # expected: fffffffffffffffa + + # 5. DIVW : positive / negative + divw x31, x8, x7 + # expected: 0000000000000000 + + # 6. DIVW : negative / negative + divw x31, x7, x9 + # expected: 0000000000000003 + + # 7. DIVW : max / 2 + li x12, 2 + divw x31, x10, x12 + # expected: 000000003fffffff + + # 8. DIVW : min / -1 + li x12, -1 # -1 + divw x31, x11, x12 + # expected: ffffffff80000000 + + # 9. DIVW : min / 1 + divw x31, x11, x4 + # expected: ffffffff80000000 + + # 10. DIVW : 0 / any + divw x31, x0, x2 + # expected: 0000000000000000 + + # 11. DIVW : any / 0 + divw x31, x2, x0 + # expected: ffffffffffffffff + divw x31, x7, x0 + # expected: ffffffffffffffff diff --git a/bench/tests/op/mul.s b/bench/tests/op/mul.s index ce007ef..76b902b 100644 --- a/bench/tests/op/mul.s +++ b/bench/tests/op/mul.s @@ -1,22 +1,54 @@ -# expected: 0000000000000000, 00000000000dead0, c1b080e900, -dead0, 54a029 .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) + li x2, 0xdead0 # +912080 + li x3, 0 # zero + li x4, 1 # one + li x5, -1 # -1 + li x6, 0xdead0 # duplicate of x2 + li x7, -2355 # negative + li x8, 123456 # positive + li x9, -765432 # negative + li x10, 0x7fffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min negative 64b - # Mul 0 + # -------------------------------------------------------------- + # 1. MUL : a * 0 mul x31, x2, x3 + # expected: 0000000000000000 - # Basic multiplications + # 2. MUL : a * 1 mul x31, x2, x4 + # expected: 00000000000dead0 + + # 3. MUL : a * a mul x31, x2, x6 + # expected: 0000000c1b080e900 - # Overflow + # 4. MUL : -1 * a mul x31, x5, x2 + # expected: -00000000000dead0 - # Signed * signed + # 5. MUL : negative * negative mul x31, x7, x7 + # expected: 000000000054a029 + + # 6. MUL : negative * positive + mul x31, x7, x8 + # expected: -00000000115452c0 + + # 7. MUL : positive * negative + mul x31, x8, x9 + # expected: -0000001600786e00 + + # 8. MUL : overflow example (max * 2) + li x12, 2 + mul x31, x10, x12 + # expected: fffffffffffffffe + + # 9. MUL : max * max + mul x31, x10, x10 + # expected: 0000000000000001 + + # 10. MUL : min * min + mul x31, x11, x11 + # expected: 0000000000000000 diff --git a/bench/tests/op/mulh.s b/bench/tests/op/mulh.s index 7eb3d98..69ee483 100644 --- a/bench/tests/op/mulh.s +++ b/bench/tests/op/mulh.s @@ -1,19 +1,54 @@ -# expected: 0000000000000000, 0000000000000000, c1b080e9, ffffffffffffffff .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, 0xdead00000000 + li x2, 0xdead00000 # +59774074880 + li x3, 0 # zero + li x4, 1 # one + li x5, -1 # -1 + li x6, 0xdead00000 # duplicate of x2 + li x7, -235555555555 # negative + li x8, 123456789 # positive + li x9, -765432000000 # negative + li x10, 0x7fffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min negative 64b - # Mul 0 + # -------------------------------------------------------------- + # 1. MULH : a * 0 mulh x31, x2, x3 + # expected: 0000000000000000 - # Basic multiplications + # 2. MULH : a * 1 mulh x31, x2, x4 - mulh x31, x7, x7 + # expected: 0000000000000000 - # Overflow + # 3. MULH : a * a + mulh x31, x2, x6 + # expected: 00000000000000c1 + + # 4. MULH : -1 * a mulh x31, x5, x2 + # expected: ffffffffffffffff + + # 5. MULH : negative * negative + mulh x31, x7, x7 + # expected: 0000000000000bbf + + # 6. MULH : negative * positive + mulh x31, x7, x8 + # expected: fffffffffffffffe + + # 7. MULH : positive * negative + mulh x31, x8, x9 + # expected: fffffffffffffffa + + # 8. MULH : overflow example (max * 2) + li x12, 2 + mulh x31, x10, x12 + # expected: 0000000000000000 + + # 9. MULH : max * max + mulh x31, x10, x10 + # expected: 3fffffffffffffff + + # 10. MULH : min * min + mulh x31, x11, x11 + # expected: 4000000000000000 diff --git a/bench/tests/op/mulhsu.s b/bench/tests/op/mulhsu.s index 57c2d10..977101f 100644 --- a/bench/tests/op/mulhsu.s +++ b/bench/tests/op/mulhsu.s @@ -1,20 +1,54 @@ -# expected: 0000000000000000, 0000000000000000, c1b080e9, ffffffffffffffff, deacf .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, 0xdead00000000 + li x2, 0xdead00000 # +59774074880 + li x3, 0 # zero + li x4, 1 # one + li x5, -1 # -1 + li x6, 0xdead00000 # duplicate of x2 + li x7, -235555555555 # negative + li x8, 123456789 # positive + li x9, 765432000000 # positive + li x10, 0x7fffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min negative 64b - # Mul 0 + # -------------------------------------------------------------- + # 1. MULHSU : a * 0 mulhsu x31, x2, x3 + # expected: 0000000000000000 - # Basic multiplications + # 2. MULHSU : a * 1 mulhsu x31, x2, x4 - mulhsu x31, x7, x7 + # expected: 0000000000000000 - # Overflow + # 3. MULHSU : a * a + mulhsu x31, x2, x6 + # expected: 00000000000000c1 + + # 4. MULHSU : -1 * a mulhsu x31, x5, x2 - mulhsu x31, x2, x5 + # expected: ffffffffffffffff + + # 5. MULHSU : negative * positive + mulhsu x31, x7, x8 + # expected: fffffffffffffffe + + # 6. MULHSU : negative * positive large + mulhsu x31, x7, x9 + # expected: ffffffffffffd9d1 + + # 7. MULHSU : positive * positive + mulhsu x31, x8, x9 + # expected: 0000000000000005 + + # 8. MULHSU : overflow example (max * 2) + li x12, 2 + mulhsu x31, x10, x12 + # expected: 0000000000000000 + + # 9. MULHSU : max * max + mulhsu x31, x10, x10 + # expected: 3fffffffffffffff + + # 10. MULHSU : min * max + mulhsu x31, x11, x10 + # expected: c000000000000000 diff --git a/bench/tests/op/mulhu.s b/bench/tests/op/mulhu.s index a77da19..9a09c8b 100644 --- a/bench/tests/op/mulhu.s +++ b/bench/tests/op/mulhu.s @@ -1,20 +1,54 @@ -# expected: 0000000000000000, 0000000000000000, c1b080e9, deacf, deacf .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, 0xdead00000000 + li x2, 0xdead00000 # +59774074880 + li x3, 0 # zero + li x4, 1 # one + li x5, 123456789 # small positive + li x6, 0xdead00000 # duplicate of x2 + li x7, 765432000000 # large positive + li x8, 123456789 # small positive + li x9, 234567890000 # large positive + li x10, 0xffffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min unsigned = 2^63 - # Mul 0 + # -------------------------------------------------------------- + # 1. MULHU : a * 0 mulhu x31, x2, x3 + # expected: 0000000000000000 - # Basic multiplications + # 2. MULHU : a * 1 mulhu x31, x2, x4 - mulhu x31, x7, x7 + # expected: 0000000000000000 - # Overflow - mulhu x31, x5, x2 - mulhu x31, x2, x5 + # 3. MULHU : a * a + mulhu x31, x2, x6 + # expected: 00000000000000c1 + + # 4. MULHU : small * small + mulhu x31, x5, x8 + # expected: 0000000000000000 + + # 5. MULHU : small * large + mulhu x31, x5, x7 + # expected: 0000000000000005 + + # 6. MULHU : large * small + mulhu x31, x7, x8 + # expected: 0000000000000005 + + # 7. MULHU : large * large + mulhu x31, x7, x9 + # expected: 0000000000002605 + + # 8. MULHU : max * 2 + li x12, 2 + mulhu x31, x10, x12 + # expected: 0000000000000001 + + # 9. MULHU : max * max + mulhu x31, x10, x10 + # expected: fffffffffffffffe + + # 10. MULHU : min * max + mulhu x31, x11, x10 + # expected: 7fffffffffffffff diff --git a/bench/tests/op/mulw.s b/bench/tests/op/mulw.s index cc96cae..cd4f938 100644 --- a/bench/tests/op/mulw.s +++ b/bench/tests/op/mulw.s @@ -1,22 +1,54 @@ -# expected: 0000000000000000, 00000000000dead0, ffffffffb080e900, -dead0, 54a029 .text _start: - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) + li x2, 0xdead0 # +912080 + li x3, 0 # zero + li x4, 1 # one + li x5, -1 # -1 + li x6, 0xdead0 # duplicate of x2 + li x7, -2355 # negative + li x8, 123456 # positive + li x9, -765432 # negative + li x10, 0x7fffffff # max positive 32b + li x11, 0x80000000 # min negative 32b - # Mul 0 + # -------------------------------------------------------------- + # 1. MULW : a * 0 mulw x31, x2, x3 + # expected: 0000000000000000 - # Basic multiplications + # 2. MULW : a * 1 mulw x31, x2, x4 + # expected: 000000000000dead0 + + # 3. MULW : a * a mulw x31, x2, x6 + # expected: FFFFFFFFB080E900 - # Overflow + # 4. MULW : -1 * a mulw x31, x5, x2 + # expected: -dead0 - # Signed * signed + # 5. MULW : negative * negative mulw x31, x7, x7 + # expected: 000000000054A029 + + # 6. MULW : negative * positive + mulw x31, x7, x8 + # expected: FFFFFFFFEEABAD40 + + # 7. MULW : positive * negative + mulw x31, x8, x9 + # expected: FFFFFFFFFF879200 + + # 8. MULW : overflow example (max * 2) + li x12, 2 + mulw x31, x10, x12 + # expected: fffffffffffffffe + + # 9. MULW : max * max + mulw x31, x10, x10 + # expected: 0000000000000001 + + # 10. MULW : min * min + mulw x31, x11, x11 + # expected: 0000000000000000 diff --git a/bench/tests/op/rem.s b/bench/tests/op/rem.s index 3b59175..b765a36 100644 --- a/bench/tests/op/rem.s +++ b/bench/tests/op/rem.s @@ -1,27 +1,60 @@ -# expected: dead0, ffffffffffffffff, 0, 0, 18, 0, -57 .text _start: - li x1, 0x0293 - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) - li x8, (-324) - li x9, 0x8000000000000000 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, -123456 # -123456 + li x6, 0xdead0 # duplicate of x2 + li x7, -765432 # -765432 + li x8, 123456 # 123456 + li x9, -234567 # -234567 + li x10, 0x7fffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min negative 64b - # Remainder by 0 - rem x31, x2, x3 - rem x31, x5, x3 - - # Basic remainders + # 1. REM : a % 1 rem x31, x2, x4 + # expected: 0000000000000000 + + # 2. REM : a % a rem x31, x2, x6 - rem x31, x6, x1 + # expected: 0000000000000000 - # Overflow - rem x31, x9, x5 + # 3. REM : negative % positive + rem x31, x5, x8 + # expected: 0000000000000000 - # Signed / signed + # 4. REM : negative % positive rem x31, x7, x8 + # expected: 00000000000181c8 + + # 5. REM : positive % negative + rem x31, x8, x7 + # expected: -9cbb8 + + # 6. REM : negative % negative + rem x31, x7, x9 + # expected: -f123 + + # 7. REM : max % 2 + li x12, 2 + rem x31, x10, x12 + # expected: 0000000000000001 + + # 8. REM : min % -1 + li x12, -1 + rem x31, x11, x12 + # expected: 0000000000000000 + + # 9. REM : min % 1 + rem x31, x11, x4 + # expected: 0000000000000000 + + # 10. REM : 0 % any + rem x31, x3, x2 + # expected: 0000000000001234 + + # 11. REM : any % 0 + rem x31, x2, x0 + # expected: 00000000000dead0 + rem x31, x7, x0 + # expected: -badf8 diff --git a/bench/tests/op/remu.s b/bench/tests/op/remu.s index 5ff7246..64d6e62 100644 --- a/bench/tests/op/remu.s +++ b/bench/tests/op/remu.s @@ -1,27 +1,55 @@ -# expected: dead0, ffffffffffffffff, 0, 0, 18, 8000000000000000, fffffffffffff6cd .text _start: - li x1, 0x0293 - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) - li x8, (-324) - li x9, 0x8000000000000000 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, 123456 # 123456 + li x6, 0xdead0 # duplicate of x2 + li x7, 765432 # 765432 + li x8, 123456 # 123456 + li x9, 234567 # 234567 + li x10, 0x7fffffffffffffff # max positive 64b + li x11, 0x8000000000000000 # min negative 64b - # Remainder by 0 - remu x31, x2, x3 - remu x31, x5, x3 - - # Basic remainders + # 1. REMU : a % 1 remu x31, x2, x4 + # expected: 0000000000000000 + + # 2. REMU : a % a remu x31, x2, x6 - remu x31, x6, x1 + # expected: 0000000000000000 - # Overflow - remu x31, x9, x5 + # 3. REMU : smaller % larger + remu x31, x5, x7 + # expected: 000000000001e240 - # Signed / signed + # 4. REMU : larger % smaller remu x31, x7, x8 + # expected: 0000000000006078 + + # 5. REMU : any % any + remu x31, x8, x7 + # expected: 000000000001e240 + + # 6. REMU : larger % larger + remu x31, x7, x9 + # expected: 000000000000f123 + + # 7. REMU : max % 2 + li x12, 2 + remu x31, x10, x12 + # expected: 0000000000000001 + + # 8. REMU : min % 1 + remu x31, x11, x4 + # expected: 0000000000000000 + + # 9. REMU : 0 % any + remu x31, x3, x2 + # expected: 0000000000001234 + + # 10. REMU : any % 0 + remu x31, x2, x0 + # expected: 00000000000dead0 + remu x31, x7, x0 + # expected: 00000000000badf8 diff --git a/bench/tests/op/remuw.s b/bench/tests/op/remuw.s index bfecbae..e20ca0b 100644 --- a/bench/tests/op/remuw.s +++ b/bench/tests/op/remuw.s @@ -1,27 +1,60 @@ -# expected: dead0, ffffffffffffffff, 0, 0, 18, ffffffff80000000, fffffffffffff6cd .text _start: - li x1, 0x0293 - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) - li x8, (-324) - li x9, 0x80000000 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, -123456 # 0xfffe1dc0 (4294843840) + li x6, 0xdead0 # duplicate of x2 + li x7, -765432 # 0xffed32b8 (4294201864) + li x8, 123456 # 123456 + li x9, -234567 # 0xfffc7239 (4294732729) + li x10, 0xffffffff # max unsigned 32b + li x11, 0x80000000 # 2147483648 - # Remainder by 0 - remuw x31, x2, x3 - remuw x31, x5, x3 - - # Basic remainders + # 1. REMUW : a % 1 remuw x31, x2, x4 + # expected: 0000000000000000 + + # 2. REMUW : a % a remuw x31, x2, x6 - remuw x31, x6, x1 + # expected: 0000000000000000 - # Overflow - remuw x31, x9, x5 + # 3. REMUW : unsigned(x5) % x8 + remuw x31, x5, x8 + # expected: 000000000000dcc0 - # Signed / signed + # 4. REMUW : unsigned(x7) % x8 remuw x31, x7, x8 + # expected: 0000000000007c48 + + # 5. REMUW : x8 % unsigned(x7) + remuw x31, x8, x7 + # expected: 000000000001e240 + + # 6. REMUW : unsigned(x7) % unsigned(x9) + remuw x31, x7, x9 + # expected: fffffffffff45208 + + # 7. REMUW : max32 % 2 + li x12, 2 + remuw x31, x10, x12 + # expected: 0000000000000001 + + # 8. REMUW : min32 % -1 + remuw x31, x11, x12 + # expected: 0000000000000000 + + # 9. REMUW : min32 % 1 + remuw x31, x11, x4 + # expected: 0000000000000000 + + # 10. REMUW : 0 % any + remuw x31, x3, x2 + # expected: 0000000000001234 + + # 11. REMUW : any % 0 + remuw x31, x2, x0 + # expected: 00000000000dead0 + + remuw x31, x7, x0 + # expected: FFFFFFFFFFF45208 diff --git a/bench/tests/op/remw.s b/bench/tests/op/remw.s index 2c08bbe..bcb531e 100644 --- a/bench/tests/op/remw.s +++ b/bench/tests/op/remw.s @@ -1,27 +1,60 @@ -# expected: dead0, ffffffffffffffff, 0, 0, 18, 0, -57 .text _start: - li x1, 0x0293 - li x2, 0xdead0 - li x3, 0x0 - li x4, 0x1 - li x5, (-1) - li x6, 0xdead0 - li x7, (-2355) - li x8, (-324) - li x9, 0x80000000 + li x2, 0xdead0 # 912080 + li x3, 0x1234 # 4660 + li x4, 1 # 1 + li x5, -123456 # -123456 + li x6, 0xdead0 # duplicate of x2 + li x7, -765432 # -765432 + li x8, 123456 # 123456 + li x9, -234567 # -234567 + li x10, 0x7fffffff # max positive 32b + li x11, 0x80000000 # min negative 32b - # Remainder by 0 - remw x31, x2, x3 - remw x31, x5, x3 - - # Basic remainders + # 1. REMW : a % 1 remw x31, x2, x4 + # expected: 0000000000000000 + + # 2. REMW : a % a remw x31, x2, x6 - remw x31, x6, x1 + # expected: 0000000000000000 - # Overflow - remw x31, x9, x5 + # 3. REMW : negative % positive + remw x31, x5, x8 + # expected: 0 - # Signed / signed + # 4. REMW : negative % positive remw x31, x7, x8 + # expected: 181c8 + + # 5. REMW : positive % negative + remw x31, x8, x7 + # expected: fffffffffff63448 + + # 6. REMW : negative % negative + remw x31, x7, x9 + # expected: ffffffffffff0edd + + # 7. REMW : max % 2 + li x12, 2 + remw x31, x10, x12 + # expected: 00000001 + + # 8. REMW : min % -1 + li x12, -1 + remw x31, x11, x12 + # expected: 00000000 + + # 9. REMW : min % 1 + remw x31, x11, x4 + # expected: 00000000 + + # 10. REMW : 0 % any + remw x31, x3, x2 + # expected: 00001234 + + # 11. REMW : any % 0 + remw x31, x2, x0 + # expected: 000dead0 + remw x31, x7, x0 + # expected: -badf8 diff --git a/src/main/scala/projet/Alu.scala b/src/main/scala/projet/Alu.scala index 8461253..68aa7da 100644 --- a/src/main/scala/projet/Alu.scala +++ b/src/main/scala/projet/Alu.scala @@ -5,10 +5,9 @@ import chisel3.util.switch import chisel3.util.is object AluOpCode extends ChiselEnum { - val Add, Sub, Mul, Mulh, Mulhsu, Mulhu, Div, Divu, Rem, Remu, Mulw, Divw, - Divuw, Remw, Remuw, And, Or, Xor, ShiftLeft, ShiftRight, - ShiftArithmeticRight, LessThanSigned, LessThanUnsigned, - GreaterEqualSigned, GreaterEqualUnsigned, Equal = + val Add, Sub, Mul, Mulh, Mulhsu, Mulhu, Div, Divu, Rem, Remu, And, Or, Xor, + ShiftLeft, ShiftRight, ShiftArithmeticRight, LessThanSigned, + LessThanUnsigned, GreaterEqualSigned, GreaterEqualUnsigned, Equal = Value } @@ -22,12 +21,16 @@ class Alu extends Module { val opcode = Input(AluOpCode()) val comp_result = Output(Bool()) + // Should stop the stall for the current computation (e.g. Division) + val should_stop_stall = Output(Bool()) + // ~~ Rv64i ~~ // If word_mode is enabled, operations are performed // on 32-bit-truncated inputs and then sign extended to 64bits val word_mode = Input(Bool()) }) + io.should_stop_stall := false.B io.out := 0.U; io.comp_result := false.B; val out = WireInit(0.U(64.W)) @@ -37,16 +40,56 @@ class Alu extends Module { // Defaults op_a := io.a op_b := io.b + val op_a_sign = WireInit(op_a(63)) + val op_b_sign = WireInit(op_b(63)) + val op_a_unsigned = WireInit(op_a) + val op_b_unsigned = WireInit(op_b) io.out := out // Truncate operands, sext result when(io.word_mode) { op_a := io.a(31, 0) op_b := io.b(31, 0) + op_a_sign := op_a(31) + op_b_sign := op_b(31) io.out := SignExtend.Sext(out(31, 0), 64) } + when(op_a_sign) { + op_a_unsigned := Utils.two_complement(op_a, io.word_mode) + } + when(op_b_sign) { + op_b_unsigned := Utils.two_complement(op_b, io.word_mode) + } + + val in_computation = RegInit(false.B) + + // Division + val divider = Module(new Divider(64, Constants.DIVISION_CYCLES_COUNT)) + divider.io.word_mode := io.word_mode + divider.io.dividend := op_a_unsigned + divider.io.divisor := op_b_unsigned + divider.io.start := false.B + def div_by_zero() = { + when(io.word_mode) { + out := (-1).S(32.W).asUInt + }.otherwise { + out := (-1).S(64.W).asUInt + } + } + + // Multiplication + val multiplication_res = op_a * op_b // Mul non signée + val multiplication_low = + Mux(io.word_mode, multiplication_res(31, 0), multiplication_res(63, 0)) + val multiplication_high = + Mux( + io.word_mode, + multiplication_res(63, 32), + multiplication_res(127, 64) + ) + switch(io.opcode) { is(Add) { out := op_a + op_b; @@ -57,56 +100,77 @@ class Alu extends Module { } is(Mul) { - out := (io.a.asSInt * io.b.asSInt).asUInt; + out := multiplication_low; } is(Mulh) { - out := ((io.a.asSInt * io.b.asSInt) >> 64.U).asUInt; + val correction = + Mux(op_a_sign, op_b, 0.U) + Mux(op_b_sign, op_a, 0.U) + val multiplication_res_with_correction = + multiplication_high - correction + out := multiplication_res_with_correction; } is(Mulhsu) { - out := ((io.a.asSInt * io.b).asSInt >> 64.U).asUInt; + val correction = + Mux(op_a_sign, op_b, 0.U) + val multiplication_res_with_correction = + multiplication_high - correction + out := multiplication_res_with_correction; } is(Mulhu) { - out := (io.a * io.b) >> 64.U; + out := multiplication_high; } - // is(Div) { - // when(io.b === 0.U) { - // when(io.word_mode) { - // out := (-1).S(32.W).asUInt - // }.otherwise { - // out := (-1).S(64.W).asUInt - // } - // }.otherwise { - // out := (io.a.asSInt / io.b.asSInt).asUInt; - // } - // } - // - // is(Divu) { - // when(io.b === 0.U) { - // out := "xFFFFFFFFFFFFFFFF".U - // }.otherwise { - // out := io.a / io.b; - // } - // } - // - // is(Rem) { - // when(io.b === 0.U) { - // out := io.a - // }.otherwise { - // out := (io.a.asSInt % io.b.asSInt).asUInt; - // } - // } - // - // is(Remu) { - // when(io.b === 0.U) { - // out := io.a - // }.otherwise { - // out := io.a % io.b; - // } - // } + is(Div) { + when(op_b === 0.U) { + div_by_zero() + }.elsewhen(op_a_sign ^ op_b_sign) { + out := Utils.two_complement(divider.io.quotient, io.word_mode) + }.otherwise { + out := divider.io.quotient + } + } + + is(Divu) { + divider.io.dividend := op_a + divider.io.divisor := op_b + when(op_b === 0.U) { + div_by_zero() + }.otherwise { out := divider.io.quotient; } + } + + is(Rem) { + when(op_b === 0.U) { + out := op_a + }.elsewhen( + op_a_sign && !op_b_sign && divider.io.remainder =/= 0.U + ) { + out := op_b - divider.io.remainder + }.elsewhen( + !op_a_sign && op_b_sign && divider.io.remainder =/= 0.U + ) { + out := Utils.two_complement( + Utils.two_complement(op_b) - divider.io.remainder, + io.word_mode + ) + }.elsewhen(op_a_sign && op_b_sign) { + out := Utils.two_complement(divider.io.remainder, io.word_mode) + }.otherwise { + out := divider.io.remainder + } + } + + is(Remu) { + divider.io.dividend := op_a + divider.io.divisor := op_b + when(op_b === 0.U) { + out := op_a + }.otherwise { + out := divider.io.remainder + } + } is(And) { out := op_a & op_b; @@ -167,4 +231,44 @@ class Alu extends Module { } } + switch(io.opcode) { + is(Div, Divu, Rem, Remu) { + when(!in_computation) { + divider.io.start := true.B + in_computation := true.B + }.elsewhen(divider.io.ready) { + io.should_stop_stall := true.B + in_computation := false.B + } + } + } + + // Special overflow cases for Div and Rem + when( + io.word_mode && + op_b === ((BigInt(1) << 32) - 1).U(32.W) && + op_a === (-1).S(32.W).asUInt + ) { + switch(io.opcode) { + is(Div) { + out := (1.U << 31) + } + is(Rem) { + out := 0.U + } + } + }.elsewhen( + !io.word_mode && + op_b === ((BigInt(1) << 64) - 1).U(64.W) && + op_a === (-1).S(64.W).asUInt + ) { + switch(io.opcode) { + is(Div) { + out := (1.U << 63) + } + is(Rem) { + out := 0.U + } + } + } } diff --git a/src/main/scala/projet/Constants.scala b/src/main/scala/projet/Constants.scala new file mode 100644 index 0000000..266dbfc --- /dev/null +++ b/src/main/scala/projet/Constants.scala @@ -0,0 +1,5 @@ +package projet + +object Constants { + def DIVISION_CYCLES_COUNT = 8 +} diff --git a/src/main/scala/projet/ControlUnit.scala b/src/main/scala/projet/ControlUnit.scala index e7c21b6..a188635 100644 --- a/src/main/scala/projet/ControlUnit.scala +++ b/src/main/scala/projet/ControlUnit.scala @@ -25,6 +25,10 @@ class CUInterface extends Bundle { // True if the decoded instruction is a jump val is_jump = Output(Bool()) + // Stall the pipeline on the current instruction + val should_stall = Output(Bool()) + val should_stop_stall = Output(Bool()) + // DMem connections val memory_size = Output(DMemSize()) val memory_en = Output(Bool()) @@ -126,6 +130,8 @@ class ControlUnit() extends Module { io.alu_word_mode := false.B io.optype := OpType.U io.is_jump := false.B; + io.should_stall := false.B; + io.should_stop_stall := false.B; io.memory_size := DMemSize.Word io.memory_en := false.B io.memory_we := false.B diff --git a/src/main/scala/projet/Divider.scala b/src/main/scala/projet/Divider.scala new file mode 100644 index 0000000..8a3f04d --- /dev/null +++ b/src/main/scala/projet/Divider.scala @@ -0,0 +1,82 @@ +package projet + +import chisel3._ +import chisel3.util._ + +class Divider(width: Int, nCycles: Int) extends Module { + require( + nCycles >= 1 && nCycles <= width, + "nCycles must be between 1 and width" + ) + + val io = IO(new Bundle { + val dividend = Input(UInt(width.W)) + val divisor = Input(UInt(width.W)) + val word_mode = Input(Bool()) + val start = Input(Bool()) + val ready = Output(Bool()) + val quotient = Output(UInt(width.W)) + val remainder = Output(UInt(width.W)) + }) + + val reg_dividend = Reg(UInt(width.W)) + val reg_divisor = Reg(UInt((width * 2).W)) + val reg_divisor_start = Reg(UInt(width.W)) + val reg_quotient = Reg(UInt(width.W)) + val reg_current_shift = Reg(UInt((log2Ceil(width) + 1).W)) + + val bits_per_cycle = ((width + nCycles - 1) / nCycles) + + val cycles_remaining = RegInit(0.U(log2Ceil(nCycles + 1).W)) + val busy = RegInit(false.B) + + io.ready := !busy + io.quotient := reg_quotient + io.remainder := reg_dividend(width - 1, 0) + + when(io.start && !busy) { + reg_dividend := io.dividend + reg_divisor := io.divisor << (width - 1) + reg_divisor_start := io.divisor + reg_quotient := 0.U + reg_current_shift := (width - 1).U + cycles_remaining := nCycles.U + busy := true.B + } + + when(busy) { + val stages = Wire(Vec(bits_per_cycle + 1, UInt(width.W))) + val dstages = Wire(Vec(bits_per_cycle + 1, UInt((width * 2).W))) + val qstages = Wire(Vec(bits_per_cycle + 1, UInt(width.W))) + + stages(0) := reg_dividend + dstages(0) := reg_divisor + qstages(0) := reg_quotient + + for (i <- 0 until bits_per_cycle) { + val cur = stages(i) + val curD = dstages(i) + val curQ = qstages(i) + + when(cur >= curD) { + stages(i + 1) := cur - curD + qstages(i + 1) := curQ + (1.U << (reg_current_shift - i.U)) + }.otherwise { + stages(i + 1) := cur + qstages(i + 1) := curQ + + } + dstages(i + 1) := curD >> 1 + } + + reg_dividend := stages(bits_per_cycle) + reg_divisor := dstages(bits_per_cycle) + reg_quotient := qstages(bits_per_cycle) + reg_current_shift := reg_current_shift - bits_per_cycle.U + + cycles_remaining := cycles_remaining - 1.U + when(cycles_remaining === 1.U) { + busy := false.B + } + } +} diff --git a/src/main/scala/projet/Rv64i.scala b/src/main/scala/projet/Rv64i.scala index b7f549b..aab3664 100644 --- a/src/main/scala/projet/Rv64i.scala +++ b/src/main/scala/projet/Rv64i.scala @@ -37,27 +37,44 @@ class Rv64i(sim: Boolean = true) extends Module { // True if the instruction in the execute stage is a jump val is_jump = Delay.Delay(control_unit.io.is_jump, 1, false.B); + // Insert no-op if jump + val decoded_instruction = + Mux( + is_jump, + "b00000000000000000000000000010011".U, + io.ibus.rdata >> (execute_pc(2) * 32.U) + ) + + val stalled_instruction = RegInit(0.U) + val should_stop_stall = + control_unit.io.should_stop_stall || alu.io.should_stop_stall + val is_stalled = RegInit(false.B) + val is_immediatly_stalled = + (!should_stop_stall && (is_stalled || control_unit.io.should_stall =/= 0.U)) + when(!is_stalled && control_unit.io.should_stall =/= 0.U) { + // Stall the pipeline + is_stalled := true.B + stalled_instruction := decoded_instruction + } + when(is_stalled && should_stop_stall) { + is_stalled := false.B + } + + val instruction = Mux(is_stalled, stalled_instruction, decoded_instruction) + // Pipelining registers for mem stage val reg_rd_index = RegInit(0.U); val reg_execute_out = RegInit(0.U); val reg_mux_executeout_dout = RegInit(true.B); val reg_regile_we = RegInit(false.B); - // Insert no-op if jump - val instruction = - Mux( - is_jump, - "b00000000000000000000000000010011".U, - io.ibus.rdata >> (execute_pc(2) * 32.U) - ); - immediate_decoder.io.instruction := instruction immediate_decoder.io.op_type := control_unit.io.optype alu.io.opcode := control_unit.io.alu_opcode; // Reg file write-enable reg_regile_we := control_unit.io.reg_file_we; - reg_file.io.we := reg_regile_we; + reg_file.io.we := reg_regile_we && !is_stalled; // Increment PC each clock val pc_adder_out = Mux( @@ -153,4 +170,7 @@ class Rv64i(sim: Boolean = true) extends Module { false.B ) + when(is_immediatly_stalled) { + reg_pc := reg_pc + } } diff --git a/src/main/scala/projet/Utils.scala b/src/main/scala/projet/Utils.scala new file mode 100644 index 0000000..8548b49 --- /dev/null +++ b/src/main/scala/projet/Utils.scala @@ -0,0 +1,15 @@ +package projet + +import chisel3._ + +object Utils { + def two_complement(x: UInt, word_sized: Bool = false.B): UInt = { + val result = Wire(UInt(64.W)) + when(word_sized) { + result := "xFFFFFFFF".U - x + 1.U + }.otherwise { + result := "xFFFFFFFFFFFFFFFF".U - x + 1.U + } + result + } +} diff --git a/src/main/scala/projet/op/OpM.scala b/src/main/scala/projet/op/OpM.scala index 551d957..1d00b51 100644 --- a/src/main/scala/projet/op/OpM.scala +++ b/src/main/scala/projet/op/OpM.scala @@ -38,15 +38,19 @@ object OpM { } is(Funct3.DIV) { io.alu_opcode := AluOpCode.Div + io.should_stall := true.B } is(Funct3.DIVU) { io.alu_opcode := AluOpCode.Divu + io.should_stall := true.B } is(Funct3.REM) { io.alu_opcode := AluOpCode.Rem + io.should_stall := true.B } is(Funct3.REMU) { io.alu_opcode := AluOpCode.Remu + io.should_stall := true.B } } } diff --git a/src/test/scala/projet/ZzTopCommon.scala b/src/test/scala/projet/ZzTopCommon.scala index 128cb94..8bf82c0 100644 --- a/src/test/scala/projet/ZzTopCommon.scala +++ b/src/test/scala/projet/ZzTopCommon.scala @@ -10,9 +10,9 @@ object ZzTopCommon extends AnyFreeSpec with ChiselSim { Source .fromFile(path) .getLines() - .filter(_.startsWith("# expected:")) + .filter(_.trim().startsWith("# expected:")) .map( - _.stripPrefix("# expected:") + _.trim().stripPrefix("# expected:") .split(",") .map(_.trim) .filter(_.nonEmpty)