Browse Source

Fix some bugs in FP emulation

pull/9/head
Andrew Waterman 11 years ago
parent
commit
40668501fa
  1. 87
      pk/emulation.c
  2. 13
      pk/minit.c
  3. 5
      pk/mtrap.h

87
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);
}

13
pk/minit.c

@ -47,6 +47,18 @@ static void hart_init()
panic("TODO: SMP support");
}
static void fp_init()
{
#ifdef __riscv_hard_float
kassert(read_csr(mstatus) & MSTATUS_FS);
SET_FCSR(0);
for (int i = 0; i < 32; i++)
init_fp_reg(i);
#else
kassert(!(read_csr(mstatus) & MSTATUS_FS));
#endif
}
void machine_init()
{
file_init();
@ -57,6 +69,7 @@ void machine_init()
mstatus_init();
memory_init();
hart_init();
fp_init();
vm_init();
boot_loader(args);
}

5
pk/mtrap.h

@ -106,6 +106,7 @@ typedef uintptr_t (*emulation_func)(uintptr_t, uintptr_t*, insn_t, uintptr_t, ui
uintptr_t offset = ((insn) >> ((pos)-3)) & 0xf8; \
uintptr_t tmp; \
asm volatile ("1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); })
# define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
# define GET_F64_REG(insn, pos, regs) ({ \
register uintptr_t value asm("a0") = ((insn) >> ((pos)-3)) & 0xf8; \
uintptr_t tmp; \
@ -160,8 +161,8 @@ typedef uintptr_t (*emulation_func)(uintptr_t, uintptr_t*, insn_t, uintptr_t, ui
#define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs))
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
#define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 15, regs, val), SET_FS_DIRTY())
#define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 15, regs, val), SET_FS_DIRTY())
#define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_FS_DIRTY() set_csr(mstatus, MSTATUS_FS)
typedef struct {

Loading…
Cancel
Save