@@ -75,6 +75,8 @@ static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
#define FLT 2
#define FLE 3
#define FCLASS 4
+#define FMIN 5
+#define FMAX 6
static INLINE void
store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
@@ -810,6 +812,39 @@ float32_compare (SIM_CPU *cpu, int rd, int rs1, int rs2, int flags)
}
}
+/* Handle single precision floating point math instructions. */
+static void
+float32_math (SIM_CPU *cpu, int rd, int rs1, int rs2, int flags)
+{
+ struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+ float a, b, result = 0;
+ uint32_t rs1_bits, rs2_bits, rd_bits;
+ const char *frd_name = riscv_fpr_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));
+ rs2_bits = (uint32_t) riscv_cpu->fpregs[rs2];
+ memcpy (&b, &rs2_bits, sizeof (b));
+
+ switch (flags)
+ {
+ case FMAX:
+ TRACE_INSN (cpu, "fmax.s %s, %s, %s;", frd_name, frs1_name, frs2_name);
+ result = fmaxf (a, b);
+ break;
+ case FMIN:
+ TRACE_INSN (cpu, "fmin.s %s, %s, %s;", frd_name, frs1_name, frs2_name);
+ result = fminf (a, b);
+ break;
+ }
+
+ /* Store result. */
+ memcpy (&rd_bits, &result, sizeof (result));
+ store_fp (cpu, rd, rd_bits);
+}
+
/* Simulate single precision floating point instructions. */
static sim_cia
execute_f (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
@@ -885,6 +920,35 @@ execute_f (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
case MATCH_FCLASS_S:
float32_compare (cpu, rd, rs1, 0, FCLASS);
break;
+ case MATCH_FSGNJN_S:
+ {
+ uint32_t rs1_bits, rs2_bits;
+ TRACE_INSN (cpu, "fsgnjn.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_FSGNJX_S:
+ {
+ uint32_t rs1_bits, rs2_bits;
+ TRACE_INSN (cpu, "fsgnjx.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 = ((rs1_bits & 0x80000000) ^ (rs2_bits & 0x80000000))
+ | (rs1_bits & 0x7fffffff);
+ store_fp (cpu, rd, rs1_bits);
+ break;
+ }
+ case MATCH_FMIN_S:
+ float32_math (cpu, rd, rs1, rs2, FMIN);
+ break;
+ case MATCH_FMAX_S:
+ float32_math (cpu, rd, rs1, rs2, FMAX);
+ break;
default:
TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled, SIM_SIGILL);
@@ -23,11 +23,16 @@ _arg2:
.float 0.5
.float 2.2
+_expected:
+ .float 0.5
+ .float 2.2
+
start
.option push
.option norelax
la a0,_arg1
la a1,_arg2
+ la a2,_expected
li a3,1
.option pop
@@ -68,6 +73,23 @@ _arg2:
fclass.s a4,fa0
bne a3,a4,test_fail
+ # Test fmin.s instruction.
+ flw fa0,0(a0)
+ flw fa1,4(a1)
+ flw fa2,0(a2)
+ fmin.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ li a3,1
+ bne a4,a3,test_fail
+
+ # Test fmax.s instruction.
+ flw fa0,0(a0)
+ flw fa1,4(a1)
+ flw fa2,4(a2)
+ fmax.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+
test_pass:
pass
@@ -14,6 +14,7 @@
_arg1:
.float 2.0
+ .float -2.0
_arg2:
.float 1.0
@@ -45,6 +46,43 @@ _expected:
feq.s a4,fa3,fa2
bne a4,a3,test_fail
+ # Test fsgnjn.s (fneg.s) instruction.
+ flw fa0,0(a0)
+ flw fa1,0(a1)
+ flw fa2,4(a2)
+ fsgnjn.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+ flw fa1,4(a1)
+ flw fa2,0(a2)
+ fsgnjn.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+ flw fa0,0(a0)
+ flw fa2,4(a2)
+ fneg.s fa3,fa0
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+
+ # Test fsgnjx.s (fabs.s) instruction.
+ flw fa0,0(a0)
+ flw fa1,4(a1)
+ flw fa2,4(a2)
+ fsgnjx.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+ flw fa0,4(a0)
+ flw fa1,4(a1)
+ flw fa2,0(a2)
+ fsgnjx.s fa3,fa0,fa1
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+ flw fa0,4(a0)
+ flw fa2,0(a2)
+ fabs.s fa3,fa0
+ feq.s a4,fa3,fa2
+ bne a4,a3,test_fail
+
test_pass:
pass