From f9541157b62ec44deff0b906757c223ca0220102 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Sun, 12 May 2024 17:02:54 +0200 Subject: Division --- emulator/hart.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++-- emulator/hart_test.c | 30 ++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) (limited to 'emulator') diff --git a/emulator/hart.c b/emulator/hart.c index 101d77f..297148b 100644 --- a/emulator/hart.c +++ b/emulator/hart.c @@ -220,7 +220,7 @@ static void execute_op(Hart* hart, uint32_t instruction) } else if (bank == 1) { - if ((inst.funct3 & 0x8) == 0) + if ((inst.funct3 & 0x4) == 0) { uint64_t a = hart->regs[inst.rs1]; uint64_t b = hart->regs[inst.rs2]; @@ -241,7 +241,68 @@ static void execute_op(Hart* hart, uint32_t instruction) } else { - assert(!"Unhandled M OP"); + uint32_t a = hart->regs[inst.rs1]; + uint32_t b = hart->regs[inst.rs2]; + + switch (inst.funct3 & 0x3) + { + case 0: // DIV + { + if (b == 0) + { + hart->regs[inst.rd] = 0xFFFFFFFF; + } + else if (a == 0x80000000 && b == 0xFFFFFFFF) + { + hart->regs[inst.rd] = 0x80000000; + } + else + { + hart->regs[inst.rd] = (uint32_t)((int32_t)a / (int32_t)b); + } + break; + } + case 1: // DIVU + { + if (b == 0) + { + hart->regs[inst.rd] = 0xFFFFFFFF; + } + else + { + hart->regs[inst.rd] = a / b; + } + break; + } + case 2: // REM + { + if (b == 0) + { + hart->regs[inst.rd] = a; + } + else if (a == 0x80000000 && b == 0xFFFFFFFF) + { + hart->regs[inst.rd] = 0; + } + else + { + hart->regs[inst.rd] = (uint32_t)((int32_t)a % (int32_t)b); + } + break; + } + case 3: // REMU + { + if (b == 0) + { + hart->regs[inst.rd] = a; + } + else + { + hart->regs[inst.rd] = a % b; + } + break; + } + } } } else diff --git a/emulator/hart_test.c b/emulator/hart_test.c index 1611804..0dea92a 100644 --- a/emulator/hart_test.c +++ b/emulator/hart_test.c @@ -263,6 +263,36 @@ static void test_m() execute(&hart, 0x022091b3); // mulh x3, x1, x2 assert(hart.regs[3] == 0x00000000); + + hart.regs[1] = (uint32_t)-63; + hart.regs[2] = 4; + + execute(&hart, 0x0220c1b3); // div x3, x1, x2 + assert(hart.regs[3] == (uint32_t)-15); + + execute(&hart, 0x0220d1b3); // divu x3, x1, x2 + assert(hart.regs[3] == 0x3FFFFFF0); + + execute(&hart, 0x0220e1b3); // rem x3, x1, x2 + assert(hart.regs[3] == (uint32_t)-3); + + execute(&hart, 0x0220f1b3); // remu x3, x1, x2 + assert(hart.regs[3] == 1); + + hart.regs[1] = 30; + hart.regs[2] = 0; + + execute(&hart, 0x0220c1b3); // div x3, x1, x2 + assert(hart.regs[3] == 0xFFFFFFFF); + + execute(&hart, 0x0220d1b3); // divu x3, x1, x2 + assert(hart.regs[3] == 0xFFFFFFFF); + + execute(&hart, 0x0220e1b3); // rem x3, x1, x2 + assert(hart.regs[3] == 30); + + execute(&hart, 0x0220f1b3); // remu x3, x1, x2 + assert(hart.regs[3] == 30); } int main(int argc, char* argv[]) -- cgit