From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 8Ev1D/che2CaOgAAWB0awg (envelope-from ) for ; Sat, 17 Apr 2021 13:59:19 -0400 Received: by simark.ca (Postfix, from userid 112) id 3DD501F108; Sat, 17 Apr 2021 13:59:19 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 8A5FD1F104 for ; Sat, 17 Apr 2021 13:59:14 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4EF9B3898527; Sat, 17 Apr 2021 17:59:14 +0000 (GMT) Received: from mail-pj1-x1031.google.com (mail-pj1-x1031.google.com [IPv6:2607:f8b0:4864:20::1031]) by sourceware.org (Postfix) with ESMTPS id A72BA3896C19 for ; Sat, 17 Apr 2021 17:59:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A72BA3896C19 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=sifive.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=jimw@sifive.com Received: by mail-pj1-x1031.google.com with SMTP id cu16so13678406pjb.4 for ; Sat, 17 Apr 2021 10:59:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ntQdsuN8+wVOFsmP6AqKktOexjCV6UKzOtR0San8nrA=; b=JBhxF99devWM7eWOVVsFIeU0P60P07zvgN/LrXbF6iQ8H9jKtB1dX6Z30NrP5l2mbx 4OVNZaHQRnEbouomteeLb/uKsPiFDcSzFSL57Ea+UHBEDmdKJuti4cjndyTlMbjHEou4 DoDSWunfcvPdpKLHiwTRDg0ht0XshjwPlo47Nc1dDYfeB6ki/KxWt/0b348d64i79Cee ampGVPiatBSPP8kmQWum0/dXWN29MbIhQzbdEE3UfgnCQPS0Vt3Hile0vj/6840fxsb7 Oy7u9AFm978VPko5gb/7PB1uGSPEhAhcEUQIWb+6xUXHM9Ux5zOk35jGhttruXkY9B3Q 1RHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ntQdsuN8+wVOFsmP6AqKktOexjCV6UKzOtR0San8nrA=; b=tUIE00SN8AnAVHQKGJ630C1XbceGeRCPzZTnjGayR5OI2/tjEJ1S0DKY4/JyKmjQPk vXUF8BPhbqgwDZAMMnW0Ab0vpofy8MOyNm2ZPpZHuJsCWog9e1h8ZHdDQ1DBtJOYZRa+ igSgwG5CRF6WW9wp8W/omyLZmKmdENaSSd/FcORtMSZ1L83Em7Yc/MaZ8jHALCW56Ibx wNO71wi73+6ykj+SxSZMsGEvBiHKzVzgSM2+pgqinSLR6r/cM1KYrnM/ziOoAxt3N624 O1gAdfEHPNQITIBVt9bn7p5AmyocGgTmQOsZYuRp6N0n73Th1f/atNadFdsqxSczT2gV OW8g== X-Gm-Message-State: AOAM531yOCjO31ZiAnCJ9upXTnDq29ucwTM16jfmi+dKfJCCxsnBQgzi pmCiFfP5LOMuJmZmm31ypguYCZAcMwzaHw== X-Google-Smtp-Source: ABdhPJyvyESVb2jdiWKjiNUg0Of939LuzZ0byB8E1T/fic9AdDCGPyS/WQ3n9ujnDL5Xp6Y7fDsoiw== X-Received: by 2002:a17:90a:5d93:: with SMTP id t19mr16078934pji.211.1618682344283; Sat, 17 Apr 2021 10:59:04 -0700 (PDT) Received: from rohan.hsd1.ca.comcast.net ([2601:646:c180:b150:1820:3ed4:975:3fbe]) by smtp.gmail.com with ESMTPSA id u4sm5030705pfk.56.2021.04.17.10.59.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 17 Apr 2021 10:59:03 -0700 (PDT) From: Jim Wilson To: gdb-patches@sourceware.org Subject: [PATCH 06/24] RISC-V: Add fp support. Date: Sat, 17 Apr 2021 10:58:13 -0700 Message-Id: <20210417175831.16413-7-jimw@sifive.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210417175831.16413-1-jimw@sifive.com> References: <20210417175831.16413-1-jimw@sifive.com> X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Monk Chiang Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" From: Monk Chiang 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 #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