aboutsummaryrefslogtreecommitdiff
path: root/machine/muldiv_emulation.c
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2016-03-09 23:54:14 -0800
committerAndrew Waterman <waterman@cs.berkeley.edu>2016-03-09 23:58:39 -0800
commitccf79891f0f1fcb570f9a63c15270b52477fe7c0 (patch)
treee86a1ef10afca65db9908df90616f58fd8fdbeb5 /machine/muldiv_emulation.c
parentb94c7a4b07f96f24ae7411780abf874416549f7b (diff)
downloadpk-ccf79891f0f1fcb570f9a63c15270b52477fe7c0.zip
pk-ccf79891f0f1fcb570f9a63c15270b52477fe7c0.tar.gz
pk-ccf79891f0f1fcb570f9a63c15270b52477fe7c0.tar.bz2
Factor emulation routines into multiple files
Diffstat (limited to 'machine/muldiv_emulation.c')
-rw-r--r--machine/muldiv_emulation.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/machine/muldiv_emulation.c b/machine/muldiv_emulation.c
new file mode 100644
index 0000000..d0583c5
--- /dev/null
+++ b/machine/muldiv_emulation.c
@@ -0,0 +1,64 @@
+#include "emulation.h"
+
+#ifndef __riscv_muldiv
+
+#ifdef __riscv64
+typedef __int128 double_int;
+#else
+typedef int64_t double_int;
+#endif
+
+// These routines rely on the compiler to turn these operations into libcalls
+// when not natively supported. So work on making those go fast.
+
+DECLARE_EMULATION_FUNC(emulate_mul_div)
+{
+ uintptr_t rs1 = GET_RS1(insn, regs), rs2 = GET_RS2(insn, regs), val;
+
+ if ((insn & MASK_MUL) == MATCH_MUL)
+ val = rs1 * rs2;
+ else if ((insn & MASK_DIV) == MATCH_DIV)
+ val = (intptr_t)rs1 / (intptr_t)rs2;
+ else if ((insn & MASK_DIVU) == MATCH_DIVU)
+ val = rs1 / rs2;
+ else if ((insn & MASK_REM) == MATCH_REM)
+ val = (intptr_t)rs1 % (intptr_t)rs2;
+ else if ((insn & MASK_REMU) == MATCH_REMU)
+ val = rs1 % rs2;
+ else if ((insn & MASK_MULH) == MATCH_MULH)
+ val = ((double_int)(intptr_t)rs1 * (double_int)(intptr_t)rs2) >> (8 * sizeof(rs1));
+ else if ((insn & MASK_MULHU) == MATCH_MULHU)
+ val = ((double_int)rs1 * (double_int)rs2) >> (8 * sizeof(rs1));
+ else if ((insn & MASK_MULHSU) == MATCH_MULHSU)
+ val = ((double_int)(intptr_t)rs1 * (double_int)rs2) >> (8 * sizeof(rs1));
+ else
+ return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
+
+ SET_RD(insn, regs, val);
+}
+
+#ifdef __riscv64
+
+DECLARE_EMULATION_FUNC(emulate_mul_div32)
+{
+ uint32_t rs1 = GET_RS1(insn, regs), rs2 = GET_RS2(insn, regs);
+ int32_t val;
+
+ if ((insn & MASK_MULW) == MATCH_MULW)
+ val = rs1 * rs2;
+ else if ((insn & MASK_DIVW) == MATCH_DIVW)
+ val = (int32_t)rs1 / (int32_t)rs2;
+ else if ((insn & MASK_DIVUW) == MATCH_DIVUW)
+ val = rs1 / rs2;
+ else if ((insn & MASK_REMW) == MATCH_REMW)
+ val = (int32_t)rs1 % (int32_t)rs2;
+ else if ((insn & MASK_REMUW) == MATCH_REMUW)
+ val = rs1 % rs2;
+ else
+ return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
+
+ SET_RD(insn, regs, val);
+}
+
+#endif
+#endif