aboutsummaryrefslogtreecommitdiff
path: root/pk/emulation.c
diff options
context:
space:
mode:
Diffstat (limited to 'pk/emulation.c')
-rw-r--r--pk/emulation.c596
1 files changed, 94 insertions, 502 deletions
diff --git a/pk/emulation.c b/pk/emulation.c
index 87db2de..4943e0d 100644
--- a/pk/emulation.c
+++ b/pk/emulation.c
@@ -1,24 +1,76 @@
+#include "emulation.h"
+#include "fp_emulation.h"
+#include "config.h"
+#include "unprivileged_memory.h"
#include "mtrap.h"
-#include "softfloat.h"
#include <limits.h>
-void redirect_trap(uintptr_t epc, uintptr_t mstatus)
+void illegal_insn_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
- write_csr(sepc, epc);
- write_csr(scause, read_csr(mcause));
- write_csr(mepc, read_csr(stvec));
+ asm (".pushsection .rodata\n"
+ "illegal_insn_trap_table:\n"
+ " .word truly_illegal_insn\n"
+#ifdef PK_ENABLE_FP_EMULATION
+ " .word emulate_float_load\n"
+#else
+ " .word truly_illegal_insn\n"
+#endif
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+#ifdef PK_ENABLE_FP_EMULATION
+ " .word emulate_float_store\n"
+#else
+ " .word truly_illegal_insn\n"
+#endif
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word emulate_mul_div\n"
+ " .word truly_illegal_insn\n"
+ " .word emulate_mul_div32\n"
+ " .word truly_illegal_insn\n"
+#ifdef PK_ENABLE_FP_EMULATION
+ " .word emulate_fmadd\n"
+ " .word emulate_fmadd\n"
+ " .word emulate_fmadd\n"
+ " .word emulate_fmadd\n"
+ " .word emulate_fp\n"
+#else
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+#endif
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word emulate_system\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .word truly_illegal_insn\n"
+ " .popsection");
- uintptr_t prev_priv = EXTRACT_FIELD(mstatus, MSTATUS_MPP);
- uintptr_t prev_ie = EXTRACT_FIELD(mstatus, MSTATUS_MPIE);
- kassert(prev_priv <= PRV_S);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_SPP, prev_priv);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_SPIE, prev_ie);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0);
- write_csr(mstatus, mstatus);
+ uintptr_t mstatus;
+ insn_t insn = get_insn(mepc, &mstatus);
- extern void __redirect_trap();
- return __redirect_trap();
+ if (unlikely((insn & 3) != 3))
+ return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
+
+ write_csr(mepc, mepc + 4);
+
+ extern int32_t illegal_insn_trap_table[];
+ int32_t* pf = (void*)illegal_insn_trap_table + (insn & 0x7c);
+ emulation_func f = (emulation_func)(uintptr_t)*pf;
+ f(regs, mcause, mepc, mstatus, insn);
}
void __attribute__((noinline)) truly_illegal_insn(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn)
@@ -28,8 +80,14 @@ void __attribute__((noinline)) truly_illegal_insn(uintptr_t* regs, uintptr_t mca
void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
+ union {
+ uint8_t bytes[8];
+ uintptr_t intx;
+ uint64_t int64;
+ } val;
uintptr_t mstatus;
insn_t insn = get_insn(mepc, &mstatus);
+ uintptr_t addr = GET_RS1(insn, regs) + IMM_I(insn);
int shift = 0, fp = 0, len;
if ((insn & MASK_LW) == MATCH_LW)
@@ -51,139 +109,54 @@ void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- uintptr_t addr = GET_RS1(insn, regs) + IMM_I(insn);
- uintptr_t val = 0, tmp, tmp2;
- unpriv_mem_access("add %[tmp2], %[addr], %[len];"
- "1: slli %[val], %[val], 8;"
- "lbu %[tmp], -1(%[tmp2]);"
- "addi %[tmp2], %[tmp2], -1;"
- "or %[val], %[val], %[tmp];"
- "bne %[addr], %[tmp2], 1b;",
- val, tmp, tmp2, addr, len);
-
- if (shift)
- val = (intptr_t)val << shift >> shift;
+ val.int64 = 0;
+ for (intptr_t i = len-1; i >= 0; i--)
+ val.bytes[i] = load_uint8_t((void *)(addr + i), mepc);
if (!fp)
- SET_RD(insn, regs, val);
+ SET_RD(insn, regs, (intptr_t)val.intx << shift >> shift);
else if (len == 8)
- SET_F64_RD(insn, regs, val);
+ SET_F64_RD(insn, regs, val.int64);
else
- SET_F32_RD(insn, regs, val);
+ SET_F32_RD(insn, regs, val.intx);
write_csr(mepc, mepc + 4);
}
void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
+ union {
+ uint8_t bytes[8];
+ uintptr_t intx;
+ uint64_t int64;
+ } val;
uintptr_t mstatus;
insn_t insn = get_insn(mepc, &mstatus);
-
- uintptr_t val = GET_RS2(insn, regs), error;
int len;
+
+ val.intx = GET_RS2(insn, regs);
if ((insn & MASK_SW) == MATCH_SW)
len = 4;
+#ifdef __riscv64
else if ((insn & MASK_SD) == MATCH_SD)
len = 8;
+#endif
else if ((insn & MASK_FSD) == MATCH_FSD)
- len = 8, val = GET_F64_RS2(insn, regs);
+ len = 8, val.int64 = GET_F64_RS2(insn, regs);
else if ((insn & MASK_FSW) == MATCH_FSW)
- len = 4, val = GET_F32_RS2(insn, regs);
+ len = 4, val.intx = GET_F32_RS2(insn, regs);
else if ((insn & MASK_SH) == MATCH_SH)
len = 2;
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
uintptr_t addr = GET_RS1(insn, regs) + IMM_S(insn);
- uintptr_t tmp, tmp2, addr_end = addr + len;
- unpriv_mem_access("mv %[tmp], %[val];"
- "mv %[tmp2], %[addr];"
- "1: sb %[tmp], 0(%[tmp2]);"
- "srli %[tmp], %[tmp], 8;"
- "addi %[tmp2], %[tmp2], 1;"
- "bne %[tmp2], %[addr_end], 1b",
- tmp, tmp2, unused1, val, addr, addr_end);
+ for (size_t i = 0; i < len; i++)
+ store_uint8_t((void *)(addr + i), val.bytes[i], mepc);
write_csr(mepc, mepc + 4);
}
-DECLARE_EMULATION_FUNC(emulate_float_load)
-{
- uintptr_t val_lo, val_hi;
- 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);
-
- unpriv_mem_access("lw %[val_lo], (%[addr])",
- val_lo, unused1, unused2, addr, mepc/*X*/);
- SET_F32_RD(insn, regs, val_lo);
- break;
-
- case MATCH_FLD & MASK_FUNCT3:
- if (addr % sizeof(uintptr_t) != 0)
- return misaligned_load_trap(regs, mcause, mepc);
-
-#ifdef __riscv64
- unpriv_mem_access("ld %[val], (%[addr])",
- val, val_hi/*X*/, unused1, addr, mepc/*X*/);
-#else
- unpriv_mem_access("lw %[val_lo], (%[addr]);"
- "lw %[val_hi], 4(%[addr])",
- val_lo, val_hi, unused1, addr, mepc/*X*/);
- val = val_lo | ((uint64_t)val_hi << 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)
-{
- uintptr_t val_lo, val_hi;
- 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);
-
- val_lo = GET_F32_RS2(insn, regs);
- unpriv_mem_access("sw %[val_lo], (%[addr])",
- unused1, unused2, unused3, val_lo, addr);
- 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);
-#ifdef __riscv64
- unpriv_mem_access("sd %[val], (%[addr])",
- unused1, unused2, unused3, val, addr);
-#else
- val_lo = val;
- val_hi = val >> 32;
- unpriv_mem_access("sw %[val_lo], (%[addr]);"
- "sw %[val_hi], 4(%[addr])",
- unused1, unused2, unused3, val_lo, val_hi, addr);
-#endif
- break;
-
- default:
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
#ifdef __riscv64
typedef __int128 double_int;
#else
@@ -279,7 +252,7 @@ static inline int emulate_read_csr(int num, uintptr_t mstatus, uintptr_t* result
+ HLS()->sinstret_delta) >> 32;
return 0;
#endif
-#ifndef __riscv_hard_float
+#ifdef PK_ENABLE_FP_EMULATION
case CSR_FRM:
if ((mstatus & MSTATUS_FS) == 0) break;
*result = GET_FRM();
@@ -301,7 +274,7 @@ static inline int emulate_write_csr(int num, uintptr_t value, uintptr_t mstatus)
{
switch (num)
{
-#ifndef __riscv_hard_float
+#ifndef PK_ENABLE_FP_EMULATION
case CSR_FRM: SET_FRM(value); return 0;
case CSR_FFLAGS: SET_FFLAGS(value); return 0;
case CSR_FCSR: SET_FCSR(value); return 0;
@@ -338,384 +311,3 @@ DECLARE_EMULATION_FUNC(emulate_system)
SET_RD(insn, regs, csr_val);
}
-
-DECLARE_EMULATION_FUNC(emulate_fp)
-{
- asm (".pushsection .rodata\n"
- "fp_emulation_table:\n"
- " .word emulate_fadd\n"
- " .word emulate_fsub\n"
- " .word emulate_fmul\n"
- " .word emulate_fdiv\n"
- " .word emulate_fsgnj\n"
- " .word emulate_fmin\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word emulate_fcvt_ff\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word emulate_fsqrt\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word emulate_fcmp\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word truly_illegal_insn\n"
- " .word emulate_fcvt_if\n"
- " .word truly_illegal_insn\n"
- " .word emulate_fcvt_fi\n"
- " .word truly_illegal_insn\n"
- " .word emulate_fmv_if\n"
- " .word truly_illegal_insn\n"
- " .word emulate_fmv_fi\n"
- " .word truly_illegal_insn\n"
- " .popsection");
-
- // if FPU is disabled, punt back to the OS
- if (unlikely((mstatus & MSTATUS_FS) == 0))
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- extern int32_t fp_emulation_table[];
- int32_t* pf = (void*)fp_emulation_table + ((insn >> 25) & 0x7c);
- emulation_func f = (emulation_func)(uintptr_t)*pf;
-
- SETUP_STATIC_ROUNDING(insn);
- return f(regs, mcause, mepc, mstatus, insn);
-}
-
-void emulate_any_fadd(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn, int32_t neg_b)
-{
- if (GET_PRECISION(insn) == PRECISION_S) {
- uint32_t rs1 = GET_F32_RS1(insn, regs);
- uint32_t rs2 = GET_F32_RS2(insn, regs) ^ neg_b;
- SET_F32_RD(insn, regs, f32_add(rs1, rs2));
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- uint64_t rs1 = GET_F64_RS1(insn, regs);
- uint64_t rs2 = GET_F64_RS2(insn, regs) ^ ((uint64_t)neg_b << 32);
- SET_F64_RD(insn, regs, f64_add(rs1, rs2));
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
-DECLARE_EMULATION_FUNC(emulate_fadd)
-{
- return emulate_any_fadd(regs, mcause, mepc, mstatus, insn, 0);
-}
-
-DECLARE_EMULATION_FUNC(emulate_fsub)
-{
- return emulate_any_fadd(regs, mcause, mepc, mstatus, insn, INT32_MIN);
-}
-
-DECLARE_EMULATION_FUNC(emulate_fmul)
-{
- if (GET_PRECISION(insn) == PRECISION_S) {
- uint32_t rs1 = GET_F32_RS1(insn, regs);
- uint32_t rs2 = GET_F32_RS2(insn, regs);
- SET_F32_RD(insn, regs, f32_mul(rs1, rs2));
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- uint64_t rs1 = GET_F64_RS1(insn, regs);
- uint64_t rs2 = GET_F64_RS2(insn, regs);
- SET_F64_RD(insn, regs, f64_mul(rs1, rs2));
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
-DECLARE_EMULATION_FUNC(emulate_fdiv)
-{
- if (GET_PRECISION(insn) == PRECISION_S) {
- uint32_t rs1 = GET_F32_RS1(insn, regs);
- uint32_t rs2 = GET_F32_RS2(insn, regs);
- SET_F32_RD(insn, regs, f32_div(rs1, rs2));
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- uint64_t rs1 = GET_F64_RS1(insn, regs);
- uint64_t rs2 = GET_F64_RS2(insn, regs);
- SET_F64_RD(insn, regs, f64_div(rs1, rs2));
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
-DECLARE_EMULATION_FUNC(emulate_fsqrt)
-{
- if ((insn >> 20) & 0x1f)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- if (GET_PRECISION(insn) == PRECISION_S) {
- SET_F32_RD(insn, regs, f32_sqrt(GET_F32_RS1(insn, regs)));
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- SET_F64_RD(insn, regs, f64_sqrt(GET_F64_RS1(insn, regs)));
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
-DECLARE_EMULATION_FUNC(emulate_fsgnj)
-{
- int rm = GET_RM(insn);
- if (rm >= 3)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- #define DO_FSGNJ(rs1, rs2, rm) ({ \
- typeof(rs1) rs1_sign = (rs1) >> (8*sizeof(rs1)-1); \
- typeof(rs1) rs2_sign = (rs2) >> (8*sizeof(rs1)-1); \
- rs1_sign &= (rm) >> 1; \
- rs1_sign ^= (rm) ^ rs2_sign; \
- ((rs1) << 1 >> 1) | (rs1_sign << (8*sizeof(rs1)-1)); })
-
- if (GET_PRECISION(insn) == PRECISION_S) {
- uint32_t rs1 = GET_F32_RS1(insn, regs);
- uint32_t rs2 = GET_F32_RS2(insn, regs);
- SET_F32_RD(insn, regs, DO_FSGNJ(rs1, rs2, rm));
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- uint64_t rs1 = GET_F64_RS1(insn, regs);
- uint64_t rs2 = GET_F64_RS2(insn, regs);
- SET_F64_RD(insn, regs, DO_FSGNJ(rs1, rs2, rm));
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
-DECLARE_EMULATION_FUNC(emulate_fmin)
-{
- int rm = GET_RM(insn);
- if (rm >= 2)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- if (GET_PRECISION(insn) == PRECISION_S) {
- uint32_t rs1 = GET_F32_RS1(insn, regs);
- uint32_t rs2 = GET_F32_RS2(insn, regs);
- uint32_t arg1 = rm ? rs2 : rs1;
- uint32_t arg2 = rm ? rs1 : rs2;
- int use_rs1 = f32_lt_quiet(arg1, arg2) || isNaNF32UI(rs2);
- SET_F32_RD(insn, regs, use_rs1 ? rs1 : rs2);
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- uint64_t rs1 = GET_F64_RS1(insn, regs);
- uint64_t rs2 = GET_F64_RS2(insn, regs);
- uint64_t arg1 = rm ? rs2 : rs1;
- uint64_t arg2 = rm ? rs1 : rs2;
- int use_rs1 = f64_lt_quiet(arg1, arg2) || isNaNF64UI(rs2);
- SET_F64_RD(insn, regs, use_rs1 ? rs1 : rs2);
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
-DECLARE_EMULATION_FUNC(emulate_fcvt_ff)
-{
- int rs2_num = (insn >> 20) & 0x1f;
- if (GET_PRECISION(insn) == PRECISION_S) {
- if (rs2_num != 1)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- SET_F32_RD(insn, regs, f64_to_f32(GET_F64_RS1(insn, regs)));
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- if (rs2_num != 0)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- SET_F64_RD(insn, regs, f32_to_f64(GET_F32_RS1(insn, regs)));
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}
-
-DECLARE_EMULATION_FUNC(emulate_fcvt_fi)
-{
- if (GET_PRECISION(insn) != PRECISION_S && GET_PRECISION(insn) != PRECISION_D)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- int negative = 0;
- uint64_t uint_val = GET_RS1(insn, regs);
-
- switch ((insn >> 20) & 0x1f)
- {
- case 0: // int32
- negative = (int32_t)uint_val < 0;
- uint_val = negative ? -(int32_t)uint_val : (int32_t)uint_val;
- break;
- case 1: // uint32
- uint_val = (uint32_t)uint_val;
- break;
-#ifdef __riscv64
- case 2: // int64
- negative = (int64_t)uint_val < 0;
- uint_val = negative ? -uint_val : uint_val;
- case 3: // uint64
- break;
-#endif
- default:
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-
- uint64_t float64 = ui64_to_f64(uint_val);
- if (negative)
- float64 ^= INT64_MIN;
-
- if (GET_PRECISION(insn) == PRECISION_S)
- SET_F32_RD(insn, regs, f64_to_f32(float64));
- else
- SET_F64_RD(insn, regs, float64);
-}
-
-DECLARE_EMULATION_FUNC(emulate_fcvt_if)
-{
- int rs2_num = (insn >> 20) & 0x1f;
-#ifdef __riscv64
- if (rs2_num >= 4)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-#else
- if (rs2_num >= 2)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-#endif
-
- int64_t float64;
- if (GET_PRECISION(insn) == PRECISION_S)
- float64 = f32_to_f64(GET_F32_RS1(insn, regs));
- else if (GET_PRECISION(insn) == PRECISION_D)
- float64 = GET_F64_RS1(insn, regs);
- else
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- int negative = 0;
- if (float64 < 0) {
- negative = 1;
- float64 ^= INT64_MIN;
- }
- uint64_t uint_val = f64_to_ui64(float64, softfloat_roundingMode, true);
- uint64_t result, limit, limit_result;
-
- switch (rs2_num)
- {
- case 0: // int32
- if (negative) {
- result = (int32_t)-uint_val;
- limit_result = limit = (uint32_t)INT32_MIN;
- } else {
- result = (int32_t)uint_val;
- limit_result = limit = INT32_MAX;
- }
- break;
-
- case 1: // uint32
- limit = limit_result = UINT32_MAX;
- if (negative)
- result = limit = 0;
- else
- result = (uint32_t)uint_val;
- break;
-
- case 2: // int32
- if (negative) {
- result = (int64_t)-uint_val;
- limit_result = limit = (uint64_t)INT64_MIN;
- } else {
- result = (int64_t)uint_val;
- limit_result = limit = INT64_MAX;
- }
- break;
-
- case 3: // uint64
- limit = limit_result = UINT64_MAX;
- if (negative)
- result = limit = 0;
- else
- result = (uint64_t)uint_val;
- break;
-
- default:
- __builtin_unreachable();
- }
-
- if (uint_val > limit) {
- result = limit_result;
- softfloat_raiseFlags(softfloat_flag_invalid);
- }
-
- SET_FS_DIRTY();
- SET_RD(insn, regs, result);
-}
-
-DECLARE_EMULATION_FUNC(emulate_fcmp)
-{
- int rm = GET_RM(insn);
- if (rm >= 3)
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- uintptr_t result;
- if (GET_PRECISION(insn) == PRECISION_S) {
- uint32_t rs1 = GET_F32_RS1(insn, regs);
- uint32_t rs2 = GET_F32_RS2(insn, regs);
- if (rm != 1)
- result = f32_eq(rs1, rs2);
- if (rm == 1 || (rm == 0 && !result))
- result = f32_lt(rs1, rs2);
- goto success;
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- uint64_t rs1 = GET_F64_RS1(insn, regs);
- uint64_t rs2 = GET_F64_RS2(insn, regs);
- if (rm != 1)
- result = f64_eq(rs1, rs2);
- if (rm == 1 || (rm == 0 && !result))
- result = f64_lt(rs1, rs2);
- goto success;
- }
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-success:
- SET_RD(insn, regs, result);
-}
-
-DECLARE_EMULATION_FUNC(emulate_fmv_if)
-{
- uintptr_t result;
- if ((insn & MASK_FMV_X_S) == MATCH_FMV_X_S)
- result = GET_F32_RS1(insn, regs);
-#ifdef __riscv64
- else if ((insn & MASK_FMV_X_D) == MATCH_FMV_X_D)
- result = GET_F64_RS1(insn, regs);
-#endif
- else
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- SET_RD(insn, regs, result);
-}
-
-DECLARE_EMULATION_FUNC(emulate_fmv_fi)
-{
- uintptr_t rs1 = GET_RS1(insn, regs);
-
- if ((insn & MASK_FMV_S_X) == MATCH_FMV_S_X)
- SET_F32_RD(insn, regs, rs1);
- else if ((insn & MASK_FMV_D_X) == MATCH_FMV_D_X)
- SET_F64_RD(insn, regs, rs1);
- else
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-}
-
-DECLARE_EMULATION_FUNC(emulate_fmadd)
-{
- // if FPU is disabled, punt back to the OS
- if (unlikely((mstatus & MSTATUS_FS) == 0))
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
-
- int op = (insn >> 2) & 3;
- SETUP_STATIC_ROUNDING(insn);
- if (GET_PRECISION(insn) == PRECISION_S) {
- uint32_t rs1 = GET_F32_RS1(insn, regs);
- uint32_t rs2 = GET_F32_RS2(insn, regs);
- uint32_t rs3 = GET_F32_RS3(insn, regs);
- SET_F32_RD(insn, regs, softfloat_mulAddF32(op, rs1, rs2, rs3));
- } else if (GET_PRECISION(insn) == PRECISION_D) {
- uint64_t rs1 = GET_F64_RS1(insn, regs);
- uint64_t rs2 = GET_F64_RS2(insn, regs);
- uint64_t rs3 = GET_F64_RS3(insn, regs);
- SET_F64_RD(insn, regs, softfloat_mulAddF64(op, rs1, rs2, rs3));
- } else {
- return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
- }
-}