aboutsummaryrefslogtreecommitdiff
path: root/machine/fp_ldst.c
blob: 93a48448ee57604a820da446551e27e49b7d2e15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "fp_emulation.h"
#include "unprivileged_memory.h"

DECLARE_EMULATION_FUNC(emulate_float_load)
{
  uint64_t val;
  uintptr_t addr = GET_RS1(insn, regs) + IMM_I(insn);
  
  switch (insn & MASK_FUNCT3)
  {
    case MATCH_FLW & MASK_FUNCT3:
      if (addr % 4 != 0)
        return misaligned_load_trap(regs, mcause, mepc);

      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);
      break;

    default:
      return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
  }
}

DECLARE_EMULATION_FUNC(emulate_float_store)
{
  uint64_t val;
  uintptr_t addr = GET_RS1(insn, regs) + IMM_S(insn);
  
  switch (insn & MASK_FUNCT3)
  {
    case MATCH_FSW & MASK_FUNCT3:
      if (addr % 4 != 0)
        return misaligned_store_trap(regs, mcause, mepc);

      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
      break;

    default:
      return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
  }
}