summaryrefslogtreecommitdiff
path: root/riscv.c
diff options
context:
space:
mode:
authorJiri Gaisler <jiri@gaisler.se>2019-03-22 10:00:07 +0100
committerJiri Gaisler <jiri@gaisler.se>2019-05-14 22:26:21 +0200
commit865b177d0e2fd534270ef158030e7c3056a930e3 (patch)
tree4edbf27496977adaed90287d11eaffbe357ac757 /riscv.c
Standalone sis - initial commit
Diffstat (limited to 'riscv.c')
-rw-r--r--riscv.c3201
1 files changed, 3201 insertions, 0 deletions
diff --git a/riscv.c b/riscv.c
new file mode 100644
index 0000000..c21d625
--- /dev/null
+++ b/riscv.c
@@ -0,0 +1,3201 @@
+/* This file is part of SIS (SPARC/RISCV instruction simulator)
+
+ Copyright (C) 1995-2019 Free Software Foundation, Inc.
+ Contributed by Jiri Gaisler, Sweden.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "riscv.h"
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+static int
+set_csr (address, sregs, value)
+ uint32 address;
+ struct pstate *sregs;
+ uint32 value;
+{
+ switch (address)
+ {
+ case CSR_MSTATUS:
+ sregs->mstatus = value & MSTATUS_MASK;
+ break;
+ case CSR_MTVEC:
+ sregs->mtvec = value;
+ break;
+ case CSR_MEPC:
+ sregs->epc = value;
+ break;
+ case CSR_MIE:
+ sregs->mie = value;
+ break;
+ case CSR_MIP:
+ sregs->mip = value;
+ break;
+ case CSR_MSCRATCH:
+ sregs->mscratch = value;
+ break;
+ case CSR_MCAUSE:
+ sregs->mcause = value;
+ break;
+ case CSR_FFLAGS:
+ sregs->fsr = (sregs->fsr & ~0x1f) | value;
+ break;
+ case CSR_FRM:
+ sregs->fsr = (sregs->fsr & ~0xc0) | (value << 5);
+ break;
+ case CSR_FCSR:
+ sregs->fsr = value;
+ break;
+ default:
+ return 1;
+ }
+ if (sis_verbose > 1)
+ printf (" %8" PRIu64 " set csr 0x%03X : %08X\n",
+ sregs->simtime, address, value);
+ return 0;
+}
+
+int
+get_csr (address, sregs)
+ uint32 address;
+ struct pstate *sregs;
+{
+ switch (address)
+ {
+ case CSR_MSTATUS:
+ return (sregs->mstatus);
+ break;
+ case CSR_MCAUSE:
+ return (sregs->mcause);
+ break;
+ case CSR_MTVEC:
+ return (sregs->mtvec);
+ break;
+ case CSR_MEPC:
+ return (sregs->epc);
+ break;
+ case CSR_MIP:
+ if (ext_irl[sregs->cpu])
+ return (sregs->mip | MIP_MEIP);
+ else
+ return (sregs->mip);
+ break;
+ case CSR_MIE:
+ return (sregs->mie);
+ break;
+ case CSR_MTVAL:
+ return (sregs->mtval);
+ break;
+ case CSR_MISA:
+ return (0x40000100);
+ break;
+ case CSR_TIME:
+ return (sregs->simtime & 0xffffffff);
+ break;
+ case CSR_TIMEH:
+ return ((sregs->simtime >> 32) & 0xffffffff);
+ break;
+ case CSR_MHARTID:
+ return (sregs->cpu);
+ break;
+ case CSR_MSCRATCH:
+ return (sregs->mscratch);
+ break;
+ case CSR_FFLAGS:
+ return (sregs->fsr & 0x1f);
+ break;
+ case CSR_FRM:
+ return ((sregs->fsr >> 5) & 0x7);
+ break;
+ case CSR_FCSR:
+ return (sregs->fsr);
+ break;
+ default:
+ return 0;
+ }
+}
+
+static int
+riscv_dispatch_instruction (sregs)
+ struct pstate *sregs;
+{
+
+ uint32 op1, op2, op3, rd, rs1, rs2, npc, btrue, inst;
+ int32 sop1, sop2, *wdata, result, offset;
+ int32 pc, data, address, ws, mexc, fcc;
+ unsigned char op, funct3, funct5, rs1p, rs2p, funct2, frs1, frs2, frd;
+ int64 sop64a, sop64b;
+ uint64 op64a, op64b;
+
+ sregs->ninst++;
+
+#ifdef C_EXTENSION
+ if ((sregs->inst & 3) != 3)
+ {
+ /* Compressed instructions (RV32C) */
+ npc = sregs->pc + 2;
+ funct3 = (sregs->inst >> 13) & 7;
+ rs1p = ((sregs->inst >> 7) & 7) | 8;
+ rs2p = ((sregs->inst >> 2) & 7) | 8;
+ rs1 = ((sregs->inst >> 7) & 0x1f);
+ rs2 = ((sregs->inst >> 2) & 0x1f);
+ switch (sregs->inst & 3)
+ {
+ case 0:
+ address =
+ (int32) sregs->g[rs1p] + (int32) EXTRACT_RVC_LW_IMM (sregs->inst);
+ switch (funct3)
+ {
+ case CADDI4SPN: /* addi rd', x2, nzuimm[9:2] */
+ if ((sregs->inst & 0x0ffff) == 0)
+ {
+ sregs->trap = TRAP_ILLEG;
+ break;
+ }
+ sregs->g[rs2p] =
+ (int32) sregs->g[2] +
+ (int32) EXTRACT_RVC_ADDI4SPN_IMM (sregs->inst);
+ break;
+ case CLW: /* lw rd', offset[6:2](rs1') */
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->g[rs2p] = data;
+ }
+ break;
+ case CSW: /* sw rs2', offset[6:2](rs1') */
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_write (address, &sregs->g[rs2p], 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+ case CFLW: /* lw rd', offset[6:2](rs1') */
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->fsi[rs2p << 1] = data;
+#ifdef FPU_D_ENABLED
+ sregs->fsi[(rs2p << 1) + 1] = -1;
+#endif
+ }
+ break;
+#ifdef FPU_D_ENABLED
+ case CFLD: /* ld frd', offset[7:3](rs1') */
+ address = (int32) sregs->g[rs1p] +
+ (int32) EXTRACT_RVC_LD_IMM (sregs->inst);
+ if (address & LDDM)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ mexc |= ms->memory_read (address + 4, &result, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->fsi[rs2p << 1] = data;
+ sregs->fsi[(rs2p << 1) + 1] = result;
+ }
+ break;
+#endif
+ case CFSW: /* sw rs2', offset[6:2](rs1') */
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc =
+ ms->memory_write (address, &sregs->fsi[rs2p << 1], 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+#ifdef FPU_D_ENABLED
+ case CFSD: /* sd frs2', offset[7:3](rs1') */
+ address = (int32) sregs->g[rs1p] +
+ (int32) EXTRACT_RVC_LD_IMM (sregs->inst);
+ if (address & LDDM)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc =
+ ms->memory_write (address, &sregs->fsi[rs2p << 1], 3, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+#endif
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 1:
+ switch (funct3)
+ {
+ case CADDI: /* addi rd, rd, nzimm[5:0] */
+ sop1 = sregs->g[rs1];
+ sop2 = EXTRACT_RVC_IMM (sregs->inst);
+ sregs->g[rs1] = sop1 + sop2;
+ break;
+ case CLI: /* addi rd, x0, imm[5:0] */
+ sregs->g[rs1] = EXTRACT_RVC_IMM (sregs->inst);
+ break;
+ case CJAL: /* jal x1, offset[11:1] */
+ case CJNL: /* jal x0, offset[11:1] */
+#ifdef STAT
+ sregs->nbranch++;
+#endif
+ offset = EXTRACT_RVC_J_IMM (sregs->inst);
+ if (funct3 == CJAL)
+ sregs->g[1] = npc;
+ npc = sregs->pc + offset;
+ npc &= ~1;
+ if (!npc)
+ sregs->trap = NULL_TRAP; // halt on null pointer
+ if (ebase.coven)
+ cov_jmp (sregs->pc, npc);
+ break;
+ case CADDI16SP: /* addi x2, x2, nzimm[9:4] */
+ if (rs1 == 2)
+ {
+ sop1 = sregs->g[rs1];
+ sop2 = EXTRACT_RVC_ADDI16SP_IMM (sregs->inst);
+ sregs->g[rs1] = sop1 + sop2;
+ }
+ else
+ { /* CLUI: lui rd, nzuimm[17:12 */
+ sregs->g[rs1] = EXTRACT_RVC_LUI_IMM (sregs->inst);
+ }
+ break;
+ case CARITH:
+ sop2 = EXTRACT_RVC_IMM (sregs->inst);
+ switch ((sregs->inst >> 10) & 7)
+ {
+ case 0: /* srli rd', rd', shamt[5:0] */
+ op1 = sregs->g[rs1p];
+ sregs->g[rs1p] = op1 >> sop2; /* SRL */
+ break;
+ case 1: /* srai rd', rd', shamt[5:0] */
+ sop1 = sregs->g[rs1p];
+ sregs->g[rs1p] = sop1 >> sop2; /* SRA */
+ break;
+ case 2:
+ case 6: /* andi rd', rd', imm[5:0] */
+ sregs->g[rs1p] &= sop2; /* ANDI */
+ break;
+ case 3:
+ switch ((sregs->inst >> 5) & 3)
+ {
+ case 0: /* sub rd', rd', rs2' */
+ sregs->g[rs1p] -= sregs->g[rs2p]; /* SUB */
+ break;
+ case 1: /* xor rd', rd', rs2' */
+ sregs->g[rs1p] ^= sregs->g[rs2p]; /* XOR */
+ break;
+ case 2: /* or rd', rd', rs2' */
+ sregs->g[rs1p] |= sregs->g[rs2p]; /* OR */
+ break;
+ case 3: /* and rd', rd', rs2' */
+ sregs->g[rs1p] &= sregs->g[rs2p]; /* AND */
+ break;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case CBEQZ: /* beq rs1', x0, offset[8:1] */
+ offset = EXTRACT_RVC_B_IMM (sregs->inst);
+ if (!sregs->g[rs1p])
+ {
+ npc = sregs->pc + offset;
+ if (offset >= 0)
+ sregs->icnt += T_BMISS;
+ if (ebase.coven)
+ cov_bt (sregs->pc, npc);
+ }
+ else
+ {
+ if (offset < 0)
+ sregs->icnt += T_BMISS;
+ if (ebase.coven)
+ {
+ cov_bnt (sregs->pc);
+ cov_start (npc);
+ }
+ }
+ npc &= ~1;
+ break;
+ case CBNEZ: /* bne rs1', x0, offset[8:1] */
+ offset = EXTRACT_RVC_B_IMM (sregs->inst);
+ if (sregs->g[rs1p])
+ {
+ npc = sregs->pc + offset;
+ if (offset >= 0)
+ sregs->icnt += T_BMISS;
+ if (ebase.coven)
+ cov_bt (sregs->pc, npc);
+ }
+ else
+ {
+ if (offset < 0)
+ sregs->icnt += T_BMISS;
+ if (ebase.coven)
+ {
+ cov_bnt (sregs->pc);
+ cov_start (npc);
+ }
+ }
+ npc &= ~1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 2:
+ switch (funct3)
+ {
+ case 0: /* slli rd', rd', shamt[5:0] */
+ sop2 = EXTRACT_RVC_IMM (sregs->inst);
+ sregs->g[rs1] <<= sop2; /* SLL */
+ break;
+ case 2: /* LWSP: lw rd, offset[7:2](x2) */
+ address = sregs->g[2] + EXTRACT_RVC_LWSP_IMM (sregs->inst);
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->g[rs1] = data;
+ }
+ break;
+#ifdef FPU_D_ENABLED
+ case 1: /* FLDSP: ld frd, offset[8:3](x2) */
+ address = sregs->g[2] + EXTRACT_RVC_LDSP_IMM (sregs->inst);
+ if (address & LDDM)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (!mexc)
+ mexc = ms->memory_read (address + 4, &result, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->fsi[rs1 << 1] = data;
+ sregs->fsi[(rs1 << 1) + 1] = result;
+ }
+ break;
+#endif
+ case 3: /* FLWSP: lw frd, offset[7:2](x2) */
+ address = sregs->g[2] + EXTRACT_RVC_LWSP_IMM (sregs->inst);
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->fsi[rs1 << 1] = data;
+ }
+ break;
+ case 4:
+ if ((sregs->inst >> 12) & 1)
+ {
+ if (rs1)
+ {
+ if (rs2)
+ { /* add rd, rd, rs2 */
+ sregs->g[rs1] =
+ (int32) sregs->g[rs1] + (int32) sregs->g[rs2];
+ }
+ else
+ { /* jalr x1, rs1, 0 */
+#ifdef STAT
+ sregs->nbranch++;
+#endif
+ sregs->g[1] = npc;
+ npc = sregs->g[rs1];
+ npc &= ~1;
+ if (ebase.coven)
+ cov_jmp (sregs->pc, npc);
+ }
+ }
+ else
+ { /* EBREAK */
+ if (sis_gdb_break)
+ {
+ sregs->trap = WPT_TRAP;
+ sregs->bphit = 1;
+ }
+ else
+ sregs->trap = TRAP_EBREAK;
+ }
+ }
+ else
+ {
+ if (rs2)
+ { /* MV */
+ sregs->g[rs1] = sregs->g[rs2];
+ }
+ else
+ { /* jalr x0, rs1, 0 */
+ npc = sregs->g[rs1];
+ npc &= ~1;
+ if (ebase.coven)
+ cov_jmp (sregs->pc, npc);
+ }
+ }
+ break;
+ case 6: /* SWSP: sw rs2, offset[7:2](x2) */
+ address = sregs->g[2] + EXTRACT_RVC_SWSP_IMM (sregs->inst);
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_write (address, &sregs->g[rs2], 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+#ifdef FPU_D_ENABLED
+ case 5: /* FSDSP: sw frs2, offset[8:3](x2) */
+ address = sregs->g[2] + EXTRACT_RVC_SDSP_IMM (sregs->inst);
+ if (address & LDDM)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc =
+ ms->memory_write (address, &sregs->fsi[rs2 << 1], 3, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+#endif
+ case 7: /* FSWSP: sw frs2, offset[7:2](x2) */
+ address = sregs->g[2] + EXTRACT_RVC_SWSP_IMM (sregs->inst);
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc =
+ ms->memory_write (address, &sregs->fsi[rs2 << 1], 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ }
+ else
+#else
+ if (1)
+#endif
+ {
+ /* Regular instructions (RV32IA) */
+ op = (sregs->inst >> 2) & 0x1f;
+ funct3 = (sregs->inst >> 12) & 0x7;
+ rd = (sregs->inst >> 7) & 0x1f;
+ rs1 = (sregs->inst >> 15) & 0x1f;
+ rs2 = (sregs->inst >> 20) & 0x1f;
+ npc = sregs->pc + 4;
+
+ op1 = sregs->g[rs1];
+ op2 = sregs->g[rs2];
+
+ switch (op)
+ {
+ case OP_LUI:
+ sop1 = sregs->inst;
+ sregs->g[rd] = ((sop1 >> 12) << 12);
+ break;
+ case OP_BRANCH:
+#ifdef STAT
+ sregs->nbranch++;
+#endif
+ btrue = 0;
+ offset = EXTRACT_SBTYPE_IMM (sregs->inst);
+ sop1 = op1;
+ sop2 = op2;
+ switch (funct3)
+ {
+ case B_BE:
+ if (op1 == op2)
+ btrue = 1;
+ break;
+ case B_BNE:
+ if (op1 != op2)
+ btrue = 1;
+ break;
+ case B_BGE:
+ if (sop1 >= sop2)
+ btrue = 1;
+ break;
+ case B_BGEU:
+ if (op1 >= op2)
+ btrue = 1;
+ break;
+ case B_BLT:
+ if (sop1 < sop2)
+ btrue = 1;
+ break;
+ case B_BLTU:
+ if (op1 < op2)
+ btrue = 1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ if (btrue)
+ {
+ npc = sregs->pc + offset;
+ if (ebase.coven)
+ cov_bt (sregs->pc, npc);
+ if (offset >= 0)
+ sregs->icnt += T_BMISS;
+ }
+ else
+ {
+ if (offset < 0)
+ sregs->icnt += T_BMISS;
+ if (ebase.coven)
+ {
+ cov_bnt (sregs->pc);
+ cov_start (npc);
+ }
+ }
+ npc &= ~1;
+ break;
+ case OP_JAL: /* JAL */
+#ifdef STAT
+ sregs->nbranch++;
+#endif
+ offset = EXTRACT_UJTYPE_IMM (sregs->inst);
+ sregs->g[rd] = npc;
+ npc = sregs->pc + offset;
+ npc &= ~1;
+ if (!npc)
+ sregs->trap = NULL_TRAP; // halt on null pointer
+ if (ebase.coven)
+ cov_jmp (sregs->pc, npc);
+ break;
+
+ case OP_JALR: /* JALR */
+#ifdef STAT
+ sregs->nbranch++;
+#endif
+ offset = EXTRACT_ITYPE_IMM (sregs->inst);
+ sregs->g[rd] = npc;
+ npc = op1 + offset;
+ npc &= ~1;
+ if (!npc)
+ sregs->trap = NULL_TRAP; // halt on null pointer
+ if (ebase.coven)
+ cov_jmp (sregs->pc, npc);
+ sregs->icnt += T_JALR;
+ break;
+
+ case OP_AUIPC: /* AUIPC */
+ sop1 = sregs->inst;
+ sop1 = ((sop1 >> 12) << 12);
+ sregs->g[rd] = sregs->pc + sop1;
+ break;
+ case OP_IMM: /* IMM */
+ sop2 = EXTRACT_ITYPE_IMM (sregs->inst);
+ switch (funct3)
+ {
+ case IXOR:
+ sregs->g[rd] = op1 ^ sop2;
+ break;
+ case IOR:
+ sregs->g[rd] = op1 | sop2;
+ break;
+ case IAND:
+ sregs->g[rd] = op1 & sop2;
+ break;
+ case ADD:
+ sop1 = op1;
+ sregs->g[rd] = sop1 + sop2;
+ break;
+ case SLL:
+ sregs->g[rd] = op1 << (rs2);
+ break;
+ case SRL:
+ if ((sregs->inst >> 30) & 1)
+ {
+ sop1 = op1;
+ sregs->g[rd] = sop1 >> rs2; /* SRA */
+ }
+ else
+ sregs->g[rd] = op1 >> rs2; /* SRL */
+ break;
+ case SLT:
+ sop1 = op1;
+ if (sop1 < sop2)
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ case SLTU:
+ op2 = sop2;
+ if (op1 < op2)
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case OP_REG: /* REG */
+ switch ((sregs->inst >> 25) & 3)
+ {
+ case 0:
+ switch (funct3)
+ {
+ case IXOR:
+ sregs->g[rd] = op1 ^ op2;
+ break;
+ case IOR:
+ sregs->g[rd] = op1 | op2;
+ break;
+ case IAND:
+ sregs->g[rd] = op1 & op2;
+ break;
+ case ADD:
+ sop1 = op1;
+ sop2 = op2;
+ if ((sregs->inst >> 30) & 1)
+ sregs->g[rd] = op1 - op2;
+ else
+ sregs->g[rd] = op1 + op2;
+ break;
+ case SLL:
+ sregs->g[rd] = op1 << (op2 & 0x1f);
+ break;
+ case SRL:
+ if ((sregs->inst >> 30) & 1)
+ {
+ sop1 = op1;
+ sregs->g[rd] = sop1 >> (op2 & 0x1f); /* SRA */
+ }
+ else
+ sregs->g[rd] = op1 >> (op2 & 0x1f); /* SRL */
+ break;
+ case SLT:
+ sop1 = op1;
+ sop2 = op2;
+ if (sop1 < sop2)
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ case SLTU:
+ if (op1 < op2)
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 1: /* MUL/DIV */
+ switch (funct3)
+ {
+ case 0: /* MUL */
+ sop1 = op1;
+ sop2 = op2;
+ sop2 = op1 * op2;
+ sregs->g[rd] = sop2;
+ break;
+ case 1: /* MULH */
+ sop64a = (int64) op1 *(int64) op2;
+ sregs->g[rd] = (sop64a >> 32) & 0xffffffff;
+ break;
+ case 2: /* MULHSU */
+ sop64a = (int64) op1 *(uint64) op2;
+ sregs->g[rd] = (sop64a >> 32) & 0xffffffff;
+ break;
+ case 3: /* MULHU */
+ op64a = (uint64) op1 *(uint64) op2;
+ sregs->g[rd] = (op64a >> 32) & 0xffffffff;
+ break;
+ case 4: /* DIV */
+ sop1 = op1;
+ sop2 = op2;
+ result = sop1 / sop2;
+ sregs->g[rd] = result;
+ break;
+ case 5: /* DIVU */
+ sregs->g[rd] = op1 / op2;
+ break;
+ case 6: /* REM */
+ sop1 = op1;
+ sop2 = op2;
+ sop1 = sop1 % sop2;
+ sregs->g[rd] = sop1;
+ break;
+ case 7: /* REMU */
+ sregs->g[rd] = op1 % op2;
+ break;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case OP_STORE: /* store instructions */
+
+#ifdef STAT
+ sregs->nstore++;
+#endif
+ offset = EXTRACT_STYPE_IMM (sregs->inst);
+ address = op1 + offset;
+ wdata = &(sregs->g[rs2]);
+
+ if (ebase.wpwnum)
+ {
+ if (ebase.wphit = check_wpw (sregs, address, funct3 & 3))
+ {
+ sregs->trap = WPT_TRAP;
+ break;
+ }
+ }
+
+ switch (funct3)
+ {
+ case SW:
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_write (address, wdata, 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+ case SB:
+ mexc = ms->memory_write (address, wdata, 0, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+ case SH:
+ if (address & 0x1)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_write (address, wdata, 1, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case OP_FSW: /* F store instructions */
+
+#ifdef STAT
+ sregs->nstore++;
+#endif
+ offset = EXTRACT_STYPE_IMM (sregs->inst);
+ address = op1 + offset;
+ wdata = &sregs->fsi[rs2 << 1];
+
+ if (ebase.wpwnum)
+ {
+ if (ebase.wphit = check_wpw (sregs, address, funct3 & 3))
+ {
+ sregs->trap = WPT_TRAP;
+ break;
+ }
+ }
+
+ switch (funct3)
+ {
+ case 2: /* FSW */
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_write (address, wdata, 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+ case 3: /* FSD */
+ if (address & LDDM)
+ {
+ sregs->trap = TRAP_SMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_write (address, wdata, 3, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case OP_LOAD: /* load instructions */
+#ifdef STAT
+ sregs->nload++;
+#endif
+ offset = EXTRACT_ITYPE_IMM (sregs->inst);
+ address = op1 + offset;
+ if (ebase.wprnum)
+ {
+ if (ebase.wphit = check_wpr (sregs, address, funct3 & 3))
+ {
+ sregs->trap = WPT_TRAP;
+ break;
+ }
+ }
+
+
+ /* Decode load/store instructions */
+
+ switch (funct3)
+ {
+ case LW:
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->g[rd] = data;
+ }
+ break;
+ case LB:
+ if (sregs->inst == 0)
+ {
+ sregs->trap = TRAP_ILLEG;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ break;
+ }
+ data = (data << 24) >> 24;
+ sregs->g[rd] = data;
+ break;
+ case LBU:
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ break;
+ }
+ sregs->g[rd] = data & 0x0ff;
+ break;
+ case LH:
+ if (address & 0x1)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ break;
+ }
+ data = (data << 16) >> 16;
+ sregs->g[rd] = data;
+ break;
+ case LHU:
+ if (address & 0x1)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ break;
+ }
+ data &= 0x0ffff;
+ sregs->g[rd] = data;
+ break;
+
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case OP_AMO: /* atomic instructions */
+ address = op1;
+ funct5 = (sregs->inst >> 27) & 0x1f;
+#ifdef STAT
+ sregs->nstore++;
+ sregs->nload++;
+#endif
+ switch (funct5)
+ {
+ case LRQ:
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->g[rd] = data;
+ sregs->lrqa = address;
+ sregs->lrq = 1;
+#ifdef DEBUG
+ if (sis_verbose)
+ printf (" %8" PRIu64 " cpu %d: LRQ at address 0x%08x\n",
+ sregs->simtime, sregs->cpu, address);
+#endif
+ }
+ break;
+ case SCQ:
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ if (sregs->lrq && (sregs->lrqa == address))
+ {
+ mexc = ms->memory_write (address, &op2, 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->g[rd] = 0;
+#ifdef DEBUG
+ if (sis_verbose)
+ printf (" %8" PRIu64
+ " cpu %d: SCQ at address 0x%08x\n",
+ sregs->simtime, sregs->cpu, address);
+#endif
+ }
+ }
+ else
+ {
+ sregs->g[rd] = 1;
+#ifdef DEBUG
+ if (sis_verbose)
+ printf (" %8" PRIu64
+ " cpu %d: failed SCQ at address 0x%08x\n",
+ sregs->simtime, sregs->cpu, address);
+#endif
+ }
+ sregs->lrq = 0;
+ break;
+ default: /* AMOXXX */
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ break;
+ }
+ switch (funct5)
+ {
+ case AMOSWAP:
+ break;
+ case AMOADD:
+ op2 = (int32) data + (int32) op2;
+ break;
+ case AMOXOR:
+ op2 = data ^ op2;
+ break;
+ case AMOOR:
+ op2 = data | op2;
+ break;
+ case AMOAND:
+ op2 = data & op2;
+ break;
+ case AMOMIN:
+ if ((int32) data < (int32) op2)
+ op2 = data;
+ break;
+ case AMOMAX:
+ if ((int32) data > (int32) op2)
+ op2 = data;
+ break;
+ case AMOMINU:
+ if ((uint32) data < (uint32) op2)
+ op2 = data;
+ break;
+ case AMOMAXU:
+ if ((uint32) data > (uint32) op2)
+ op2 = data;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ if (sregs->trap)
+ break;
+ mexc = ms->memory_write (address, &op2, 2, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_SEXC;
+ sregs->wpaddress = address;
+ break;
+ }
+ sregs->g[rd] = data;
+ }
+ break;
+ case OP_SYS:
+ address = sregs->inst >> 20;
+ switch (funct3)
+ {
+ case 0: /* ecall, xret */
+ switch (rs2)
+ {
+ case 0: /* ecall */
+ sregs->trap = ERROR_TRAP;
+ break;
+ case 1: /* ebreak */
+ if (sis_gdb_break)
+ {
+ sregs->trap = WPT_TRAP;
+ sregs->bphit = 1;
+ }
+ else
+ sregs->trap = TRAP_EBREAK;
+ break;
+ case 2: /* xret */
+ npc = sregs->epc;
+ sregs->mode = sregs->mpp;
+ sregs->mstatus |= (sregs->mstatus >> 4) & MSTATUS_MIE;
+ sregs->mstatus |= MSTATUS_MPIE; // set mstatus.mpie
+ if (ebase.coven)
+ cov_jmp (sregs->pc, npc);
+ break;
+ case 5: /* wfi */
+ pwd_enter (sregs);
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case CSRRW:
+ op2 = get_csr (address, sregs);
+ if (set_csr (address, sregs, op1))
+ sregs->trap = TRAP_ILLEG;
+ else
+ sregs->g[rd] = op2;
+ break;
+ case CSRRS:
+ op2 = get_csr (address, sregs);
+ if ((rs1) && set_csr (address, sregs, op1 | op2))
+ sregs->trap = TRAP_ILLEG;
+ if (!sregs->trap)
+ sregs->g[rd] = op2;
+ break;
+ case CSRRC:
+ op2 = get_csr (address, sregs);
+ if ((rs1) && set_csr (address, sregs, ~op1 & op2))
+ sregs->trap = TRAP_ILLEG;
+ if (!sregs->trap)
+ sregs->g[rd] = op2;
+ break;
+ case CSRRWI:
+ op2 = get_csr (address, sregs);
+ op1 = (sregs->inst >> 15) & 0x1f;
+ if (set_csr (address, sregs, op1))
+ sregs->trap = TRAP_ILLEG;
+ else
+ sregs->g[rd] = op2;
+ break;
+ case CSRRSI:
+ op2 = get_csr (address, sregs);
+ op1 = (sregs->inst >> 15) & 0x1f;
+ if ((rs1) && set_csr (address, sregs, op1 | op2))
+ sregs->trap = TRAP_ILLEG;
+ if (!sregs->trap)
+ sregs->g[rd] = op2;
+ break;
+ case CSRRCI:
+ op2 = get_csr (address, sregs);
+ op1 = (sregs->inst >> 15) & 0x1f;
+ if ((rs1) && set_csr (address, sregs, ~op1 & op2))
+ sregs->trap = TRAP_ILLEG;
+ if (!sregs->trap)
+ sregs->g[rd] = op2;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case OP_FLOAD: /* float load instructions */
+#ifdef STAT
+ sregs->nload++;
+#endif
+ offset = EXTRACT_ITYPE_IMM (sregs->inst);
+ address = op1 + offset;
+ if (ebase.wprnum)
+ {
+ if (ebase.wphit = check_wpr (sregs, address, funct3 & 3))
+ {
+ sregs->trap = WPT_TRAP;
+ break;
+ }
+ }
+
+
+ /* Decode load/store instructions */
+
+ switch (funct3)
+ {
+ case LW:
+ if (address & 0x3)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->fsi[rd << 1] = data;
+ sregs->fsi[(rd << 1) + 1] = -1;
+ }
+ break;
+ case LD:
+ if (address & LDDM)
+ {
+ sregs->trap = TRAP_LMALI;
+ sregs->wpaddress = address;
+ break;
+ }
+ mexc = ms->memory_read (address, &data, &ws);
+ sregs->hold += ws;
+ if (!mexc)
+ mexc = ms->memory_read (address + 4, &result, &ws);
+ sregs->hold += ws;
+ if (mexc)
+ {
+ sregs->trap = TRAP_LEXC;
+ sregs->wpaddress = address;
+ }
+ else
+ {
+ sregs->fsi[rd << 1] = data;
+ sregs->fsi[(rd << 1) + 1] = result;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+#ifdef FPU_ENABLED
+ case OP_FPU:
+ sregs->finst++;
+ clear_accex ();
+ funct2 = (sregs->inst >> 25) & 3;
+ funct5 = (sregs->inst >> 27);
+ switch (funct2)
+ {
+ case 0: /* single-precision ops */
+ frs1 = rs1 << 1;
+ frs2 = rs2 << 1;
+ frd = rd << 1;
+ switch (funct5)
+ {
+ case 0: /* FADDS */
+ sregs->fs[frd] = sregs->fs[frs1] + sregs->fs[frs2];
+ sregs->fsi[frd + 1] = -1;
+ sregs->fhold += T_FADDs;
+ break;
+ case 1: /* FSUBS */
+ sregs->fs[frd] = sregs->fs[frs1] - sregs->fs[frs2];
+ sregs->fsi[frd + 1] = -1;
+ sregs->fhold += T_FSUBs;
+ break;
+ case 2: /* FMULS */
+ sregs->fs[frd] = sregs->fs[frs1] * sregs->fs[frs2];
+ sregs->fsi[frd + 1] = -1;
+ sregs->fhold += T_FMULs;
+ break;
+ case 3: /* FDIVS */
+ sregs->fs[frd] = sregs->fs[frs1] / sregs->fs[frs2];
+ sregs->fsi[frd + 1] = -1;
+ sregs->fhold += T_FDIVs;
+ break;
+ case 4: /* FSGX */
+ switch (funct3)
+ {
+ case 0: /* FSGNJ */
+ sregs->fsi[frd] = (sregs->fsi[frs1] & 0x7fffffff) |
+ (sregs->fsi[frs2] & 0x80000000);
+ sregs->fsi[frd + 1] = -1;
+ break;
+ case 1: /* FSGNJN */
+ sregs->fsi[frd] = (sregs->fsi[frs1] & 0x7fffffff) |
+ (~sregs->fsi[frs2] & 0x80000000);
+ sregs->fsi[frd + 1] = -1;
+ break;
+ case 2: /* FSGNJX */
+ sregs->fsi[frd] =
+ sregs->fsi[frs1] ^ (sregs->fsi[frs2] & 0x80000000);
+ sregs->fsi[frd + 1] = -1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 5: /* FMINS / FMAXS */
+ if ((sregs->fs[frs1] <
+ sregs->fs[frs2]) ^ ((sregs->inst >> 12) & 1))
+ sregs->fs[frd] = sregs->fs[frs1];
+ else
+ sregs->fs[frd] = sregs->fs[frs2];
+ sregs->fsi[frd + 1] = -1;
+ sregs->fhold += T_FSUBs;
+ break;
+#ifdef FPU_D_ENABLED
+ case 0x08: /* FCVTSD / FCVTDS */
+ switch (funct2)
+ {
+ case 0: /* FCVTSD */
+ sregs->fs[frd] = (float32) sregs->fd[rs1];
+ sregs->fsi[frd + 1] = -1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+#endif
+ case 0x0b: /* FSQRTS */
+ sregs->fs[frd] = sqrtf (sregs->fs[frs1]);
+ sregs->fsi[frd + 1] = -1;
+ sregs->fhold += T_FSQRTs;
+ break;
+ case 0x14: /* FCMPS */
+ switch (funct3)
+ {
+ case 0: /* FLES */
+ if ((sregs->fs[frs1] == sregs->fs[frs2]) ||
+ (sregs->fs[frs1] < sregs->fs[frs2]))
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ case 1: /* FLTS */
+ if (sregs->fs[frs1] < sregs->fs[frs2])
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ case 2: /* FEQS */
+ if (sregs->fs[frs1] == sregs->fs[frs2])
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 0x18: /* FCVTW */
+ switch (rs2)
+ {
+ case 0: /* FCVTWS */
+ sregs->g[rd] = (int32) sregs->fs[frs1];
+ break;
+ case 1: /* FCVTWUS */
+ sregs->g[rd] = (uint32) sregs->fs[frs1];
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 0x1a: /* FCVT */
+ switch (rs2)
+ {
+ case 0: /* FCVTSW */
+ sop1 = sregs->g[rs1];
+ sregs->fs[frd] = (float32) sop1;
+ sregs->fsi[frd + 1] = -1;
+ break;
+ case 1: /* FCVTSWU */
+ op1 = sregs->g[rs1];
+ sregs->fs[frd] = (float32) op1;
+ sregs->fsi[frd + 1] = -1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 0x1c:
+ switch (funct3)
+ {
+ case 0: /* FMVXS */
+ sregs->g[rd] = sregs->fsi[frs1];
+ break;
+ case 1: /* FCLASS */
+ op1 = fpclassify (sregs->fs[frs1]);
+ switch (op1)
+ {
+ case FP_NAN:
+ op1 = (1 << 8); // FIX ME, add quiet NaN
+ break;
+ case FP_INFINITE:
+ if (sregs->fsi[frs1] & 0x80000000)
+ op1 = (1 << 0);
+ else
+ op1 = (1 << 7);
+ break;
+ case FP_ZERO:
+ if (sregs->fsi[frs1] & 0x80000000)
+ op1 = (1 << 3);
+ else
+ op1 = (1 << 4);
+ break;
+ case FP_SUBNORMAL:
+ if (sregs->fsi[frs1] & 0x80000000)
+ op1 = (1 << 2);
+ else
+ op1 = (1 << 5);
+ break;
+ case FP_NORMAL:
+ if (sregs->fsi[frs1] & 0x80000000)
+ op1 = (1 << 1);
+ else
+ op1 = (1 << 6);
+ break;
+ }
+ sregs->g[rd] = op1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 0x1e: /* FMVSX */
+ sregs->fsi[frd] = sregs->g[rs1];
+ sregs->fsi[frd + 1] = -1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+#ifdef FPU_D_ENABLED
+ case 1: /* double-precision ops */
+ switch (funct5)
+ {
+ case 0:
+ sregs->fd[rd] = sregs->fd[rs1] + sregs->fd[rs2];
+ sregs->fhold += T_FADDd;
+ break;
+ case 1:
+ sregs->fd[rd] = sregs->fd[rs1] - sregs->fd[rs2];
+ sregs->fhold += T_FSUBd;
+ break;
+ case 2:
+ sregs->fd[rd] = sregs->fd[rs1] * sregs->fd[rs2];
+ sregs->fhold += T_FMULd;
+ break;
+ case 3:
+ sregs->fd[rd] = sregs->fd[rs1] / sregs->fd[rs2];
+ sregs->fhold += T_FDIVd;
+ break;
+ case 4: /* FSGX */
+ frd = (rd << 1);
+ frs1 = (rs1 << 1);
+ frs2 = (rs2 <<= 1);
+ switch (funct3)
+ {
+ case 0: /* FSGNJ */
+ sregs->fsi[frd] = sregs->fsi[frs1];
+ sregs->fsi[frd + 1] =
+ (sregs->
+ fsi[frs1 + 1] & 0x7fffffff) | (sregs->fsi[frs2 +
+ 1] &
+ 0x80000000);
+ break;
+ case 1: /* FSGNJN */
+ sregs->fsi[frd] = sregs->fsi[frs1];
+ sregs->fsi[frd + 1] =
+ (sregs->
+ fsi[frs1 + 1] & 0x7fffffff) | (~sregs->fsi[frs2 +
+ 1] &
+ 0x80000000);
+ break;
+ case 2: /* FSGNJX */
+ sregs->fsi[frd] = sregs->fsi[frs1];
+ sregs->fsi[frd + 1] =
+ sregs->fsi[frs1 +
+ 1] ^ (sregs->fsi[frs2 + 1] & 0x80000000);
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 5: /* FMIND / FMAXD */
+ if ((sregs->fd[rs1] <
+ sregs->fd[rs2]) ^ ((sregs->inst >> 12) & 1))
+ sregs->fd[rd] = sregs->fd[rs1];
+ else
+ sregs->fd[rd] = sregs->fd[rs2];
+ sregs->fhold += T_FSUBd;
+ break;
+#ifdef FPU_D_ENABLED
+ case 0x08: /* FCVTSD / FCVTDS */
+ switch (funct2)
+ {
+ case 1: /* FCVTDS */
+ sregs->fd[rd] = (float64) sregs->fs[(rs1 << 1)];
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+#endif
+ case 0x0b: /* FSQRTD */
+ sregs->fd[rd] = sqrt (sregs->fd[rs1]);
+ sregs->fhold += T_FSQRTd;
+ break;
+ case 0x14: /* FCMPD */
+ switch (funct3)
+ {
+ case 0: /* FLED */
+ if ((sregs->fd[rs1] == sregs->fd[rs2]) ||
+ (sregs->fd[rs1] < sregs->fd[rs2]))
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ case 1: /* FLTD */
+ if (sregs->fd[rs1] < sregs->fd[rs2])
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ case 2: /* FEQD */
+ if (sregs->fd[rs1] == sregs->fd[rs2])
+ sregs->g[rd] = 1;
+ else
+ sregs->g[rd] = 0;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 0x18: /* FCVTW */
+ switch (rs2)
+ {
+ case 0: /* FCVTWD */
+ sregs->g[rd] = (int32) sregs->fd[rs1];
+ break;
+ case 1: /* FCVTWUD */
+ sregs->g[rd] = (uint32) sregs->fd[rs1];
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 0x1a: /* FCVTD */
+ switch (rs2)
+ {
+ case 0: /* FCVTDW */
+ sop1 = sregs->g[rs1];
+ sregs->fd[rd] = (float64) sop1;
+ break;
+ case 1: /* FCVTDWU */
+ op1 = sregs->g[rs1];
+ sregs->fd[rd] = (float64) op1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ case 0x1c: /* FCLASSD */
+ switch (funct3)
+ {
+ case 1:
+ op1 = fpclassify (sregs->fd[rs1]);
+ switch (op1)
+ {
+ case FP_NAN:
+ op1 = (1 << 8); // FIX ME, add quiet NaN
+ break;
+ case FP_INFINITE:
+ if (sregs->fsi[(rs1 << 1) + 1] & 0x80000000)
+ op1 = (1 << 0);
+ else
+ op1 = (1 << 7);
+ break;
+ case FP_ZERO:
+ if (sregs->fsi[(rs1 << 1) + 1] & 0x80000000)
+ op1 = (1 << 3);
+ else
+ op1 = (1 << 4);
+ break;
+ case FP_SUBNORMAL:
+ if (sregs->fsi[(rs1 << 1) + 1] & 0x80000000)
+ op1 = (1 << 2);
+ else
+ op1 = (1 << 5);
+ break;
+ case FP_NORMAL:
+ if (sregs->fsi[(rs1 << 1) + 1] & 0x80000000)
+ op1 = (1 << 1);
+ else
+ op1 = (1 << 6);
+ break;
+ }
+ sregs->g[rd] = op1;
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ break;
+#endif
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ sregs->fsr |= get_accex ();
+ clear_accex ();
+ break;
+ case OP_FMADD:
+ sregs->finst++;
+ clear_accex ();
+ switch ((sregs->inst >> 25) & 3)
+ {
+ case 0: /* OP_FMADDS */
+ sregs->fs[rd << 1] = (sregs->fs[rs1 << 1] * sregs->fs[rs2 << 1])
+ + sregs->fs[(sregs->inst >> 27) << 1];
+ sregs->fsi[(rd << 1) + 1] = -1;
+ sregs->fhold += T_FADDs + T_FMULs;
+ break;
+#ifdef FPU_D_ENABLED
+ case 1: /* OP_FMADDD */
+ sregs->fd[rd] = (sregs->fd[rs1] * sregs->fd[rs2])
+ + sregs->fd[sregs->inst >> 27];
+ sregs->fhold += T_FADDd + T_FMULd;
+ break;
+#endif
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ sregs->fsr |= get_accex ();
+ clear_accex ();
+ break;
+ case OP_FMSUB:
+ sregs->finst++;
+ clear_accex ();
+ switch ((sregs->inst >> 25) & 3)
+ {
+ case 0: /* OP_FMSUBS */
+ sregs->fs[rd << 1] = (sregs->fs[rs1 << 1] * sregs->fs[rs2 << 1])
+ - sregs->fs[(sregs->inst >> 27) << 1];
+ sregs->fsi[(rd << 1) + 1] = -1;
+ sregs->fhold += T_FMULs + T_FSUBs;
+ break;
+#ifdef FPU_D_ENABLED
+ case 1: /* OP_FMSUBD */
+ sregs->fd[rd] = (sregs->fd[rs1] * sregs->fd[rs2])
+ - sregs->fd[sregs->inst >> 27];
+ sregs->fhold += T_FMULd + T_FSUBd;
+ break;
+#endif
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ sregs->fsr |= get_accex ();
+ clear_accex ();
+ break;
+ case OP_FNMSUB:
+ sregs->finst++;
+ clear_accex ();
+ switch ((sregs->inst >> 25) & 3)
+ {
+ case 0: /* OP_FNMSUBS */
+ sregs->fs[rd << 1] =
+ (-sregs->fs[rs1 << 1] * sregs->fs[rs2 << 1]) +
+ sregs->fs[(sregs->inst >> 27) << 1];
+ sregs->fsi[(rd << 1) + 1] = -1;
+ sregs->fhold += T_FADDs + T_FSUBs;
+ break;
+#ifdef FPU_D_ENABLED
+ case 1: /* OP_FNMSUBD */
+ sregs->fd[rd] = (-sregs->fd[rs1] * sregs->fd[rs2])
+ + sregs->fd[sregs->inst >> 27];
+ sregs->fhold += T_FADDd + T_FSUBd;
+ break;
+#endif
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ sregs->fsr |= get_accex ();
+ clear_accex ();
+ break;
+ case OP_FNMADD:
+ sregs->finst++;
+ clear_accex ();
+ switch ((sregs->inst >> 25) & 3)
+ {
+ case 0: /* OP_FNMADDS */
+ sregs->fs[rd << 1] =
+ (-sregs->fs[rs1 << 1] * sregs->fs[rs2 << 1]) -
+ sregs->fs[(sregs->inst >> 27) << 1];
+ sregs->fsi[(rd << 1) + 1] = -1;
+ sregs->fhold += T_FADDs + T_FMULs;
+ break;
+#ifdef FPU_D_ENABLED
+ case 1: /* OP_FNMADDD */
+ sregs->fd[rd] = (-sregs->fd[rs1] * sregs->fd[rs2])
+ - sregs->fd[sregs->inst >> 27];
+ sregs->fhold += T_FADDs + T_FMULs;
+ break;
+#endif
+ default:
+ sregs->trap = TRAP_ILLEG;
+ }
+ sregs->fsr |= get_accex ();
+ clear_accex ();
+ break;
+#endif
+ case OP_FENCE:
+ break;
+ default:
+ sregs->trap = TRAP_ILLEG;
+ break;
+ }
+ }
+
+ sregs->g[0] = 0;
+ if (!sregs->trap)
+ {
+ sregs->pc = npc;
+ }
+ return 0;
+}
+
+static int
+riscv_execute_trap (sregs)
+ struct pstate *sregs;
+{
+ if (sis_verbose > 1)
+ printf (" %8" PRIu64 " cpu %d trap : %08X\n",
+ sregs->simtime, sregs->cpu, sregs->trap);
+ if (sregs->trap >= 256)
+ {
+ switch (sregs->trap)
+ {
+ case 256:
+ sregs->pc = 0;
+ sregs->trap = 0;
+ break;
+ case ERROR_TRAP:
+ return (ERROR);
+ case WPT_TRAP:
+ return (WPT_HIT);
+ case NULL_TRAP:
+ return (NULL_HIT);
+
+ }
+ }
+ else
+ {
+
+ if (ebase.coven)
+ cov_jmp (sregs->pc, sregs->mtvec);
+ sregs->epc = sregs->pc;
+ sregs->mpp = sregs->mode;
+ sregs->mode = 1;
+ sregs->pc = sregs->mtvec;
+ sregs->mcause = sregs->trap;
+ sregs->lrq = 0;
+ switch (sregs->trap)
+ {
+ case TRAP_IEXC:
+ sregs->err_mode = 1;
+ case TRAP_EBREAK:
+ sregs->mtval = sregs->epc;
+ break;
+ case TRAP_ILLEG:
+ sregs->mtval = sregs->inst;
+ if ((sregs->inst & 0x0ffff) && (sregs->inst != 0xc0001073))
+ /* Not a RTEMS UNIMP test - stop execution ... */
+ sregs->err_mode = 1;
+ break;
+ case TRAP_LEXC:
+ case TRAP_SEXC:
+ case TRAP_LMALI:
+ case TRAP_SMALI:
+ sregs->mtval = sregs->wpaddress;
+ sregs->err_mode = 1;
+ break;
+ }
+
+ if (((sregs->trap >= 16) && (sregs->trap < 32))
+// || ((sregs->trap == 7) || (sregs->trap == 11))
+ )
+ {
+ sregs->mcause &= 0x1f; // filter trap cause
+ sregs->mcause |= 0x80000000; // indicate async interrupt
+ if ((sregs->trap > 16) && (sregs->trap < 32))
+ sregs->intack (sregs->trap - 16, sregs->cpu);
+ }
+
+ // save mstatus.mie in mstatus.mpie
+ sregs->mstatus |= (sregs->mstatus << 4) & MSTATUS_MPIE;
+ sregs->mstatus &= ~MSTATUS_MIE; // clear mstatus.mie
+ /* single vector trapping! */
+ /*
+ if ( 0 != (1 & (sregs->asr17 >> 13)) ) {
+ sregs->mtvec = (sregs->mtvec & 0xfffff000) | (sregs->trap << 4);
+ }
+ */
+
+ sregs->icnt = TRAP_C;
+ sregs->trap = 0;
+
+ if (sregs->err_mode)
+ return (ERROR);
+ }
+
+
+ return 0;
+
+}
+
+static int
+riscv_check_interrupts (sregs)
+ struct pstate *sregs;
+{
+ if ((ext_irl[sregs->cpu]) && (sregs->mstatus & MSTATUS_MIE) &&
+ (sregs->mie & MIE_MEIE))
+ {
+ if (sregs->pwd_mode)
+ {
+ sregs->pwdtime += sregs->simtime - sregs->pwdstart;
+ sregs->pwd_mode = 0;
+ }
+ if (sregs->trap == 0)
+ {
+ return ext_irl[sregs->cpu];
+ }
+ }
+ return 0;
+}
+
+static void
+riscv_set_regi (sregs, reg, rval)
+ struct pstate *sregs;
+ int32 reg;
+ uint32 rval;
+{
+
+ if ((reg >= 0) && (reg < 32))
+ {
+ sregs->g[reg] = rval;
+ }
+ else if (reg == 32)
+ {
+ sregs->pc = rval;
+ last_load_addr = rval;
+ }
+ else if ((reg >= 33) && (reg < 65))
+ {
+ sregs->fsi[reg - 33] = rval;
+ }
+ else if ((reg >= 65) && (reg < 4161))
+ {
+ set_csr (reg - 65, sregs, rval);
+ }
+}
+
+static void
+riscv_get_regi (struct pstate *sregs, int32 reg, char *buf, int length)
+{
+ uint32 rval = 0;
+
+ if ((reg >= 0) && (reg < 32))
+ {
+ rval = sregs->g[reg];
+ }
+ else if (reg == 32)
+ {
+ rval = sregs->pc;
+ }
+ else if ((reg >= 33) && (reg < 65))
+ {
+ if (length == 8)
+ {
+ rval = sregs->fsi[((reg - 33) << 1) + 1];
+ buf[7] = (rval >> 24) & 0x0ff;
+ buf[6] = (rval >> 16) & 0x0ff;
+ buf[5] = (rval >> 8) & 0x0ff;
+ buf[4] = rval & 0x0ff;
+ }
+ rval = sregs->fsi[(reg - 33) << 1];
+ }
+ else if ((reg >= 65) && (reg < 4161))
+ {
+ get_csr (reg - 65, sregs);
+ }
+ buf[3] = (rval >> 24) & 0x0ff;
+ buf[2] = (rval >> 16) & 0x0ff;
+ buf[1] = (rval >> 8) & 0x0ff;
+ buf[0] = rval & 0x0ff;
+}
+
+static int
+riscv_gdb_get_reg (char *buf)
+{
+ int i;
+
+ for (i = 0; i < 65; i++)
+ riscv_get_regi (&sregs[cpu], i, &buf[i * 4], 4);
+
+ return (65 * 4);
+}
+
+static void
+riscv_set_rega (struct pstate *sregs, char *reg, uint32 rval)
+{
+ int32 err = 0;
+
+ if (strcmp (reg, "psr") == 0)
+ sregs->psr = (rval = (rval & 0x00f03fff));
+ else if (strcmp (reg, "mtvec") == 0)
+ sregs->mtvec = (rval = (rval & 0xfffffff0));
+ else if (strcmp (reg, "mstatus") == 0)
+ sregs->mstatus = (rval = (rval & 0x0ff));
+ else if (strcmp (reg, "pc") == 0)
+ sregs->pc = rval;
+ else if (strcmp (reg, "fsr") == 0)
+ {
+ sregs->fsr = rval;
+ set_fsr (rval);
+ }
+ else if (strcmp (reg, "g0") == 0)
+ err = 2;
+ else if (strcmp (reg, "x1") == 0)
+ sregs->g[1] = rval;
+ else if (strcmp (reg, "x2") == 0)
+ sregs->g[2] = rval;
+ else if (strcmp (reg, "x3") == 0)
+ sregs->g[3] = rval;
+ else if (strcmp (reg, "x4") == 0)
+ sregs->g[4] = rval;
+ else if (strcmp (reg, "x5") == 0)
+ sregs->g[5] = rval;
+ else if (strcmp (reg, "x6") == 0)
+ sregs->g[6] = rval;
+ else if (strcmp (reg, "x7") == 0)
+ sregs->g[7] = rval;
+ else
+ err = 1;
+ switch (err)
+ {
+ case 0:
+ printf ("%s = %d (0x%08x)\n", reg, rval, rval);
+ break;
+ case 1:
+ printf ("no such regiser: %s\n", reg);
+ break;
+ case 2:
+ printf ("cannot set x0\n");
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void
+riscv_set_register (struct pstate *sregs, char *reg, uint32 rval, uint32 addr)
+{
+ if (reg == NULL)
+ riscv_set_regi (sregs, addr, rval);
+ else
+ riscv_set_rega (sregs, reg, rval);
+}
+
+static void
+riscv_display_registers (struct pstate *sregs)
+{
+
+ int i;
+
+ printf ("\n 0 - 7 8 - 15 16 - 23 24 - 31\n");
+ printf (" z0: %08X s0: %08X a6: %08X s8: %08X\n",
+ sregs->g[0], sregs->g[8], sregs->g[16], sregs->g[24]);
+ printf (" ra: %08X s1: %08X a7: %08X s9: %08X\n",
+ sregs->g[1], sregs->g[9], sregs->g[17], sregs->g[25]);
+ printf (" sp: %08X a0: %08X s2: %08X s10: %08X\n",
+ sregs->g[2], sregs->g[10], sregs->g[18], sregs->g[26]);
+ printf (" gp: %08X a1: %08X s3: %08X s11: %08X\n",
+ sregs->g[3], sregs->g[11], sregs->g[19], sregs->g[27]);
+ printf (" tp: %08X a2: %08X s4: %08X t3: %08X\n",
+ sregs->g[4], sregs->g[12], sregs->g[20], sregs->g[28]);
+ printf (" t0: %08X a3: %08X s5: %08X t4: %08X\n",
+ sregs->g[5], sregs->g[13], sregs->g[21], sregs->g[29]);
+ printf (" t1: %08X a4: %08X s6: %08X t5: %08X\n",
+ sregs->g[6], sregs->g[14], sregs->g[22], sregs->g[30]);
+ printf (" t2: %08X a5: %08X s7: %08X t6: %08X\n",
+ sregs->g[7], sregs->g[15], sregs->g[23], sregs->g[31]);
+}
+
+
+
+static void
+riscv_display_ctrl (struct pstate *sregs)
+{
+ uint32 i;
+
+ printf ("\n mtvec: %08X mcause: %08X mepc: %08X mtval: %08X \
+mstatus: %08X\n", get_csr (CSR_MTVEC, sregs), get_csr (CSR_MCAUSE, sregs), get_csr (CSR_MEPC, sregs), sregs->mtval, get_csr (CSR_MSTATUS, sregs));
+ ms->sis_memory_read (sregs->pc, (char *) &i, 4);
+ printf ("\n pc: %08X = %08X ", sregs->pc, i);
+// print_insn_sis (sregs->pc, &dinfo);
+ if (sregs->err_mode)
+ printf ("\n CPU in error mode");
+ else if (sregs->pwd_mode)
+ printf ("\n IU in power-down mode");
+ printf ("\n\n");
+}
+
+static void
+riscv_display_special (struct pstate *sregs)
+{
+ uint32 i;
+
+ printf ("\n 0x001 fcsr : %08X\n", get_csr (CSR_FCSR, sregs));
+ printf (" 0x300 mstatus : %08X\n", get_csr (CSR_MSTATUS, sregs));
+ printf (" 0x301 misa : %08X\n", get_csr (CSR_MISA, sregs));
+ printf (" 0x304 mie : %08X\n", get_csr (CSR_MIE, sregs));
+ printf (" 0x305 mtvec : %08X\n", get_csr (CSR_MTVEC, sregs));
+ printf (" 0x341 mepc : %08X\n", get_csr (CSR_MEPC, sregs));
+ printf (" 0x342 mcause : %08X\n", get_csr (CSR_MCAUSE, sregs));
+ printf (" 0x343 mtval : %08X\n", get_csr (CSR_MTVAL, sregs));
+ printf (" 0x344 mip : %08X\n", get_csr (CSR_MIP, sregs));
+ printf (" 0xC01 time : %08X\n", get_csr (CSR_TIME, sregs));
+ printf (" 0xC81 timeh : %08X\n\n", get_csr (CSR_TIMEH, sregs));
+
+}
+
+static void
+riscv_display_fpu (struct pstate *sregs)
+{
+ int i;
+ float t;
+
+ printf ("\n fsr: %08X\n\n", sregs->fsr);
+ printf
+ (" hex single double\n");
+
+ for (i = 0; i < 32; i++)
+ {
+ if (i < 8)
+ printf ("ft%d ", i);
+ else if (i < 10)
+ printf ("fs%d ", i - 8);
+ else if (i < 18)
+ printf ("fa%d ", i - 10);
+ else if (i < 26)
+ printf ("fs%d ", i - 16);
+ else if (i < 28)
+ printf ("fs%d ", i - 16);
+ else if (i < 30)
+ printf ("ft%d ", i - 20);
+ else
+ printf ("ft%d ", i - 20);
+
+ printf (" f%02d %08x%08x %.15e %.15e\n", i, sregs->fsi[(i << 1) + 1],
+ sregs->fsi[i << 1], sregs->fs[i << 1], sregs->fd[i]);
+ }
+ printf ("\n");
+}
+
+static char rtbl[32][8] = { "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
+ "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
+ "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
+};
+
+static char ftbl[32][8] =
+ { "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
+ "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
+ "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+ "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
+};
+
+char *
+ctbl (uint32 address)
+{
+ switch (address)
+ {
+ case CSR_MSTATUS:
+ return "mstatus";
+ break;
+ case CSR_MCAUSE:
+ return "mcause";
+ break;
+ case CSR_MTVEC:
+ return "mtvec";
+ break;
+ case CSR_MEPC:
+ return "mepc";
+ break;
+ case CSR_MIP:
+ return "mip";
+ break;
+ case CSR_MIE:
+ return "mie";
+ break;
+ case CSR_MTVAL:
+ return "mtval";
+ break;
+ case CSR_MISA:
+ return "misa";
+ break;
+ case CSR_TIME:
+ return "time";
+ break;
+ case CSR_TIMEH:
+ return "timeh";
+ break;
+ case CSR_MHARTID:
+ return "hartid";
+ break;
+ case CSR_MSCRATCH:
+ return "mscratch";
+ break;
+ case CSR_FFLAGS:
+ return "fflags";
+ break;
+ case CSR_FRM:
+ return "frm";
+ break;
+ case CSR_FCSR:
+ return "fcsr";
+ break;
+ default:
+ return "unimp";
+ }
+}
+
+static void
+riscv_disas (char *st, uint32 pc, uint32 inst)
+{
+ uint32 op1, op2, op3, rd, rs1, rs2, npc, btrue;
+ int32 sop1, sop2, *wdata, result, offset;
+ int32 data, address, ws, mexc, fcc, z;
+ unsigned char op, funct3, funct5, rs1p, rs2p, funct2, frs1, frs2, frd;
+ int64 sop64a, sop64b;
+ uint64 op64a, op64b;
+ char opc[16], param[32], stmp[16];
+
+ strcpy (opc, "unimp");
+ strcpy (param, "");
+
+ if ((inst & 3) != 3)
+ {
+ /* Compressed instructions (RV32C) */
+ npc = pc + 2;
+ funct3 = (inst >> 13) & 7;
+ rs1p = ((inst >> 7) & 7) | 8;
+ rs2p = ((inst >> 2) & 7) | 8;
+ rs1 = ((inst >> 7) & 0x1f);
+ rs2 = ((inst >> 2) & 0x1f);
+ switch (inst & 3)
+ {
+ case 0:
+ address = (int32) EXTRACT_RVC_LW_IMM (inst);
+ sprintf (param, "%s,%d(%s)", rtbl[rs2p], address, rtbl[rs1p]);
+ switch (funct3)
+ {
+ case CADDI4SPN: /* addi rd', x2, nzuimm[9:2] */
+ if ((inst & 0x0ffff) == 0)
+ {
+ param[0] = 0;
+ break;
+ }
+ strcpy (opc, "addi");
+ sprintf (param, "%s,%s,%d", rtbl[rs2p], rtbl[2],
+ (int32) EXTRACT_RVC_ADDI4SPN_IMM (inst));
+ break;
+ case CLW: /* lw rd', offset[6:2](rs1') */
+ strcpy (opc, "lw");
+ break;
+ case CSW: /* sw rs2', offset[6:2](rs1') */
+ strcpy (opc, "sw");
+ break;
+ case CFLW: /* lw rd', offset[6:2](rs1') */
+ strcpy (opc, "flw");
+ sprintf (param, "%s,%d(%s)", ftbl[rs2p], address, rtbl[rs1p]);
+ break;
+ case CFLD: /* ld frd', offset[7:3](rs1') */
+ address = (int32) EXTRACT_RVC_LD_IMM (inst);
+ strcpy (opc, "fld");
+ sprintf (param, "%s,%d(%s)", ftbl[rs2p], address, rtbl[rs1p]);
+ break;
+ case CFSW: /* sw rs2', offset[6:2](rs1') */
+ strcpy (opc, "fsw");
+ sprintf (param, "%s,%d(%s)", ftbl[rs2p], address, rtbl[rs1p]);
+ break;
+ case CFSD: /* sd frs2', offset[7:3](rs1') */
+ address = (int32) EXTRACT_RVC_LD_IMM (inst);
+ strcpy (opc, "fsd");
+ sprintf (param, "%s,%d(%s)", ftbl[rs2p], address, rtbl[rs1p]);
+ break;
+ }
+ break;
+ case 1:
+ switch (funct3)
+ {
+ case CADDI: /* addi rd, rd, nzimm[5:0] */
+ sop2 = EXTRACT_RVC_IMM (inst);
+ strcpy (opc, "addi");
+ sprintf (param, "%s,%s,%d", rtbl[rs1], rtbl[rs1], sop2);
+ break;
+ case CLI: /* addi rd, x0, imm[5:0] */
+ sop2 = EXTRACT_RVC_IMM (inst);
+ strcpy (opc, "li");
+ sprintf (param, "%s,%d", rtbl[rs1], sop2);
+ break;
+ case CJAL: /* jal x1, offset[11:1] */
+ case CJNL: /* jal x0, offset[11:1] */
+ offset = EXTRACT_RVC_J_IMM (inst);
+ npc = pc + offset;
+ if (funct3 == CJAL)
+ {
+ strcpy (opc, "jal");
+ sprintf (param, "%s,0x%x", rtbl[1], npc);
+ }
+ else
+ {
+ strcpy (opc, "j");
+ sprintf (param, "0x%x", npc);
+ }
+ break;
+ case CADDI16SP: /* addi x2, x2, nzimm[9:4] */
+ if (rs1 == 2)
+ {
+ sop2 = EXTRACT_RVC_ADDI16SP_IMM (inst);
+ strcpy (opc, "addi");
+ sprintf (param, "%s,%s,%d", rtbl[rs1], rtbl[rs1], sop2);
+ }
+ else
+ { /* CLUI: lui rd, nzuimm[17:12 */
+ strcpy (opc, "lui");
+ sprintf (param, "%s,0x%x", rtbl[rs1],
+ EXTRACT_RVC_LUI_IMM (inst));
+ }
+ break;
+ case CARITH:
+ sop2 = EXTRACT_RVC_IMM (inst);
+ sprintf (param, "%s,%s,%d", rtbl[rs1p], rtbl[rs1p], sop2);
+ switch ((inst >> 10) & 7)
+ {
+ case 0: /* srli rd', rd', shamt[5:0] */
+ strcpy (opc, "srli");
+ sprintf (param, "%s,%s,%d", rtbl[rs1p], rtbl[rs1p],
+ sop2 & 0x1f);
+ break;
+ case 1: /* srai rd', rd', shamt[5:0] */
+ strcpy (opc, "srai");
+ sprintf (param, "%s,%s,%d", rtbl[rs1p], rtbl[rs1p],
+ sop2 & 0x1f);
+ break;
+ case 2:
+ case 6: /* andi rd', rd', imm[5:0] */
+ strcpy (opc, "andi");
+ break;
+ case 3:
+ sprintf (param, "%s,%s,%s", rtbl[rs1p], rtbl[rs1p],
+ rtbl[rs2p]);
+ switch ((inst >> 5) & 3)
+ {
+ case 0: /* sub rd', rd', rs2' */
+ strcpy (opc, "sub");
+ break;
+ case 1: /* xor rd', rd', rs2' */
+ strcpy (opc, "xor");
+ break;
+ case 2: /* or rd', rd', rs2' */
+ strcpy (opc, "or");
+ break;
+ case 3: /* and rd', rd', rs2' */
+ strcpy (opc, "and");
+ break;
+ }
+ break;
+ }
+ break;
+ case CBEQZ: /* beq rs1', x0, offset[8:1] */
+ offset = EXTRACT_RVC_B_IMM (inst);
+ strcpy (opc, "beqz");
+ sprintf (param, "%s,0x%08x", rtbl[rs1p], pc + offset);
+ break;
+ case CBNEZ: /* bne rs1', x0, offset[8:1] */
+ offset = EXTRACT_RVC_B_IMM (inst);
+ strcpy (opc, "bnez");
+ sprintf (param, "%s,0x%08x", rtbl[rs1p], pc + offset);
+ break;
+ }
+ break;
+ case 2:
+ switch (funct3)
+ {
+ case 0: /* slli rd', rd', shamt[5:0] */
+ sop2 = EXTRACT_RVC_IMM (inst);
+ strcpy (opc, "slli");
+ sprintf (param, "%s,%s,%d", rtbl[rs1], rtbl[rs1], sop2 & 0x1f);
+ break;
+ case 2: /* LWSP: lw rd, offset[7:2](x2) */
+ offset = EXTRACT_RVC_LWSP_IMM (inst);
+ sprintf (param, "%s,%d(%s)", rtbl[rs1], offset, rtbl[2]);
+ strcpy (opc, "lw");
+ break;
+ case 1: /* FLDSP: ld frd, offset[8:3](x2) */
+ offset = EXTRACT_RVC_LDSP_IMM (inst);
+ sprintf (param, "%s,%d(%s)", ftbl[rs1], offset, rtbl[2]);
+ strcpy (opc, "fld");
+ break;
+ case 3: /* FLWSP: lw frd, offset[7:2](x2) */
+ offset = EXTRACT_RVC_LWSP_IMM (inst);
+ sprintf (param, "%s,%d(%s)", ftbl[rs1], offset, rtbl[2]);
+ strcpy (opc, "flw");
+ break;
+ case 4:
+ if ((inst >> 12) & 1)
+ {
+ if (rs1)
+ {
+ if (rs2)
+ { /* add rd, rd, rs2 */
+ strcpy (opc, "add");
+ sprintf (param, "%s,%s,%s", rtbl[rs1], rtbl[rs1],
+ rtbl[rs2]);
+ }
+ else
+ { /* jalr x1, rs1, 0 */
+ strcpy (opc, "jalr");
+ sprintf (param, "%s,%s", rtbl[1], rtbl[rs1]);
+ }
+ }
+ else
+ { /* EBREAK */
+ strcpy (opc, "ebreak");
+ }
+ }
+ else
+ {
+ if (rs2)
+ { /* MV */
+ strcpy (opc, "mv");
+ sprintf (param, "%s,%s", rtbl[rs1], rtbl[rs2]);
+ }
+ else
+ { /* jalr x0, rs1, 0 */
+ if (rs1 == 1)
+ {
+ strcpy (opc, "ret");
+ }
+ else
+ {
+ strcpy (opc, "j");
+ sprintf (param, "%s", rtbl[rs1]);
+ }
+ }
+ }
+ break;
+ case 6: /* SWSP: sw rs2, offset[7:2](x2) */
+ address = EXTRACT_RVC_SWSP_IMM (inst);
+ strcpy (opc, "sw");
+ sprintf (param, "%s,%d(sp)", rtbl[rs2], address);
+ break;
+ case 5: /* FSDSP: sw frs2, offset[8:3](x2) */
+ address = EXTRACT_RVC_SDSP_IMM (inst);
+ strcpy (opc, "fsd");
+ sprintf (param, "%s,%d(sp)", ftbl[rs2], address);
+ break;
+ case 7: /* FSWSP: sw frs2, offset[7:2](x2) */
+ address = EXTRACT_RVC_SWSP_IMM (inst);
+ strcpy (opc, "fsw");
+ sprintf (param, "%s,%d(sp)", ftbl[rs2], address);
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ op = (inst >> 2) & 0x1f;
+ funct3 = (inst >> 12) & 0x7;
+ rd = (inst >> 7) & 0x1f;
+ rs1 = (inst >> 15) & 0x1f;
+ rs2 = (inst >> 20) & 0x1f;
+ switch (op)
+ {
+ case OP_LUI:
+ strcpy (opc, "lui");
+ sprintf (param, "%s,0x%x", rtbl[rd], inst >> 12);
+ break;
+ case OP_BRANCH:
+ offset = EXTRACT_SBTYPE_IMM (inst);
+ switch (funct3)
+ {
+ case B_BE:
+ strcpy (opc, "beq ");
+ break;
+ case B_BNE:
+ strcpy (opc, "bne ");
+ break;
+ case B_BGE:
+ strcpy (opc, "bge ");
+ break;
+ case B_BGEU:
+ strcpy (opc, "bgeu");
+ break;
+ case B_BLT:
+ if (rs1)
+ strcpy (opc, "blt ");
+ else
+ strcpy (opc, "bgtz");
+ break;
+ case B_BLTU:
+ strcpy (opc, "bltu");
+ break;
+ }
+ if (rs1)
+ {
+ sprintf (stmp, "%s,", rtbl[rs1]);
+ strcat (param, stmp);
+ }
+ if (rs2)
+ {
+ sprintf (stmp, "%s,", rtbl[rs2]);
+ strcat (param, stmp);
+ }
+ else
+ opc[3] = 'z';
+ sprintf (stmp, "0x%08x", pc + offset);
+ strcat (param, stmp);
+ break;
+ case OP_JAL: /* JAL */
+ offset = EXTRACT_UJTYPE_IMM (inst);
+ npc = (pc + offset) & ~1;
+ if (!rd)
+ {
+ strcpy (opc, "j");
+ sprintf (param, "0x%x", npc);
+ }
+ else
+ {
+ strcpy (opc, "jal");
+ sprintf (param, "%s,0x%x", rtbl[rd], npc);
+ }
+ break;
+ case OP_JALR: /* JALR */
+ offset = EXTRACT_ITYPE_IMM (inst);
+ if (!rd && !offset && (rs1 == 1))
+ {
+ strcpy (opc, "ret");
+ param[0] = 0;
+ }
+ else
+ {
+ strcpy (opc, "jalr");
+ if (rd == 1)
+ sprintf (param, "%s", rtbl[rs1]);
+ else
+ sprintf (param, "%s,%s", rtbl[rd], rtbl[rs1]);
+ if (offset)
+ {
+ sprintf (stmp, ",0x%x", offset);
+ strcat (param, stmp);
+ }
+ }
+ break;
+ case OP_AUIPC: /* AUIPC */
+ strcpy (opc, "auipc");
+ sprintf (param, "%s,0x%x", rtbl[rd], inst >> 12);
+ break;
+ case OP_IMM: /* IMM */
+ sop2 = EXTRACT_ITYPE_IMM (inst);
+ sprintf (param, "%s,%s,%d", rtbl[rd], rtbl[rs1], sop2);
+ switch (funct3)
+ {
+ case IXOR:
+ strcpy (opc, "xori");
+ break;
+ case IOR:
+ strcpy (opc, "ori");
+ break;
+ case IAND:
+ strcpy (opc, "andi");
+ break;
+ case ADD:
+ if (!rs1)
+ {
+ strcpy (opc, "li");
+ sprintf (param, "%s,%d", rtbl[rd], sop2);
+ }
+ else if (!sop2)
+ {
+ strcpy (opc, "mv");
+ sprintf (param, "%s,%d", rtbl[rd], sop2);
+ sprintf (param, "%s,%s", rtbl[rd], rtbl[rs1]);
+ }
+ else
+ strcpy (opc, "addi");
+ break;
+ case SLL:
+ strcpy (opc, "slli");
+ sprintf (param, "%s,%s,%d", rtbl[rd], rtbl[rs1], sop2 & 0x1f);
+ break;
+ case SRL:
+ if ((inst >> 30) & 1)
+ strcpy (opc, "srai");
+ else
+ strcpy (opc, "srli");
+ sprintf (param, "%s,%s,%d", rtbl[rd], rtbl[rs1], sop2 & 0x1f);
+ break;
+ case SLT:
+ strcpy (opc, "slti");
+ break;
+ case SLTU:
+ strcpy (opc, "sltiu");
+ break;
+ }
+ break;
+ case OP_REG: /* REG */
+ sprintf (param, "%s,%s,%s", rtbl[rd], rtbl[rs1], rtbl[rs2]);
+ switch ((inst >> 25) & 3)
+ {
+ case 0:
+ switch (funct3)
+ {
+ case IXOR:
+ strcpy (opc, "xor");
+ break;
+ case IOR:
+ strcpy (opc, "or");
+ break;
+ case IAND:
+ strcpy (opc, "and");
+ break;
+ case ADD:
+ if ((inst >> 30) & 1)
+ strcpy (opc, "sub");
+ else
+ strcpy (opc, "add");
+ break;
+ case SLL:
+ strcpy (opc, "sll");
+ break;
+ case SRL:
+ if ((inst >> 30) & 1)
+ {
+ strcpy (opc, "sra");
+ }
+ else
+ strcpy (opc, "srl");
+ break;
+ case SLT:
+ strcpy (opc, "slt");
+ break;
+ case SLTU:
+ strcpy (opc, "sltu");
+ break;
+ }
+ break;
+ case 1: /* MUL/DIV */
+ switch (funct3)
+ {
+ case 0: /* MUL */
+ strcpy (opc, "mul");
+ break;
+ case 1: /* MULH */
+ strcpy (opc, "mulh");
+ break;
+ case 2: /* MULHSU */
+ strcpy (opc, "mulhsu");
+ break;
+ case 3: /* MULHU */
+ strcpy (opc, "mulhu");
+ break;
+ case 4: /* DIV */
+ strcpy (opc, "div");
+ break;
+ case 5: /* DIVU */
+ strcpy (opc, "divu");
+ break;
+ case 6: /* REM */
+ strcpy (opc, "rem");
+ break;
+ case 7: /* REMU */
+ strcpy (opc, "remu");
+ break;
+ }
+ break;
+ }
+ break;
+ case OP_STORE: /* store instructions */
+ offset = EXTRACT_STYPE_IMM (inst);
+ sprintf (param, "%s,%d(%s)", rtbl[rs2], offset, rtbl[rs1]);
+ switch (funct3)
+ {
+ case SW:
+ strcpy (opc, "sw");
+ break;
+ case SB:
+ strcpy (opc, "sb");
+ break;
+ case SH:
+ strcpy (opc, "sh");
+ break;
+ }
+ break;
+ case OP_FSW: /* F store instructions */
+ offset = EXTRACT_STYPE_IMM (inst);
+ sprintf (param, "%s,%d(%s)", ftbl[rs2], offset, rtbl[rs1]);
+ switch (funct3)
+ {
+ case 2: /* FSW */
+ strcpy (opc, "fsw");
+ break;
+ case 3: /* FSD */
+ strcpy (opc, "fsd");
+ }
+ break;
+ case OP_LOAD: /* load instructions */
+ offset = EXTRACT_ITYPE_IMM (inst);
+ sprintf (param, "%s,%d(%s)", rtbl[rd], offset, rtbl[rs1]);
+ switch (funct3)
+ {
+ case LW:
+ strcpy (opc, "lw");
+ break;
+ case LB:
+ strcpy (opc, "lb");
+ break;
+ case LBU:
+ strcpy (opc, "lbu");
+ break;
+ case LH:
+ strcpy (opc, "lh");
+ break;
+ case LHU:
+ strcpy (opc, "lhu");
+ break;
+ }
+ break;
+ case OP_AMO: /* atomic instructions */
+ sprintf (param, "%s,%s,(%s)", rtbl[rd], rtbl[rs2], rtbl[rs1]);
+ funct5 = (inst >> 27) & 0x1f;
+ switch (funct5)
+ {
+ case LRQ:
+ sprintf (param, "%s,(%s)", rtbl[rd], rtbl[rs1]);
+ strcpy (opc, "lr.w");
+ if ((inst >> 26) & 1)
+ strcat (opc, ".aq");
+ if ((inst >> 25) & 1)
+ strcat (opc, ".rl");
+ break;
+ case SCQ:
+ strcpy (opc, "sc.w");
+ if ((inst >> 26) & 1)
+ strcat (opc, ".aq");
+ if ((inst >> 25) & 1)
+ strcat (opc, ".rl");
+ break;
+ default: /* AMOXXX */
+ switch (funct5)
+ {
+ case AMOSWAP:
+ strcpy (opc, "amoswap");
+ break;
+ case AMOADD:
+ strcpy (opc, "amoadd");
+ break;
+ case AMOXOR:
+ strcpy (opc, "amoxor");
+ break;
+ case AMOOR:
+ strcpy (opc, "amoor");
+ break;
+ case AMOAND:
+ strcpy (opc, "amoand");
+ break;
+ case AMOMIN:
+ strcpy (opc, "amomin");
+ break;
+ case AMOMAX:
+ strcpy (opc, "amomax");
+ break;
+ case AMOMINU:
+ strcpy (opc, "amominu");
+ break;
+ case AMOMAXU:
+ strcpy (opc, "amomaxu");
+ break;
+ }
+ }
+ break;
+ case OP_SYS:
+ address = inst >> 20;
+ sprintf (param, "%s,%s,%s", rtbl[rd], ctbl (address), rtbl[rs1]);
+ op1 = (inst >> 15) & 0x1f;
+ switch (funct3)
+ {
+ case 0: /* ecall, xret */
+ param[0] = 0;
+ switch (rs2)
+ {
+ case 0: /* ecall */
+ strcpy (opc, "ecall");
+ break;
+ case 1: /* ebreak */
+ strcpy (opc, "ebreak");
+ break;
+ case 2: /* xret */
+ strcpy (opc, "mret");
+ break;
+ case 5: /* wfi */
+ strcpy (opc, "wfi");
+ break;
+ }
+ break;
+ case CSRRW:
+ if (rd)
+ strcpy (opc, "csrrw");
+ else
+ {
+ sprintf (param, "%s,%s", ctbl (address), rtbl[rs1]);
+ strcpy (opc, "csrw");
+ }
+ break;
+ case CSRRS:
+ if (rd)
+ strcpy (opc, "csrrs");
+ else
+ {
+ sprintf (param, "%s,%s", ctbl (address), rtbl[rs1]);
+ strcpy (opc, "csrs");
+ }
+ break;
+ case CSRRC:
+ strcpy (opc, "csrrc");
+ break;
+ case CSRRWI:
+ strcpy (opc, "csrrwi");
+ sprintf (param, "%s,%s,%d", rtbl[rd], ctbl (address), op1);
+ break;
+ case CSRRCI:
+ strcpy (opc, "csrrci");
+ sprintf (param, "%s,%s,%d", rtbl[rd], ctbl (address), op1);
+ break;
+ case CSRRSI:
+ if (rd)
+ strcpy (opc, "csrrsi");
+ else
+ {
+ strcpy (opc, "csrsi");
+ sprintf (param, "%s,%d", ctbl (address), op1);
+ }
+ break;
+ }
+ break;
+ case OP_FLOAD: /* float load instructions */
+ offset = EXTRACT_ITYPE_IMM (inst);
+ sprintf (param, "%s,%d(%s)", ftbl[rd], offset, rtbl[rs1]);
+ switch (funct3)
+ {
+ case LW:
+ strcpy (opc, "flw");
+ break;
+ case LD:
+ strcpy (opc, "fld");
+ break;
+ }
+ break;
+ case OP_FPU:
+ funct2 = (inst >> 25) & 3;
+ funct5 = (inst >> 27);
+ sprintf (param, "%s,%s,%s", ftbl[rd], ftbl[rs1], ftbl[rs2]);
+ switch (funct2)
+ {
+ case 0: /* single-precision ops */
+ switch (funct5)
+ {
+ case 0: /* FADDS */
+ strcpy (opc, "fadd.s");
+ break;
+ case 1: /* FSUBS */
+ strcpy (opc, "fsub.s");
+ break;
+ case 2: /* FMULS */
+ strcpy (opc, "fmul.s");
+ break;
+ case 3: /* FDIVS */
+ strcpy (opc, "fdiv.s");
+ break;
+ case 4: /* FSGX */
+ switch (funct3)
+ {
+ case 0: /* FSGNJ */
+ strcpy (opc, "fsgnj.s");
+ break;
+ case 1: /* FSGNJN */
+ strcpy (opc, "fsgnjn.s");
+ break;
+ case 2: /* FSGNJX */
+ strcpy (opc, "fsgnjx.s");
+ break;
+ }
+ break;
+ case 5: /* FMINS / FMAXS */
+ if ((inst >> 12) & 1)
+ strcpy (opc, "fmax.s");
+ else
+ strcpy (opc, "fmin.s");
+ break;
+ case 0x08: /* FCVTSD / FCVTDS */
+ switch (funct2)
+ {
+ case 0: /* FCVTSD */
+ strcpy (opc, "fcvt.s.d");
+ sprintf (param, "%s,%s", ftbl[rd], ftbl[rs1]);
+ break;
+ }
+ break;
+ case 0x0b: /* FSQRTS */
+ strcpy (opc, "fsqrt.s");
+ sprintf (param, "%s,%s", ftbl[rd], ftbl[rs1]);
+ break;
+ case 0x14: /* FCMPS */
+ sprintf (param, "%s,%s,%s", rtbl[rd], ftbl[rs1], ftbl[rs2]);
+ switch (funct3)
+ {
+ case 0: /* FLES */
+ strcpy (opc, "fle.s");
+ break;
+ case 1: /* FLTS */
+ strcpy (opc, "flt.s");
+ break;
+ case 2: /* FEQS */
+ strcpy (opc, "feq.s");
+ break;
+ }
+ break;
+ case 0x18: /* FCVTW */
+ sprintf (param, "%s,%s", rtbl[rd], ftbl[rs1]);
+ switch (rs2)
+ {
+ case 0: /* FCVTWS */
+ strcpy (opc, "fcvt.w.s");
+ break;
+ case 1: /* FCVTWUS */
+ strcpy (opc, "fcvt.wu.s");
+ break;
+ }
+ break;
+ case 0x1a: /* FCVT */
+ sprintf (param, "%s,%s", ftbl[rd], rtbl[rs1]);
+ switch (rs2)
+ {
+ case 0: /* FCVTSW */
+ strcpy (opc, "fcvt.s.w");
+ break;
+ case 1: /* FCVTSWU */
+ strcpy (opc, "fcvt.s.wu");
+ break;
+ }
+ break;
+ case 0x1c:
+ switch (funct3)
+ {
+ case 0: /* FMVXS */
+ sprintf (param, "%s,%s", rtbl[rd], ftbl[rs1]);
+ strcpy (opc, "fmv.x.s");
+ break;
+ case 1: /* FCLASS */
+ sprintf (param, "%s,%s", rtbl[rd], ftbl[rs1]);
+ strcpy (opc, "fclass.s");
+ break;
+ }
+ break;
+ case 0x1e: /* FMVSX */
+ sprintf (param, "%s,%s", ftbl[rd], rtbl[rs1]);
+ strcpy (opc, "fmv.s.x");
+ break;
+ }
+ break;
+ case 1: /* double-precision ops */
+ switch (funct5)
+ {
+ case 0:
+ strcpy (opc, "fadd.d");
+ break;
+ case 1:
+ strcpy (opc, "fsub.d");
+ break;
+ case 2:
+ strcpy (opc, "fmul.d");
+ break;
+ case 3:
+ strcpy (opc, "fdiv.d");
+ break;
+ case 4: /* FSGX */
+ switch (funct3)
+ {
+ case 0: /* FSGNJ */
+ strcpy (opc, "fsgnj.d");
+ break;
+ case 1: /* FSGNJN */
+ strcpy (opc, "fsgnjn.d");
+ break;
+ case 2: /* FSGNJX */
+ strcpy (opc, "fsgnjx.d");
+ break;
+ }
+ break;
+ case 5: /* FMIND / FMAXD */
+ if ((inst >> 12) & 1)
+ strcpy (opc, "fmax.d");
+ else
+ strcpy (opc, "fmin.d");
+ break;
+ case 0x08: /* FCVTSD / FCVTDS */
+ switch (funct2)
+ {
+ case 1: /* FCVTDS */
+ strcpy (opc, "fcvt.d.s");
+ sprintf (param, "%s,%s", ftbl[rd], ftbl[rs1]);
+ break;
+ }
+ break;
+ case 0x0b: /* FSQRTD */
+ strcpy (opc, "fsqrt.d");
+ sprintf (param, "%s,%s", ftbl[rd], ftbl[rs1]);
+ break;
+ case 0x14: /* FCMPD */
+ sprintf (param, "%s,%s,%s", rtbl[rd], ftbl[rs1], ftbl[rs2]);
+ switch (funct3)
+ {
+ case 0: /* FLED */
+ strcpy (opc, "fle.d");
+ break;
+ case 1: /* FLTD */
+ strcpy (opc, "flt.d");
+ break;
+ case 2: /* FEQD */
+ strcpy (opc, "feq.d");
+ break;
+ }
+ break;
+ case 0x18: /* FCVTW */
+ sprintf (param, "%s,%s", rtbl[rd], ftbl[rs1]);
+ switch (rs2)
+ {
+ case 0: /* FCVTWD */
+ strcpy (opc, "fcvt.w.d");
+ break;
+ case 1: /* FCVTWUD */
+ strcpy (opc, "fcvt.wu.d");
+ break;
+ }
+ break;
+ case 0x1a: /* FCVTD */
+ sprintf (param, "%s,%s", ftbl[rd], rtbl[rs1]);
+ switch (rs2)
+ {
+ case 0: /* FCVTDW */
+ strcpy (opc, "fcvt.d.w");
+ break;
+ case 1: /* FCVTDWU */
+ strcpy (opc, "fcvt.d.wu");
+ break;
+ }
+ break;
+ case 0x1c: /* FCLASSD */
+ sprintf (param, "%s,%s", rtbl[rd], ftbl[rs1]);
+ switch (funct3)
+ {
+ case 1:
+ strcpy (opc, "fclass.d");
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case OP_FMADD:
+ sprintf (param, "%s,%s, %s, %s", ftbl[rd], ftbl[rs1], ftbl[rs2],
+ ftbl[inst >> 27]);
+ switch ((inst >> 25) & 3)
+ {
+ case 0: /* OP_FMADDS */
+ strcpy (opc, "fmadd.s");
+ break;
+ case 1: /* OP_FMADDD */
+ strcpy (opc, "fmadd.d");
+ break;
+ }
+ break;
+ case OP_FMSUB:
+ sprintf (param, "%s,%s, %s, %s", ftbl[rd], ftbl[rs1], ftbl[rs2],
+ ftbl[inst >> 27]);
+ switch ((inst >> 25) & 3)
+ {
+ case 0: /* OP_FMSUBS */
+ strcpy (opc, "fmsub.s");
+ break;
+ case 1: /* OP_FMSUBD */
+ strcpy (opc, "fmsub.d");
+ break;
+ }
+ break;
+ case OP_FNMSUB:
+ sprintf (param, "%s,%s, %s, %s", ftbl[rd], ftbl[rs1], ftbl[rs2],
+ ftbl[inst >> 27]);
+ switch ((inst >> 25) & 3)
+ {
+ case 0: /* OP_FNMSUBS */
+ strcpy (opc, "fnmsub.s");
+ break;
+ case 1: /* OP_FNMSUBD */
+ strcpy (opc, "fnmsub.d");
+ break;
+ }
+ break;
+ case OP_FNMADD:
+ sprintf (param, "%s,%s, %s, %s", ftbl[rd], ftbl[rs1], ftbl[rs2],
+ ftbl[inst >> 27]);
+ switch ((inst >> 25) & 3)
+ {
+ case 0: /* OP_FNMADDS */
+ strcpy (opc, "fnmadd.s");
+ break;
+ case 1: /* OP_FNMADDD */
+ strcpy (opc, "fnmadd.d");
+ break;
+ }
+ break;
+ case OP_FENCE:
+ strcpy (opc, "fence");
+ break;
+ }
+ }
+
+ sprintf (st, "%-12s%s", opc, param);
+
+}
+
+static void
+riscv_print_insn (uint32 addr)
+{
+ char tmp[128];
+ uint32 insn;
+ uint32 hold;
+
+ ms->memory_iread (addr, &insn, &hold);
+ riscv_disas (tmp, addr, insn);
+ printf (" %s", tmp);
+}
+
+const struct cpu_arch riscv = {
+ 0,
+ riscv_dispatch_instruction,
+ riscv_execute_trap,
+ riscv_check_interrupts,
+ riscv_print_insn,
+ riscv_gdb_get_reg,
+ riscv_set_register,
+ riscv_display_registers,
+ riscv_display_ctrl,
+ riscv_display_special,
+ riscv_display_fpu
+};