From 865b177d0e2fd534270ef158030e7c3056a930e3 Mon Sep 17 00:00:00 2001 From: Jiri Gaisler Date: Fri, 22 Mar 2019 10:00:07 +0100 Subject: Standalone sis - initial commit --- riscv.c | 3201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3201 insertions(+) create mode 100644 riscv.c (limited to 'riscv.c') 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 . */ + +#include "riscv.h" +#include +#include +#include +#include +#include +#include + +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 +}; -- cgit v1.2.3