aboutsummaryrefslogtreecommitdiff
path: root/machine/fp_ldst.c
diff options
context:
space:
mode:
Diffstat (limited to 'machine/fp_ldst.c')
-rw-r--r--machine/fp_ldst.c46
1 files changed, 18 insertions, 28 deletions
diff --git a/machine/fp_ldst.c b/machine/fp_ldst.c
index 93a4844..e11900c 100644
--- a/machine/fp_ldst.c
+++ b/machine/fp_ldst.c
@@ -1,31 +1,28 @@
#include "fp_emulation.h"
#include "unprivileged_memory.h"
+#define punt_to_misaligned_handler(align, handler) \
+ if (addr % (align) != 0) \
+ return write_csr(mbadaddr, addr), (handler)(regs, mcause, mepc)
+
DECLARE_EMULATION_FUNC(emulate_float_load)
{
- uint64_t val;
uintptr_t addr = GET_RS1(insn, regs) + IMM_I(insn);
+
+ // if FPU is disabled, punt back to the OS
+ if (unlikely((mstatus & MSTATUS_FS) == 0))
+ return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
switch (insn & MASK_FUNCT3)
{
case MATCH_FLW & MASK_FUNCT3:
- if (addr % 4 != 0)
- return misaligned_load_trap(regs, mcause, mepc);
-
+ punt_to_misaligned_handler(4, misaligned_load_trap);
SET_F32_RD(insn, regs, load_int32_t((void *)addr, mepc));
break;
case MATCH_FLD & MASK_FUNCT3:
- if (addr % sizeof(uintptr_t) != 0)
- return misaligned_load_trap(regs, mcause, mepc);
-
-#if __riscv_xlen == 64
- val = load_uint64_t((void *)addr, mepc);
-#else
- val = load_uint32_t((void *)addr, mepc);
- val += (uint64_t)load_uint32_t((void *)(addr + 4), mepc) << 32;
-#endif
- SET_F64_RD(insn, regs, val);
+ punt_to_misaligned_handler(sizeof(uintptr_t), misaligned_load_trap);
+ SET_F64_RD(insn, regs, load_uint64_t((void *)addr, mepc));
break;
default:
@@ -35,29 +32,22 @@ DECLARE_EMULATION_FUNC(emulate_float_load)
DECLARE_EMULATION_FUNC(emulate_float_store)
{
- uint64_t val;
uintptr_t addr = GET_RS1(insn, regs) + IMM_S(insn);
+
+ // if FPU is disabled, punt back to the OS
+ if (unlikely((mstatus & MSTATUS_FS) == 0))
+ return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
switch (insn & MASK_FUNCT3)
{
case MATCH_FSW & MASK_FUNCT3:
- if (addr % 4 != 0)
- return misaligned_store_trap(regs, mcause, mepc);
-
+ punt_to_misaligned_handler(4, misaligned_store_trap);
store_uint32_t((void *)addr, GET_F32_RS2(insn, regs), mepc);
break;
case MATCH_FSD & MASK_FUNCT3:
- if (addr % sizeof(uintptr_t) != 0)
- return misaligned_store_trap(regs, mcause, mepc);
-
- val = GET_F64_RS2(insn, regs);
-#if __riscv_xlen == 64
- store_uint64_t((void *)addr, val, mepc);
-#else
- store_uint32_t((void *)addr, val, mepc);
- store_uint32_t((void *)(addr + 4), val >> 32, mepc);
-#endif
+ punt_to_misaligned_handler(sizeof(uintptr_t), misaligned_store_trap);
+ store_uint64_t((void *)addr, GET_F64_RS2(insn, regs), mepc);
break;
default: