1// See LICENSE for license details.
2
3#include "fp_emulation.h"
4#include "unprivileged_memory.h"
5
6#define punt_to_misaligned_handler(align, handler) \
7  if (addr % (align) != 0) \
8    return write_csr(mbadaddr, addr), (handler)(regs, mcause, mepc)
9
10DECLARE_EMULATION_FUNC(emulate_float_load)
11{
12  uintptr_t addr = GET_RS1(insn, regs) + IMM_I(insn);
13
14  // if FPU is disabled, punt back to the OS
15  if (unlikely((mstatus & MSTATUS_FS) == 0))
16    return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
17
18  switch (insn & MASK_FUNCT3)
19  {
20    case MATCH_FLW & MASK_FUNCT3:
21      punt_to_misaligned_handler(4, misaligned_load_trap);
22      SET_F32_RD(insn, regs, load_int32_t((void *)addr, mepc));
23      break;
24
25    case MATCH_FLD & MASK_FUNCT3:
26      punt_to_misaligned_handler(sizeof(uintptr_t), misaligned_load_trap);
27      SET_F64_RD(insn, regs, load_uint64_t((void *)addr, mepc));
28      break;
29
30    default:
31      return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
32  }
33}
34
35DECLARE_EMULATION_FUNC(emulate_float_store)
36{
37  uintptr_t addr = GET_RS1(insn, regs) + IMM_S(insn);
38
39  // if FPU is disabled, punt back to the OS
40  if (unlikely((mstatus & MSTATUS_FS) == 0))
41    return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
42
43  switch (insn & MASK_FUNCT3)
44  {
45    case MATCH_FSW & MASK_FUNCT3:
46      punt_to_misaligned_handler(4, misaligned_store_trap);
47      store_uint32_t((void *)addr, GET_F32_RS2(insn, regs), mepc);
48      break;
49
50    case MATCH_FSD & MASK_FUNCT3:
51      punt_to_misaligned_handler(sizeof(uintptr_t), misaligned_store_trap);
52      store_uint64_t((void *)addr, GET_F64_RS2(insn, regs), mepc);
53      break;
54
55    default:
56      return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
57  }
58}
59
60