@@ -1254,6 +1254,111 @@ convert_long_to_float (SIM_CPU *cpu, int rd, int rs1, int sign,
store_fp (cpu, rd, rd_bits);
}
+/* Handle double precision floating point compare instructions. */
+static void
+float64_compare (SIM_CPU *cpu, int rd, int rs1, int rs2, int flags)
+{
+ struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+ double a, b = .0f;
+ uint64_t result = 0, exception = 0, sign = 0, bit_pos;
+ uint64_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 = (uint64_t) riscv_cpu->fpregs[rs1];
+ memcpy (&a, &rs1_bits, sizeof (a));
+ if (flags != FCLASS)
+ {
+ rs2_bits = (uint64_t) riscv_cpu->fpregs[rs2];
+ memcpy (&b, &rs2_bits, sizeof (b));
+ }
+
+ switch (flags)
+ {
+ case FEQ:
+ TRACE_INSN (cpu, "feq.d %s, %s, %s;", rd_name, frs1_name, frs2_name);
+ if (__isnan (a) || __isnan (b))
+ {
+ result = 0;
+ if (__issignaling (a) || __issignaling (b))
+ exception = 1;
+ }
+ else
+ result = (a == b);
+ break;
+ case FLT:
+ TRACE_INSN (cpu, "flt.d %s, %s, %s;", rd_name, frs1_name, frs2_name);
+ if (__isnan (a) || __isnan (b))
+ {
+ result = 0;
+ exception = 1;
+ }
+ else
+ result = (a < b);
+ break;
+ case FLE:
+ TRACE_INSN (cpu, "fle.d %s, %s, %s;", rd_name, frs1_name, frs2_name);
+ if (__isnan (a) || __isnan (b))
+ {
+ result = 0;
+ exception = 1;
+ }
+ else
+ result = (a <= b);
+ break;
+ case FCLASS:
+ TRACE_INSN (cpu, "fclass.d %s, %s;", rd_name, frs1_name);
+ bit_pos = 0;
+ exception = 0;
+ result = riscv_cpu->regs[rd];
+ sign = __signbit (a);
+ if (__isinf (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 (__issignaling (a))
+ bit_pos = 8; /* signaling NaN. */
+ else if (__isnan (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)
@@ -1496,6 +1601,81 @@ execute_f (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
return pc;
}
+/* Simulate double precision floating point instructions. */
+static sim_cia
+execute_d (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);
+
+ sim_cia pc = riscv_cpu->pc + 4;
+
+ switch (op->match)
+ {
+ case MATCH_FLD:
+ TRACE_INSN (cpu, "fld %s, %" PRIiTW "(%s);",
+ frd_name, i_imm, rs1_name);
+ store_fp (cpu, rd, sim_core_read_unaligned_8
+ (cpu, riscv_cpu->pc, read_map,
+ riscv_cpu->regs[rs1] + i_imm));
+ break;
+ case MATCH_FSD:
+ TRACE_INSN (cpu, "fsd %s, %" PRIiTW "(%s);",
+ frs2_name, s_imm, rs1_name);
+ sim_core_write_unaligned_8
+ (cpu, riscv_cpu->pc, write_map,
+ riscv_cpu->regs[rs1] + s_imm, riscv_cpu->fpregs[rs2]);
+ break;
+ case MATCH_FMV_X_D:
+ TRACE_INSN (cpu, "fmv.x.d %s, %s;", rd_name, frs1_name);
+ store_rd (cpu, rd, riscv_cpu->fpregs[rs1]);
+ break;
+ case MATCH_FMV_D_X:
+ TRACE_INSN (cpu, "fmv.d.x %s, %s;", frd_name, rs1_name);
+ store_fp (cpu, rd, riscv_cpu->regs[rs1]);
+ break;
+ case MATCH_FEQ_D:
+ float64_compare (cpu, rd, rs1, rs2, FEQ);
+ break;
+ case MATCH_FLT_D:
+ float64_compare (cpu, rd, rs1, rs2, FLT);
+ break;
+ case MATCH_FLE_D:
+ float64_compare (cpu, rd, rs1, rs2, FLE);
+ break;
+ case MATCH_FCLASS_D:
+ float64_compare (cpu, rd, rs1, 0, FCLASS);
+ break;
+ case MATCH_FSGNJ_D:
+ {
+ uint64_t rs1_bits, rs2_bits;
+ TRACE_INSN (cpu, "fsgnj.d %s, %s, %s;",
+ frd_name, frs1_name, frs2_name);
+ rs1_bits = (uint64_t) riscv_cpu->fpregs[rs1];
+ rs2_bits = (uint64_t) riscv_cpu->fpregs[rs2];
+ rs1_bits = (rs2_bits & 0x8000000000000000ull)
+ | (rs1_bits & 0x7fffffffffffffffull);
+ store_fp (cpu, rd, rs1_bits);
+ 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)
{
@@ -2127,6 +2307,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_D:
+ case INSN_CLASS_D_INX:
+ return execute_d (cpu, iw, op);
case INSN_CLASS_F:
case INSN_CLASS_F_INX:
return execute_f (cpu, iw, op);
new file mode 100755
@@ -0,0 +1,72 @@
+# Double precision compare and classify tests.
+# mach: riscv64
+# sim(riscv64): --model RV64ID
+# ld(riscv64): -m elf64lriscv
+# as(riscv64): -march=rv64id
+
+.include "testutils.inc"
+
+ .section .data
+ .align 3
+
+_arg1:
+ .double 0.5
+ .double 1.1
+ .dword 0xfff0000000000000 # -INF
+ .dword 0x7ff4000000000000 # sNAN
+ .dword 0x7ff8000000000000 # qNAN
+
+_arg2:
+ .double 0.5
+ .double 2.2
+
+ start
+ .option push
+ .option norelax
+ la a0,_arg1
+ la a1,_arg2
+ li a3,1
+ .option pop
+
+ # Test feq instruction.
+ fld fa0,0(a0)
+ fld fa1,0(a1)
+ feq.d a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test flt instruction.
+ fld fa0,8(a0)
+ fld fa1,8(a1)
+ mv a4,x0
+ flt.d a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test fle instruction.
+ fld fa0,8(a0)
+ fld fa1,8(a1)
+ mv a4,x0
+ fle.d a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test fclass instruction.
+ fld fa0,16(a0)
+ mv a4,x0
+ li a3,0x1 # 1 << 0
+ fclass.d a4,fa0
+ bne a3,a4,test_fail
+ fld fa0,24(a0)
+ mv a4,x0
+ li a3,0x100 # 1 << 8
+ fclass.d a4,fa0
+ bne a3,a4,test_fail
+ fld fa0,32(a0)
+ mv a4,x0
+ li a3,0x200 # 1 << 9
+ fclass.d a4,fa0
+ bne a3,a4,test_fail
+
+test_pass:
+ pass
+
+test_fail:
+ fail
new file mode 100755
@@ -0,0 +1,58 @@
+# Double precision load-store and move tests.
+# mach: riscv64
+# sim(riscv64): --model RV64ID
+# ld(riscv64): -m elf64lriscv
+# as(riscv64): -march=rv64id
+
+.include "testutils.inc"
+
+ .section .data
+ .align 3
+
+_src:
+ .double 0.5
+
+_dst:
+ .double 0.5
+ .double 0
+ .dword 0x3FE0000000000000 # 0.5
+
+ start
+ .option push
+ .option norelax
+ la a0,_src
+ la a1,_dst
+ li a3,1
+ .option pop
+
+ # Test load instruction.
+ fld fa0,0(a0)
+ fld fa1,0(a1)
+ feq.d a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test store instruction.
+ fld fa0,0(a0)
+ fsd fa0,8(a1)
+ fld fa1,8(a1)
+ feq.d a4,fa0,fa1
+ bne a4,a3,test_fail
+
+ # Test convert double value to integer encoding instruction.
+ fld fa0,0(a0) # load double value.
+ ld a4,16(a1) # load expected result.
+ fmv.x.d a2,fa0 # convert bit pattern into integer register.
+ bne a4,a2,test_fail # compare result with expected.
+
+ # Test convert integer encoding to double value instruction.
+ lw a4,16(a1) # load integer encoding.
+ fmv.d.x fa1,a4 # convert encoding into double value.
+ flw fa0,0(a0) # load expected double value.
+ feq.d a5,fa0,fa1 # compare result with expected.
+ bne a5,a3,test_fail
+
+test_pass:
+ pass
+
+test_fail:
+ fail