summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--emulator/hart.c65
-rw-r--r--emulator/hart_test.c30
2 files changed, 93 insertions, 2 deletions
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[])