diff options
Diffstat (limited to 'machine/fp_ldst.c')
-rw-r--r-- | machine/fp_ldst.c | 46 |
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: |