@@ -5,6 +5,8 @@ M(IMA)
M(IA)
M(GC)
M(IC)
+M(IF)
+M(ID)
M(IMC)
M(IMAC)
M(IAC)
@@ -13,6 +15,8 @@ M(EM)
M(EMA)
M(EA)
M(EC)
+M(EF)
+M(ED)
M(EMC)
M(EMAC)
M(EAC)
@@ -24,6 +24,7 @@
/* This must come before any other includes. */
#include "defs.h"
+#include <math.h>
#include <inttypes.h>
#include <time.h>
@@ -64,6 +65,17 @@ static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
} \
} while (0)
+#define FCSR_NX 0x1 /* Inexact. */
+#define FCSR_UF 0x2 /* Underflow. */
+#define FCSR_OF 0x4 /* Overflow. */
+#define FCSR_DZ 0x8 /* Divide by zero. */
+#define FCSR_NV 0x10 /* Invalid Operation. */
+
+#define FEQ 1
+#define FLT 2
+#define FLE 3
+#define FCLASS 4
+
static INLINE void
store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
{
@@ -76,6 +88,16 @@ store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
}
}
+/* Store a value into floating point register. */
+static INLINE void
+store_fp (SIM_CPU *cpu, int rd, unsigned_word val)
+{
+ struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+ riscv_cpu->fpregs[rd] = val;
+ TRACE_REG (cpu, rd);
+}
+
static INLINE unsigned_word
fetch_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg)
{
@@ -682,6 +704,195 @@ mulhsu (int64_t a, uint64_t b)
return negate ? ~res + (a * b == 0) : res;
}
+/* Handle single precision floating point compare instructions. */
+static void
+float32_compare (SIM_CPU *cpu, int rd, int rs1, int rs2, int flags)
+{
+ struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+ float a, b = .0f;
+ uint32_t result = 0, exception = 0, sign = 0, bit_pos;
+ uint32_t rs1_bits, rs2_bits;
+ const char *rd_name = riscv_gpr_names_abi[rd];
+ const char *frs1_name = riscv_fpr_names_abi[rs1];
+ const char *frs2_name = riscv_fpr_names_abi[rs2];
+
+ rs1_bits = (uint32_t) riscv_cpu->fpregs[rs1];
+ memcpy (&a, &rs1_bits, sizeof (a));
+
+ if (flags != FCLASS)
+ {
+ rs2_bits = (uint32_t) riscv_cpu->fpregs[rs2];
+ memcpy (&b, &rs2_bits, sizeof (b));
+ }
+
+ switch (flags)
+ {
+ case FEQ:
+ TRACE_INSN (cpu, "feq.s %s, %s, %s;", rd_name, frs1_name, frs2_name);
+ if (__isnanf (a) || __isnanf (b))
+ {
+ result = 0;
+ if (__issignalingf (a) || __issignalingf (b))
+ exception = 1;
+ }
+ else
+ result = (a == b);
+ break;
+ case FLT:
+ TRACE_INSN (cpu, "flt.s %s, %s, %s;", rd_name, frs1_name, frs2_name);
+ if (__isnanf (a) || __isnanf (b))
+ {
+ result = 0;
+ exception = 1;
+ }
+ else
+ result = (a < b);
+ break;
+ case FLE:
+ TRACE_INSN (cpu, "fle.s %s, %s, %s;", rd_name, frs1_name, frs2_name);
+ if (__isnanf (a) || __isnanf (b))
+ {
+ result = 0;
+ exception = 1;
+ }
+ else
+ result = (a <= b);
+ break;
+ case FCLASS:
+ TRACE_INSN (cpu, "fclass.s %s, %s;", rd_name, frs1_name);
+ bit_pos = 0;
+ exception = 0;
+ result = riscv_cpu->regs[rd];
+ sign = __signbitf (a);
+ if (__isinff (a))
+ {
+ if (sign)
+ bit_pos = 0; /* -INF. */
+ else
+ bit_pos = 7; /* +INF. */
+ }
+ else if (fpclassify (a) == FP_SUBNORMAL)
+ {
+ if (sign)
+ bit_pos = 2; /* -SUBNORMAL. */
+ else
+ bit_pos = 5; /* +SUBNORMAL. */
+ }
+ else if (fpclassify (a) == FP_ZERO)
+ {
+ if (sign)
+ bit_pos = 3; /* -ZERO. */
+ else
+ bit_pos = 4; /* +ZERO. */
+ }
+ else if (__issignalingf (a))
+ bit_pos = 8; /* signaling NaN. */
+ else if (__isnanf (a))
+ bit_pos = 9; /* quiet NaN. */
+ else
+ {
+ if (sign)
+ bit_pos = 1; /* -NORMAL. */
+ else
+ bit_pos = 6; /* +NORMAL. */
+ }
+ result |= (1 << bit_pos);
+ break;
+ }
+
+ store_rd (cpu, rd, result);
+
+ if (exception)
+ {
+ riscv_cpu->csr.fcsr |= FCSR_NV;
+ riscv_cpu->csr.fflags |= FCSR_NV;
+ TRACE_REGISTER (cpu, "wrote CSR fcsr |= NV");
+ }
+}
+
+/* Simulate single precision floating point instructions. */
+static sim_cia
+execute_f (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+ struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+ SIM_DESC sd = CPU_STATE (cpu);
+ int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
+ int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
+ int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
+ const char *frd_name = riscv_fpr_names_abi[rd];
+ const char *rd_name = riscv_gpr_names_abi[rd];
+ const char *frs1_name = riscv_fpr_names_abi[rs1];
+ const char *frs2_name = riscv_fpr_names_abi[rs2];
+ const char *rs1_name = riscv_gpr_names_abi[rs1];
+ signed_word i_imm = EXTRACT_ITYPE_IMM (iw);
+ signed_word s_imm = EXTRACT_STYPE_IMM (iw);
+ int is_32bit = (RISCV_XLEN (cpu) == 32);
+
+ sim_cia pc = riscv_cpu->pc + 4;
+
+ switch (op->match)
+ {
+ case MATCH_FLW:
+ TRACE_INSN (cpu, "flw %s, %" PRIiTW "(%s);",
+ frd_name, i_imm, rs1_name);
+ store_fp (cpu, rd, sim_core_read_unaligned_4 (cpu, riscv_cpu->pc,
+ read_map, riscv_cpu->regs[rs1] + i_imm));
+ break;
+ case MATCH_FSW:
+ TRACE_INSN (cpu, "fsw %s, %" PRIiTW "(%s);",
+ frs2_name, s_imm, rs1_name);
+ sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, write_map,
+ riscv_cpu->regs[rs1] + s_imm,
+ riscv_cpu->fpregs[rs2]);
+ break;
+ case MATCH_FMV_X_S:
+ TRACE_INSN (cpu, "fmv.x.w %s, %s;", rd_name, frs1_name);
+ if (is_32bit)
+ store_rd (cpu, rd, riscv_cpu->fpregs[rs1]);
+ else
+ {
+ uint64_t f64bits;
+ f64bits = (uint64_t) ((uint32_t) riscv_cpu->fpregs[rs1]);
+ if (f64bits & 0x80000000)
+ f64bits = (uint64_t) (0xffffffff00000000ull | (uint32_t) f64bits);
+ store_rd (cpu, rd, f64bits);
+ }
+ break;
+ case MATCH_FMV_S_X:
+ TRACE_INSN (cpu, "fmv.w.x %s, %s;", frd_name, rs1_name);
+ store_fp (cpu, rd, riscv_cpu->regs[rs1]);
+ break;
+ case MATCH_FSGNJ_S:
+ {
+ uint32_t rs1_bits, rs2_bits;
+ TRACE_INSN (cpu, "fsgnj.s %s, %s, %s;",
+ frd_name, frs1_name, frs2_name);
+ rs1_bits = (uint32_t) riscv_cpu->fpregs[rs1];
+ rs2_bits = (uint32_t) riscv_cpu->fpregs[rs2];
+ rs1_bits = (rs2_bits & 0x80000000) | (rs1_bits & 0x7fffffff);
+ store_fp (cpu, rd, rs1_bits);
+ break;
+ }
+ case MATCH_FEQ_S:
+ float32_compare (cpu, rd, rs1, rs2, FEQ);
+ break;
+ case MATCH_FLT_S:
+ float32_compare (cpu, rd, rs1, rs2, FLT);
+ break;
+ case MATCH_FLE_S:
+ float32_compare (cpu, rd, rs1, rs2, FLE);
+ break;
+ case MATCH_FCLASS_S:
+ float32_compare (cpu, rd, rs1, 0, FCLASS);
+ break;
+ default:
+ TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+ sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled, SIM_SIGILL);
+ }
+
+ return pc;
+}
+
static sim_cia
execute_m (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
{
@@ -1313,6 +1524,9 @@ execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled,
SIM_SIGILL);
}
+ case INSN_CLASS_F:
+ case INSN_CLASS_F_INX:
+ return execute_f (cpu, iw, op);
case INSN_CLASS_I:
return execute_i (cpu, iw, op);
case INSN_CLASS_M:
new file mode 100644
@@ -0,0 +1,75 @@
+# Single precision compare and classify tests.
+# mach: riscv32 riscv64
+# sim(riscv32): --model RV32IF
+# sim(riscv64): --model RV64ID
+# ld(riscv32): -m elf32lriscv
+# ld(riscv64): -m elf64lriscv
+# as(riscv32): -march=rv32if
+# as(riscv64): -march=rv64id
+
+.include "testutils.inc"
+
+ .section .data
+ .align 2
+
+_arg1:
+ .float 0.5
+ .float 1.1
+ .word 0xff800000 # -INF
+ .word 0x7faaaaaa # sNAN
+ .word 0x7feaaaaa # qNAN
+
+_arg2:
+ .float 0.5
+ .float 2.2
+
+ start
+ .option push
+ .option norelax
+ la a0,_arg1
+ la a1,_arg2
+ li a3,1
+ .option pop
+
+ # Test feq instruction.
+ flw fa0,0(a0)
+ flw fa1,0(a1)
+ feq.s a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test flt instruction.
+ flw fa0,4(a0)
+ flw fa1,4(a1)
+ mv a4,x0
+ flt.s a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test fle instruction.
+ flw fa0,4(a0)
+ flw fa1,4(a1)
+ mv a4,x0
+ fle.s a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test fclass instruction.
+ flw fa0,8(a0)
+ mv a4,x0
+ li a3,0x1 # 1 << 0
+ fclass.s a4,fa0
+ bne a3,a4,test_fail
+ flw fa0,12(a0)
+ mv a4,x0
+ li a3,0x100 # 1 << 8
+ fclass.s a4,fa0
+ bne a3,a4,test_fail
+ flw fa0,16(a0)
+ mv a4,x0
+ li a3,0x200 # 1 << 9
+ fclass.s a4,fa0
+ bne a3,a4,test_fail
+
+test_pass:
+ pass
+
+test_fail:
+ fail
new file mode 100644
@@ -0,0 +1,62 @@
+# Single precision load-store and move tests.
+# mach: riscv32 riscv64
+# sim(riscv32): --model RV32IF
+# sim(riscv64): --model RV64ID
+# ld(riscv32): -m elf32lriscv
+# ld(riscv64): -m elf64lriscv
+# as(riscv32): -march=rv32if
+# as(riscv64): -march=rv64id
+
+.include "testutils.inc"
+
+ .section .data
+ .align 2
+
+_src:
+ .float 0.5
+
+_dst:
+ .float 0.5
+ .float 0
+ .word 0x3f000000 # 0.5
+
+ start
+ .option push
+ .option norelax
+ la a0,_src
+ la a1,_dst
+ li a3,1
+ .option pop
+
+ # Test load instruction.
+ flw fa0,0(a0)
+ flw fa1,0(a1)
+ feq.s a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test store instruction.
+ flw fa0,0(a0)
+ fsw fa0,4(a1)
+ flw fa1,4(a1)
+ feq.s a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test convert float value to integer encoding instruction.
+ flw fa0,0(a0) # load float value.
+ lw a4,8(a1) # load expected result.
+ fmv.x.w a2,fa0 # convert bit pattern into integer register.
+ bne a4,a2,test_fail # compare result with expected.
+
+ # Test convert integer encoding to float value instruction.
+ lw a4,8(a1) # load integer encoding.
+ fmv.w.x fa1,a4 # convert encoding into float value.
+ flw fa0,0(a0) # load expected float value.
+ feq.s a5,fa0,fa1 # compare result with expected.
+ bne a5,a3,test_fail
+
+
+test_pass:
+ pass
+
+test_fail:
+ fail
new file mode 100644
@@ -0,0 +1,52 @@
+# Single precision sign-injection instructions.
+# mach: riscv32 riscv64
+# sim(riscv32): --model RV32IF
+# sim(riscv64): --model RV64ID
+# ld(riscv32): -m elf32lriscv
+# ld(riscv64): -m elf64lriscv
+# as(riscv32): -march=rv32if
+# as(riscv64): -march=rv64id
+
+.include "testutils.inc"
+
+ .section .data
+ .align 2
+
+_arg1:
+ .float 2.0
+
+_arg2:
+ .float 1.0
+ .float -1.0
+
+_expected:
+ .float 2.0
+ .float -2.0
+
+ start
+ .option push
+ .option norelax
+ la a0,_arg1
+ la a1,_arg2
+ la a2,_expected
+ li a3,1
+ .option pop
+
+ # Test fsgnj.s instruction.
+ flw fa0,0(a0)
+ flw fa1,0(a1)
+ flw fa2,0(a2)
+ fsgnj.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+ flw fa1,4(a1)
+ flw fa2,4(a2)
+ fsgnj.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+
+test_pass:
+ pass
+
+test_fail:
+ fail