aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2016-07-16 16:16:22 -0700
committerAndrew Waterman <waterman@cs.berkeley.edu>2016-07-16 16:16:22 -0700
commit023ae43e8d7b1cdd54ebdc98beeb6dae9dd6f05a (patch)
tree54d6ce5311ff94c2df38b339b11ca2fc98b319f1
parent6bead31951a5f70508b343681a6f6905324f7bec (diff)
downloadpk-023ae43e8d7b1cdd54ebdc98beeb6dae9dd6f05a.zip
pk-023ae43e8d7b1cdd54ebdc98beeb6dae9dd6f05a.tar.gz
pk-023ae43e8d7b1cdd54ebdc98beeb6dae9dd6f05a.tar.bz2
Add FCLASS emulation
-rw-r--r--machine/emulation.h4
-rw-r--r--machine/fp_emulation.c24
2 files changed, 21 insertions, 7 deletions
diff --git a/machine/emulation.h b/machine/emulation.h
index f1a71ec..b8712b5 100644
--- a/machine/emulation.h
+++ b/machine/emulation.h
@@ -11,8 +11,8 @@ typedef void (*emulation_func)(uintptr_t*, uintptr_t, uintptr_t, uintptr_t, insn
void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
-void redirect_trap(uintptr_t epc, uintptr_t mstatus);
-DECLARE_EMULATION_FUNC(truly_illegal_insn);
+void redirect_trap(uintptr_t epc, uintptr_t mstatus) __attribute__((noreturn));
+DECLARE_EMULATION_FUNC(truly_illegal_insn) __attribute__((noreturn));
#define GET_REG(insn, pos, regs) ({ \
int mask = (1 << (5+LOG_REGBYTES)) - (1 << LOG_REGBYTES); \
diff --git a/machine/fp_emulation.c b/machine/fp_emulation.c
index f1ed919..be9c067 100644
--- a/machine/fp_emulation.c
+++ b/machine/fp_emulation.c
@@ -337,14 +337,26 @@ success:
DECLARE_EMULATION_FUNC(emulate_fmv_if)
{
uintptr_t result;
- if ((insn & MASK_FMV_X_S) == MATCH_FMV_X_S)
+ if ((insn >> 20) & 0x1f)
+ return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
+
+ if (GET_PRECISION(insn) == PRECISION_S) {
result = GET_F32_RS1(insn, regs);
-#ifdef __riscv64
- else if ((insn & MASK_FMV_X_D) == MATCH_FMV_X_D)
+ switch (GET_RM(insn)) {
+ case GET_RM(MATCH_FMV_X_S): break;
+ case GET_RM(MATCH_FCLASS_S): result = f32_classify(result); break;
+ default: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
+ }
+ } else if (GET_PRECISION(insn) == PRECISION_D) {
result = GET_F64_RS1(insn, regs);
-#endif
- else
+ switch (GET_RM(insn)) {
+ case GET_RM(MATCH_FMV_X_D): break;
+ case GET_RM(MATCH_FCLASS_D): result = f64_classify(result); break;
+ default: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
+ }
+ } else {
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
+ }
SET_RD(insn, regs, result);
}
@@ -355,8 +367,10 @@ DECLARE_EMULATION_FUNC(emulate_fmv_fi)
if ((insn & MASK_FMV_S_X) == MATCH_FMV_S_X)
SET_F32_RD(insn, regs, rs1);
+#ifdef __riscv64
else if ((insn & MASK_FMV_D_X) == MATCH_FMV_D_X)
SET_F64_RD(insn, regs, rs1);
+#endif
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
}