[PATCH 06/24] RISC-V: Add fp support.

Jim Wilson jimw@sifive.com
Sat Apr 17 17:58:13 GMT 2021


From: Monk Chiang <monk@andestech.com>

Add F and D instruction support.

	sim/riscv/
	* sim-main.c: Include sim-fpu.h.
	(store_frd, store_frd64, execute_d, execute_f): New functions.
	(execute_i): Call new execute functions.
	* sim-main.h (union FRegisterValue): New.
	(struct _sim_cpu): Change fpregs to use FRegisterValue.
---
 sim/riscv/sim-main.c | 662 +++++++++++++++++++++++++++++++++++++++++++++++++++
 sim/riscv/sim-main.h |  15 +-
 2 files changed, 676 insertions(+), 1 deletion(-)

diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
index 1b9fb89..de76089 100644
--- a/sim/riscv/sim-main.c
+++ b/sim/riscv/sim-main.c
@@ -27,6 +27,7 @@
 #include <time.h>
 
 #include "sim-main.h"
+#include "sim-fpu.h"
 #include "sim-syscall.h"
 
 #include "opcode/riscv.h"
@@ -72,6 +73,18 @@ store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
     }
 }
 
+static INLINE void
+store_frd (SIM_CPU *cpu, int rd, unsigned_word val)
+{
+  cpu->fpregs[rd].w[0] = val;
+}
+
+static inline void
+store_frd64 (SIM_CPU *cpu, int rd, uint64_t val)
+{
+  cpu->fpregs[rd].v[0] = val;
+}
+
 static INLINE unsigned_word
 fetch_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg)
 {
@@ -144,6 +157,651 @@ ashiftrt64 (unsigned_word val, unsigned_word shift)
 }
 
 static sim_cia
+execute_d (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  unsigned int mask_arithmetic = MASK_FADD_D;
+  unsigned int mask_mul_add = MASK_FMADD_S;
+  unsigned int mask_convert = MASK_FCVT_S_W;
+
+  static const int round_modes[] =
+  {
+      sim_fpu_round_near, sim_fpu_round_zero,
+      sim_fpu_round_down, sim_fpu_round_up,
+      sim_fpu_round_default, sim_fpu_round_default,
+      sim_fpu_round_default
+  };
+
+  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;
+  int rs3 = (iw >> OP_SH_RS3) & OP_MASK_RS3;
+  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];
+  const char *frs3_name = riscv_fpr_names_abi[rs3];
+  const char *rd_name = riscv_gpr_names_abi[rd];
+  const char *rs1_name = riscv_gpr_names_abi[rs1];
+  unsigned_word i_imm = EXTRACT_ITYPE_IMM (iw);
+  unsigned_word s_imm = EXTRACT_STYPE_IMM (iw);
+  uint32_t u32;
+  int32_t i32;
+  uint64_t u64;
+  int64_t i64;
+  sim_cia pc = cpu->pc + 4;
+
+  /* Rounding mode.  */
+  int rm = (iw >> OP_SH_RM) & OP_MASK_RM;
+  int rounding = round_modes[rm];
+
+  sim_fpu sft, sft2;
+  sim_fpu sfa, sfb, sfc;
+  sim_fpu_64to (&sfa, cpu->fpregs[rs1].v[0]);
+  sim_fpu_64to (&sfb, cpu->fpregs[rs2].v[0]);
+
+  switch (op->match & mask_mul_add)
+    {
+    case MATCH_FMADD_D:
+      TRACE_INSN (cpu, "fmadd.d %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_64to (&sfc, cpu->fpregs[rs3].v[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_add (&sft, &sfc, &sft2);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FMSUB_D:
+      TRACE_INSN (cpu, "fmsub.d %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_64to (&sfc, cpu->fpregs[rs3].v[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_sub (&sft, &sft2, &sfc);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FNMADD_D:
+      TRACE_INSN (cpu, "fnmadd.d %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_64to (&sfc, cpu->fpregs[rs3].v[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_add (&sft, &sfc, &sft2);
+      sim_fpu_neg (&sft, &sft);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FNMSUB_D:
+      TRACE_INSN (cpu, "fnmsub.d %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_64to (&sfc, cpu->fpregs[rs3].v[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_sub (&sft, &sft2, &sfc);
+      sim_fpu_neg (&sft, &sft);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    }
+
+  switch (op->match & mask_arithmetic)
+    {
+    case MATCH_FADD_D:
+      TRACE_INSN (cpu, "fadd.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_add (&sft, &sfa, &sfb);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FSUB_D:
+      TRACE_INSN (cpu, "fsub.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_sub (&sft, &sfa, &sfb);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FMUL_D:
+      TRACE_INSN (cpu, "fmul.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_mul (&sft, &sfa, &sfb);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FDIV_D:
+      TRACE_INSN (cpu, "fdiv.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_div (&sft, &sfa, &sfb);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FSQRT_D:
+      TRACE_INSN (cpu, "fsqrt.d %s, %s",
+		  frd_name, frs1_name);
+      sim_fpu_sqrt (&sft, &sfa);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    }
+
+  switch (op->match & mask_convert)
+    {
+    case MATCH_FCVT_W_D:
+      TRACE_INSN (cpu, "fcvt.w.d %s, %s",
+		  rd_name, frs1_name);
+      sim_fpu_to32i (&i32, &sfa, rounding);
+      cpu->regs[rd] = i32;
+      goto done;
+    case MATCH_FCVT_WU_D:
+      TRACE_INSN (cpu, "fcvt.wu.d %s, %s",
+		  rd_name, frs1_name);
+      sim_fpu_to32u (&u32, &sfa, rounding);
+      i32 = u32;
+      cpu->regs[rd] = i32;
+      goto done;
+    case MATCH_FCVT_D_W:
+      TRACE_INSN (cpu, "fcvt.d.w %s, %s",
+		  frd_name, rs1_name);
+      sim_fpu_i32to (&sft, cpu->regs[rs1], rounding);
+      sim_fpu_to64 ((unsigned64 *) (cpu->fpregs + rd), &sft);
+      goto done;
+    case MATCH_FCVT_D_WU:
+      TRACE_INSN (cpu, "fcvt.d.wu %s, %s",
+		  frd_name, rs1_name);
+      sim_fpu_u32to (&sft, cpu->regs[rs1], rounding);
+      sim_fpu_to64 ((unsigned64 *) (cpu->fpregs + rd), &sft);
+      goto done;
+    case MATCH_FCVT_S_D:
+      TRACE_INSN (cpu, "fcvt.s.d %s, %s",
+		  frd_name, frs1_name);
+      sft = sfa;
+      sim_fpu_round_32 (&sft, sim_fpu_round_near, sim_fpu_denorm_default);
+      sim_fpu_to32 ((unsigned32 *) (cpu -> fpregs + rd), &sft);
+      goto done;
+    case MATCH_FCVT_D_S:
+      TRACE_INSN (cpu, "fcvt.d.s %s, %s",
+		  frd_name, frs1_name);
+      sim_fpu_32to (&sft, cpu->fpregs[rs1].w[0]);
+      sim_fpu_to64 (&cpu->fpregs[rd].v[0], &sft);
+      goto done;
+    case MATCH_FCVT_L_D:
+      TRACE_INSN (cpu, "fcvt.l.d %s, %s",
+		  rd_name, frs1_name);
+      cpu->regs[rd] = (int64_t) cpu->fpregs[rs1].D[0];
+      goto done;
+    case MATCH_FCVT_LU_D:
+      TRACE_INSN (cpu, "fcvt.lu.d %s, %s",
+		  rd_name, frs1_name);
+      cpu->regs[rd] = (uint64_t) cpu->fpregs[rs1].D[0];
+      goto done;
+    case MATCH_FCVT_D_L:
+      TRACE_INSN (cpu, "fcvt.d.l %s, %s",
+		  frd_name, rs1_name);
+      cpu->fpregs[rd].D[0] = (double) ((int64_t) cpu->regs[rs1]);
+      goto done;
+    case MATCH_FCVT_D_LU:
+      TRACE_INSN (cpu, "fcvt.d.lu %s, %s",
+		  frd_name, rs1_name);
+      cpu->fpregs[rd].D[0] = (double) cpu->regs[rs1];
+      goto done;
+    }
+
+  switch (op->match)
+    {
+    case MATCH_FLD:
+      TRACE_INSN (cpu, "fld %s, %" PRIiTW "(%s)",
+		  frd_name, i_imm, rs1_name);
+      store_frd64 (cpu, rd,
+	sim_core_read_unaligned_8 (cpu, cpu->pc, read_map,
+				   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, cpu->pc, write_map,
+				  cpu->regs[rs1] + s_imm,
+				  cpu->fpregs[rs2].v[0]);
+      break;
+    case MATCH_FSGNJ_D:
+      TRACE_INSN (cpu, "fsgnj.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      u32 = cpu->fpregs[rs1].w[1] & 0x7fffffff;
+      u32 |= cpu->fpregs[rs2].w[1] & 0x80000000;
+      cpu->fpregs[rd].w[1] = u32;
+      cpu->fpregs[rd].w[0] = cpu->fpregs[rs1].w[0];
+      break;
+    case MATCH_FSGNJN_D:
+      TRACE_INSN (cpu, "fsgnjn.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      u32 = cpu->fpregs[rs1].w[1] & 0x7fffffff;
+      u32 |= (cpu->fpregs[rs2].w[1] & 0x80000000) ^ 0x80000000;
+      cpu->fpregs[rd].w[1] = u32;
+      cpu->fpregs[rd].w[0] = cpu->fpregs[rs1].w[0];
+      break;
+    case MATCH_FSGNJX_D:
+      TRACE_INSN (cpu, "fsgnjx.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      u32 = cpu->fpregs[rs1].w[1] & 0x7fffffff;
+      u32 |= (cpu->fpregs[rs1].w[1] & 0x80000000) ^ (cpu->fpregs[rs2].w[1] & 0x80000000);
+      cpu->fpregs[rd].w[1] = u32;
+      cpu->fpregs[rd].w[0] = cpu->fpregs[rs1].w[0];
+      break;
+    case MATCH_FMIN_D:
+      TRACE_INSN (cpu, "fmin.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      if (cpu->fpregs[rs1].D[0] < cpu->fpregs[rs2].D[0])
+	cpu->fpregs[rd].D[0] = cpu->fpregs[rs1].D[0];
+      else
+	cpu->fpregs[rd].D[0] = cpu->fpregs[rs2].D[0];
+      break;
+    case MATCH_FMAX_D:
+      TRACE_INSN (cpu, "fmax.d %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      if (cpu->fpregs[rs1].D[0] > cpu->fpregs[rs2].D[0])
+	cpu->fpregs[rd].D[0] = cpu->fpregs[rs1].D[0];
+      else
+	cpu->fpregs[rd].D[0] = cpu->fpregs[rs2].D[0];
+      break;
+    case MATCH_FMV_X_D:
+      TRACE_INSN (cpu, "fmv.x.d %s, %s",
+		  rd_name, frs1_name);
+      cpu->regs[rd] = cpu->fpregs[rs1].v[0];
+      break;
+    case MATCH_FMV_D_X:
+      TRACE_INSN (cpu, "fmv.d.x %s, %s",
+		  frd_name, frs1_name);
+      cpu->fpregs[rd].v[0] = cpu->regs[rs1];
+      break;
+    case MATCH_FEQ_D:
+      TRACE_INSN (cpu, "feq.d %s, %s, %s",
+		  rd_name, frs1_name, frs2_name);
+      cpu->regs[rd] = sim_fpu_is_eq (&sfa, &sfb);
+      break;
+    case MATCH_FLE_D:
+      TRACE_INSN (cpu, "fle.d %s, %s, %s",
+		  rd_name, frs1_name, frs2_name);
+      cpu->regs[rd] = sim_fpu_is_le (&sfa, &sfb);
+      break;
+    case MATCH_FLT_D:
+      TRACE_INSN (cpu, "flt.d %s, %s, %s",
+		  rd_name, frs1_name, frs2_name);
+      cpu->regs[rd] = sim_fpu_is_lt (&sfa, &sfb);
+      break;
+    case MATCH_FCLASS_D:
+      TRACE_INSN (cpu, "fclass.d %s, %s",
+		  rd_name, frs1_name);
+      switch (sim_fpu_is (&sfa))
+	{
+	case SIM_FPU_IS_NINF:
+	  cpu->regs[rd] = 1;
+	  break;
+	case SIM_FPU_IS_NNUMBER:
+	  cpu->regs[rd] = 1 << 1;
+	  break;
+	case SIM_FPU_IS_NDENORM:
+	  cpu->regs[rd] = 1 << 2;
+	  break;
+	case SIM_FPU_IS_NZERO:
+	  cpu->regs[rd] = 1 << 3;
+	  break;
+	case SIM_FPU_IS_PZERO:
+	  cpu->regs[rd] = 1 << 4;
+	  break;
+	case SIM_FPU_IS_PDENORM:
+	  cpu->regs[rd] = 1 << 5;
+	  break;
+	case SIM_FPU_IS_PNUMBER:
+	  cpu->regs[rd] = 1 << 6;
+	  break;
+	case SIM_FPU_IS_PINF:
+	  cpu->regs[rd] = 1 << 7;
+	  break;
+	case SIM_FPU_IS_SNAN:
+	  cpu->regs[rd] = 1 << 8;
+	  break;
+	case SIM_FPU_IS_QNAN:
+	  cpu->regs[rd] = 1 << 9;
+	  break;
+	}
+      break;
+    default:
+      TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+      sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+    }
+
+ done:
+  return pc;
+
+}
+
+static sim_cia
+execute_f (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  unsigned int mask_arithmetic = MASK_FADD_S;
+  unsigned int mask_mul_add = MASK_FMADD_S;
+  unsigned int mask_convert = MASK_FCVT_S_W;
+
+  static const int round_modes[] =
+  {
+      sim_fpu_round_near, sim_fpu_round_zero,
+      sim_fpu_round_down, sim_fpu_round_up,
+      sim_fpu_round_default, sim_fpu_round_default,
+      sim_fpu_round_default
+  };
+
+  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;
+  int rs3 = (iw >> OP_SH_RS3) & OP_MASK_RS3;
+  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];
+  const char *frs3_name = riscv_fpr_names_abi[rs3];
+  const char *rd_name = riscv_gpr_names_abi[rd];
+  const char *rs1_name = riscv_gpr_names_abi[rs1];
+  unsigned_word i_imm = EXTRACT_ITYPE_IMM (iw);
+  unsigned_word s_imm = EXTRACT_STYPE_IMM (iw);
+  uint32_t u32;
+  int32_t i32;
+  int64_t i64;
+  uint64_t u64;
+  sim_cia pc = cpu->pc + 4;
+
+  /* Rounding mode.  */
+  int rm = (iw >> OP_SH_RM) & OP_MASK_RM;
+  int rounding = round_modes[rm];
+
+  sim_fpu sft, sft2;
+  sim_fpu sfa, sfb, sfc;
+  sim_fpu_32to (&sfa, cpu->fpregs[rs1].w[0]);
+  sim_fpu_32to (&sfb, cpu->fpregs[rs2].w[0]);
+
+  switch (op->match & mask_mul_add)
+    {
+    case MATCH_FMADD_S:
+      TRACE_INSN (cpu, "fmadd.s %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_32to (&sfc, cpu->fpregs[rs3].w[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_add (&sft, &sfc, &sft2);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    case MATCH_FMSUB_S:
+      TRACE_INSN (cpu, "fmsub.s %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_32to (&sfc, cpu->fpregs[rs3].w[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_sub (&sft, &sft2, &sfc);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    case MATCH_FNMADD_S:
+      TRACE_INSN (cpu, "fnmadd.s %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_32to (&sfc, cpu->fpregs[rs3].w[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_add (&sft, &sfc, &sft2);
+      sim_fpu_neg (&sft, &sft);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    case MATCH_FNMSUB_S:
+      TRACE_INSN (cpu, "fnmsub.s %s, %s, %s, %s",
+		  frd_name, frs1_name, frs2_name, frs3_name);
+      sim_fpu_32to (&sfc, cpu->fpregs[rs3].w[0]);
+      sim_fpu_mul (&sft2, &sfa, &sfb);
+      sim_fpu_sub (&sft, &sft2, &sfc);
+      sim_fpu_neg (&sft, &sft);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    }
+
+  switch (op->match & mask_arithmetic)
+    {
+    case MATCH_FADD_S:
+      TRACE_INSN (cpu, "fadd.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_add (&sft, &sfa, &sfb);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    case MATCH_FSUB_S:
+      TRACE_INSN (cpu, "fsub.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_sub (&sft, &sfa, &sfb);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    case MATCH_FMUL_S:
+      TRACE_INSN (cpu, "fmul.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_mul (&sft, &sfa, &sfb);
+      sim_fpu_round_64 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    case MATCH_FDIV_S:
+      TRACE_INSN (cpu, "fdiv.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_div (&sft, &sfa, &sfb);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    case MATCH_FSQRT_S:
+      TRACE_INSN (cpu, "fsqrt.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      sim_fpu_sqrt (&sft, &sfa);
+      sim_fpu_to32 (&cpu->fpregs[rd].w[0], &sft);
+      goto done;
+    }
+
+  switch (op->match & mask_convert)
+    {
+    case MATCH_FCVT_W_S:
+      TRACE_INSN (cpu, "fcvt.w.s %s, %s",
+		  rd_name, frs1_name);
+      sim_fpu_to32i (&i32, &sfa, rounding);
+      cpu->regs[rd] = i32;
+      goto done;
+    case MATCH_FCVT_WU_S:
+      TRACE_INSN (cpu, "fcvt.wu.s %s, %s",
+		  rd_name, frs1_name);
+      sim_fpu_to32u (&u32, &sfa, rounding);
+      i32 = u32;
+      cpu->regs[rd] = i32;
+      goto done;
+    case MATCH_FCVT_S_W:
+      TRACE_INSN (cpu, "fcvt.s.w %s, %s",
+		  frd_name, rs1_name);
+      sim_fpu_i32to (&sft, cpu->regs[rs1], rounding);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 ((unsigned32 *) (cpu->fpregs + rd), &sft);
+      goto done;
+    case MATCH_FCVT_S_WU:
+      TRACE_INSN (cpu, "fcvt.s.wu %s, %s",
+		  frd_name, rs1_name);
+      sim_fpu_u32to (&sft, cpu->regs[rs1], rounding);
+      sim_fpu_round_32 (&sft, rounding, sim_fpu_denorm_default);
+      sim_fpu_to32 ((unsigned32 *) (cpu->fpregs + rd), &sft);
+      goto done;
+    case MATCH_FCVT_L_S:
+      TRACE_INSN (cpu, "fcvt.l.s %s, %s",
+		  rd_name, frs1_name);
+      cpu->regs[rd] = (int64_t) cpu->fpregs[rs1].S[0];
+      goto done;
+    case MATCH_FCVT_LU_S:
+      TRACE_INSN (cpu, "fcvt.lu.s %s, %s",
+		  rd_name, frs1_name);
+      cpu->regs[rd] = (uint64_t) cpu->fpregs[rs1].S[0];
+      goto done;
+    case MATCH_FCVT_S_L:
+      TRACE_INSN (cpu, "fcvt.s.l %s, %s",
+		  frd_name, rs1_name);
+      cpu->fpregs[rd].S[0] = (float) ((int64_t) cpu->regs[rs1]);
+      goto done;
+    case MATCH_FCVT_S_LU:
+      TRACE_INSN (cpu, "fcvt.s.lu %s, %s",
+		  frd_name, rs1_name);
+      cpu->fpregs[rd].S[0] = (float) cpu->regs[rs1];
+      goto done;
+    }
+
+  switch (op->match)
+    {
+    case MATCH_FLW:
+      TRACE_INSN (cpu, "flw %s, %" PRIiTW "(%s)",
+		  frd_name, i_imm, rs1_name);
+      store_frd (cpu, rd, EXTEND32 (
+	sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
+				   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, cpu->pc, write_map,
+				  cpu->regs[rs1] + s_imm, cpu->fpregs[rs2].w[0]);
+      break;
+    case MATCH_FSGNJ_S:
+      TRACE_INSN (cpu, "fsgnj.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      u32 = cpu->fpregs[rs1].w[0] & 0x7fffffff;
+      u32 |= cpu->fpregs[rs2].w[0] & 0x80000000;
+      cpu->fpregs[rd].w[0] = u32;
+      break;
+    case MATCH_FSGNJN_S:
+      TRACE_INSN (cpu, "fsgnjn.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      u32 = cpu->fpregs[rs1].w[0] & 0x7fffffff;
+      u32 |= (cpu->fpregs[rs2].w[0] & 0x80000000) ^ 0x80000000;
+      cpu->fpregs[rd].w[0] = u32;
+      break;
+    case MATCH_FSGNJX_S:
+      TRACE_INSN (cpu, "fsgnx.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      u32 = cpu->fpregs[rs1].w[0] & 0x7fffffff;
+      u32 |= (cpu->fpregs[rs1].w[0] & 0x80000000) ^ (cpu->fpregs[rs2].w[0] & 0x80000000);
+      cpu->fpregs[rd].w[0] = u32;
+      break;
+    case MATCH_FMIN_S:
+      TRACE_INSN (cpu, "fmin.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      if (cpu->fpregs[rs1].S[0] < cpu->fpregs[rs2].S[0])
+	cpu->fpregs[rd].S[0] = cpu->fpregs[rs1].S[0];
+      else
+	cpu->fpregs[rd].S[0] = cpu->fpregs[rs2].S[0];
+      break;
+    case MATCH_FMAX_S:
+      TRACE_INSN (cpu, "fmax.s %s, %s, %s",
+		  frd_name, frs1_name, frs2_name);
+      if (cpu->fpregs[rs1].S[0] > cpu->fpregs[rs2].S[0])
+	cpu->fpregs[rd].S[0] = cpu->fpregs[rs1].S[0];
+      else
+	cpu->fpregs[rd].S[0] = cpu->fpregs[rs2].S[0];
+      break;
+    case MATCH_FMV_X_S:
+      TRACE_INSN (cpu, "fmv.x.s %s, %s",
+		  rd_name, frs1_name);
+      cpu->regs[rd] = cpu->fpregs[rs1].W[0];
+      break;
+    case MATCH_FMV_S_X:
+      TRACE_INSN (cpu, "fmv.s.x %s, %s",
+		  frd_name, rs1_name);
+      cpu->fpregs[rd].w[0] = cpu->regs[rs1];
+      break;
+    case MATCH_FEQ_S:
+      TRACE_INSN (cpu, "feq.s %s, %s, %s",
+		  rd_name, frs1_name, frs2_name);
+      cpu->regs[rd] = sim_fpu_is_eq (&sfa, &sfb);
+      break;
+    case MATCH_FLE_S:
+      TRACE_INSN (cpu, "fle.s %s, %s, %s",
+		  rd_name, frs1_name, frs2_name);
+      cpu->regs[rd] = sim_fpu_is_le (&sfa, &sfb);
+      break;
+    case MATCH_FLT_S:
+      TRACE_INSN (cpu, "flt.s %s, %s, %s",
+		  rd_name, frs1_name, frs2_name);
+      cpu->regs[rd] = sim_fpu_is_lt (&sfa, &sfb);
+      break;
+    case MATCH_FCLASS_S:
+      TRACE_INSN (cpu, "fclass.s %s, %s",
+		  rd_name, frs1_name);
+      switch (sim_fpu_is (&sfa))
+	{
+	case SIM_FPU_IS_NINF:
+	  cpu->regs[rd] = 1;
+	  break;
+	case SIM_FPU_IS_NNUMBER:
+	  cpu->regs[rd] = 1 << 1;
+	  break;
+	case SIM_FPU_IS_NDENORM:
+	  cpu->regs[rd] = 1 << 2;
+	  break;
+	case SIM_FPU_IS_NZERO:
+	  cpu->regs[rd] = 1 << 3;
+	  break;
+	case SIM_FPU_IS_PZERO:
+	  cpu->regs[rd] = 1 << 4;
+	  break;
+	case SIM_FPU_IS_PDENORM:
+	  cpu->regs[rd] = 1 << 5;
+	  break;
+	case SIM_FPU_IS_PNUMBER:
+	  cpu->regs[rd] = 1 << 6;
+	  break;
+	case SIM_FPU_IS_PINF:
+	  cpu->regs[rd] = 1 << 7;
+	  break;
+	case SIM_FPU_IS_SNAN:
+	  cpu->regs[rd] = 1 << 8;
+	  break;
+	case SIM_FPU_IS_QNAN:
+	  cpu->regs[rd] = 1 << 9;
+	  break;
+	}
+      break;
+    case MATCH_FRCSR:
+      TRACE_INSN (cpu, "frcsr %s",
+		  rd_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "fcsr", CSR_FCSR, &cpu->csr.fcsr));
+      break;
+    case MATCH_FSCSR:
+      TRACE_INSN (cpu, "fscsr %s, %sf",
+		  rd_name, rs1_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "fcsr", CSR_FCSR, &cpu->csr.fcsr));
+      store_csr (cpu, "fcsr", CSR_FCSR, &cpu->csr.fcsr, cpu->regs[rs1]);
+      break;
+    case MATCH_FRRM:
+      TRACE_INSN (cpu, "frrm %s",
+		  rd_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "frm", CSR_FRM, &cpu->csr.frm));
+      break;
+    case MATCH_FSRM:
+      TRACE_INSN (cpu, "fsrm %s, %s",
+		  rd_name, rs1_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "frm", CSR_FCSR, &cpu->csr.frm));
+      store_csr (cpu, "frm", CSR_FCSR, &cpu->csr.frm, cpu->regs[rs1]);
+      break;
+    case MATCH_FRFLAGS:
+      TRACE_INSN (cpu, "frflags %s",
+		  rd_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "fflags", CSR_FFLAGS, &cpu->csr.fflags));
+      break;
+    case MATCH_FSFLAGS:
+      TRACE_INSN (cpu, "fsflags %s, %s",
+		  rd_name, frs1_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "fflags", CSR_FFLAGS, &cpu->csr.fflags));
+      store_csr (cpu, "fflags", CSR_FFLAGS, &cpu->csr.fflags, cpu->regs[rs1]);
+      break;
+    default:
+      TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+      sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+    }
+
+ done:
+  return pc;
+}
+
+static sim_cia
 execute_i (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
 {
   SIM_DESC sd = CPU_STATE (cpu);
@@ -960,6 +1618,10 @@ execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
       return execute_i (cpu, iw, op);
     case INSN_CLASS_M:
       return execute_m (cpu, iw, op);
+    case INSN_CLASS_D:
+      return execute_d (cpu, iw, op);
+    case INSN_CLASS_F:
+      return execute_f (cpu, iw, op);
     case INSN_CLASS_ZIFENCEI:
       return execute_zifencei (cpu, iw, op);
     default:
diff --git a/sim/riscv/sim-main.h b/sim/riscv/sim-main.h
index 4a1b31e..e53794f 100644
--- a/sim/riscv/sim-main.h
+++ b/sim/riscv/sim-main.h
@@ -25,6 +25,19 @@
 #include "machs.h"
 #include "sim-base.h"
 
+typedef union FRegisterValue
+{
+  uint64_t     v[2];
+  uint32_t     w[4];
+
+  int64_t      V[2];
+  int32_t      W[4];
+
+  float        S[4];
+  double       D[2];
+
+} FRegister;
+
 struct _sim_cpu {
   union {
     unsigned_word regs[32];
@@ -39,7 +52,7 @@ struct _sim_cpu {
     };
   };
   union {
-    unsigned_word fpregs[32];
+    FRegister fpregs[32];
     struct {
       /* These are the ABI names.  */
       unsigned_word ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7;
-- 
2.7.4



More information about the Gdb-patches mailing list