From 40668501fa8d52054f5678db4e6dd32b5ed7fe15 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Sat, 14 Mar 2015 02:06:21 -0700 Subject: Fix some bugs in FP emulation --- pk/emulation.c | 87 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 32 deletions(-) (limited to 'pk/emulation.c') diff --git a/pk/emulation.c b/pk/emulation.c index 25c4de0..1ff858a 100644 --- a/pk/emulation.c +++ b/pk/emulation.c @@ -303,6 +303,7 @@ DECLARE_EMULATION_FUNC(emulate_mul_div) return -1; SET_RD(insn, regs, val); + write_csr(mepc, mepc + 4); return 0; } @@ -330,6 +331,7 @@ DECLARE_EMULATION_FUNC(emulate_mul_div32) return -1; SET_RD(insn, regs, val); + write_csr(mepc, mepc + 4); return 0; } @@ -391,6 +393,7 @@ DECLARE_EMULATION_FUNC(emulate_system) return -1; SET_RD(insn, regs, csr_val); + write_csr(mepc, mepc + 4); return 0; } @@ -444,30 +447,32 @@ DECLARE_EMULATION_FUNC(emulate_fp) return f(mcause, regs, insn, mstatus, mepc); } -uintptr_t emulate_any_fadd(uintptr_t mcause, uintptr_t* regs, insn_t insn, uintptr_t neg_b) +uintptr_t emulate_any_fadd(uintptr_t mcause, uintptr_t* regs, insn_t insn, uintptr_t mstatus, uintptr_t mepc, uintptr_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)); - return 0; } 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)); - return 0; + } else { + return -1; } - return -1; + + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fadd) { - return emulate_any_fadd(mcause, regs, insn, 0); + return emulate_any_fadd(mcause, regs, insn, mstatus, mepc, 0); } DECLARE_EMULATION_FUNC(emulate_fsub) { - return emulate_any_fadd(mcause, regs, insn, INT32_MIN); + return emulate_any_fadd(mcause, regs, insn, mstatus, mepc, INT32_MIN); } DECLARE_EMULATION_FUNC(emulate_fmul) @@ -476,14 +481,16 @@ DECLARE_EMULATION_FUNC(emulate_fmul) 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)); - return 0; } 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)); - return 0; + } else { + return -1; } - return -1; + + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fdiv) @@ -492,14 +499,16 @@ DECLARE_EMULATION_FUNC(emulate_fdiv) 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)); - return 0; } 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)); - return 0; + } else { + return -1; } - return -1; + + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fsqrt) @@ -509,12 +518,14 @@ DECLARE_EMULATION_FUNC(emulate_fsqrt) if (GET_PRECISION(insn) == PRECISION_S) { SET_F32_RD(insn, regs, f32_sqrt(GET_F32_RS1(insn, regs))); - return 0; } else if (GET_PRECISION(insn) == PRECISION_D) { SET_F64_RD(insn, regs, f64_sqrt(GET_F64_RS1(insn, regs))); - return 0; + } else { + return -1; } - return -1; + + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fsgnj) @@ -534,14 +545,16 @@ DECLARE_EMULATION_FUNC(emulate_fsgnj) 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)); - return 0; } 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)); - return 0; + } else { + return -1; } - return -1; + + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fmin) @@ -557,7 +570,6 @@ DECLARE_EMULATION_FUNC(emulate_fmin) 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); - return 0; } else if (GET_PRECISION(insn) == PRECISION_D) { uint64_t rs1 = GET_F64_RS1(insn, regs); uint64_t rs2 = GET_F64_RS2(insn, regs); @@ -565,9 +577,12 @@ DECLARE_EMULATION_FUNC(emulate_fmin) 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); - return 0; + } else { + return -1; } - return -1; + + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fcvt_ff) @@ -577,14 +592,16 @@ DECLARE_EMULATION_FUNC(emulate_fcvt_ff) if (rs2_num != 1) return -1; SET_F32_RD(insn, regs, f64_to_f32(GET_F64_RS1(insn, regs))); - return 0; } else if (GET_PRECISION(insn) == PRECISION_D) { if (rs2_num != 0) return -1; SET_F64_RD(insn, regs, f32_to_f64(GET_F32_RS1(insn, regs))); - return 0; + } else { + return -1; } - return -1; + + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fcvt_fi) @@ -624,6 +641,7 @@ DECLARE_EMULATION_FUNC(emulate_fcvt_fi) else SET_F64_RD(insn, regs, float64); + write_csr(mepc, mepc + 4); return 0; } @@ -701,6 +719,7 @@ DECLARE_EMULATION_FUNC(emulate_fcvt_if) SET_FS_DIRTY(); SET_RD(insn, regs, result); + write_csr(mepc, mepc + 4); return 0; } @@ -731,6 +750,7 @@ DECLARE_EMULATION_FUNC(emulate_fcmp) return -1; success: SET_RD(insn, regs, result); + write_csr(mepc, mepc + 4); return 0; } @@ -747,6 +767,7 @@ DECLARE_EMULATION_FUNC(emulate_fmv_if) return -1; SET_RD(insn, regs, result); + write_csr(mepc, mepc + 4); return 0; } @@ -761,10 +782,11 @@ DECLARE_EMULATION_FUNC(emulate_fmv_fi) else return -1; + write_csr(mepc, mepc + 4); return 0; } -uintptr_t emulate_any_fmadd(int op, uintptr_t* regs, insn_t insn, uintptr_t mstatus) +uintptr_t emulate_any_fmadd(int op, uintptr_t* regs, insn_t insn, uintptr_t mstatus, uintptr_t mepc) { // if FPU is disabled, punt back to the OS if (unlikely((mstatus & MSTATUS_FS) == 0)) @@ -776,37 +798,38 @@ uintptr_t emulate_any_fmadd(int op, uintptr_t* regs, insn_t insn, uintptr_t msta 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)); - return 0; } 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)); - return 0; + } else { + return -1; } - return -1; + write_csr(mepc, mepc + 4); + return 0; } DECLARE_EMULATION_FUNC(emulate_fmadd) { int op = 0; - return emulate_any_fmadd(op, regs, insn, mstatus); + return emulate_any_fmadd(op, regs, insn, mstatus, mepc); } DECLARE_EMULATION_FUNC(emulate_fmsub) { int op = softfloat_mulAdd_subC; - return emulate_any_fmadd(op, regs, insn, mstatus); + return emulate_any_fmadd(op, regs, insn, mstatus, mepc); } DECLARE_EMULATION_FUNC(emulate_fnmadd) { int op = softfloat_mulAdd_subC | softfloat_mulAdd_subProd; - return emulate_any_fmadd(op, regs, insn, mstatus); + return emulate_any_fmadd(op, regs, insn, mstatus, mepc); } DECLARE_EMULATION_FUNC(emulate_fnmsub) { int op = softfloat_mulAdd_subProd; - return emulate_any_fmadd(op, regs, insn, mstatus); + return emulate_any_fmadd(op, regs, insn, mstatus, mepc); } -- cgit v1.1