[07/11] sim: riscv: Add double precision floating-point load-store, move, compare and classify instructions

Message ID 20240226142628.1629048-4-bhushan.attarde@imgtec.com
State New
Headers
Series sim: riscv: simulation of single and double precision floating point instructions |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Testing passed

Commit Message

Bhushan Attarde Feb. 26, 2024, 2:26 p.m. UTC
  From: Bhushan Attarde <bhushan.attarde@imgtec.com>

Added simulation of following single precision floating-point instructions
fld, fsd, fmv.x.d, fmv.d.x, fsgnj.d, feq.d, flt.d, fle.d and fclass.d.

Added test files d-fp-compare.s and d-fp-load-store.s in sim/testsuite/riscv/
to test these instructions.
---
 sim/riscv/sim-main.c                  | 183 ++++++++++++++++++++++++++
 sim/testsuite/riscv/d-fp-compare.s    |  72 ++++++++++
 sim/testsuite/riscv/d-fp-load-store.s |  58 ++++++++
 3 files changed, 313 insertions(+)
 create mode 100755 sim/testsuite/riscv/d-fp-compare.s
 create mode 100755 sim/testsuite/riscv/d-fp-load-store.s
  

Patch

diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
index 4d4ad82cce9..4313516b8b7 100644
--- a/sim/riscv/sim-main.c
+++ b/sim/riscv/sim-main.c
@@ -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);
diff --git a/sim/testsuite/riscv/d-fp-compare.s b/sim/testsuite/riscv/d-fp-compare.s
new file mode 100755
index 00000000000..0e168fed9de
--- /dev/null
+++ b/sim/testsuite/riscv/d-fp-compare.s
@@ -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
diff --git a/sim/testsuite/riscv/d-fp-load-store.s b/sim/testsuite/riscv/d-fp-load-store.s
new file mode 100755
index 00000000000..1eccf5720a9
--- /dev/null
+++ b/sim/testsuite/riscv/d-fp-load-store.s
@@ -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