Home | History | Annotate | Line # | Download | only in riscv
sim-main.c revision 1.1
      1 /* RISC-V simulator.
      2 
      3    Copyright (C) 2005-2023 Free Software Foundation, Inc.
      4    Contributed by Mike Frysinger.
      5 
      6    This file is part of simulators.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     20 
     21 /* This file contains the main simulator decoding logic.  i.e. everything that
     22    is architecture specific.  */
     23 
     24 /* This must come before any other includes.  */
     25 #include "defs.h"
     26 
     27 #include <inttypes.h>
     28 #include <time.h>
     29 
     30 #include "sim-main.h"
     31 #include "sim-signal.h"
     32 #include "sim-syscall.h"
     33 
     34 #include "opcode/riscv.h"
     35 
     36 #include "gdb/sim-riscv.h"
     37 
     38 #define TRACE_REG(cpu, reg) \
     40   TRACE_REGISTER (cpu, "wrote %s = %#" PRIxTW, riscv_gpr_names_abi[reg], \
     41 		  cpu->regs[reg])
     42 
     43 static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
     45 #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : 0x7f))
     46 
     47 #define RISCV_ASSERT_RV32(cpu, fmt, args...) \
     48   do { \
     49     if (RISCV_XLEN (cpu) != 32) \
     50       { \
     51 	SIM_DESC sd = CPU_STATE (cpu); \
     52 	TRACE_INSN (cpu, "RV32I-only " fmt, ## args); \
     53 	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
     54       } \
     55   } while (0)
     56 
     57 #define RISCV_ASSERT_RV64(cpu, fmt, args...) \
     58   do { \
     59     if (RISCV_XLEN (cpu) != 64) \
     60       { \
     61 	SIM_DESC sd = CPU_STATE (cpu); \
     62 	TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \
     63 	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
     64       } \
     65   } while (0)
     66 
     67 static INLINE void
     68 store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
     69 {
     70   if (rd)
     71     {
     72       cpu->regs[rd] = val;
     73       TRACE_REG (cpu, rd);
     74     }
     75 }
     76 
     77 static INLINE unsigned_word
     78 fetch_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg)
     79 {
     80   /* Handle pseudo registers.  */
     81   switch (csr)
     82     {
     83     /* Allow certain registers only in respective modes.  */
     84     case CSR_CYCLEH:
     85     case CSR_INSTRETH:
     86     case CSR_TIMEH:
     87       RISCV_ASSERT_RV32 (cpu, "CSR: %s", name);
     88       break;
     89     }
     90 
     91   return *reg;
     92 }
     93 
     94 static INLINE void
     95 store_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg,
     96 	   unsigned_word val)
     97 {
     98   switch (csr)
     99     {
    100     /* These are pseudo registers that modify sub-fields of fcsr.  */
    101     case CSR_FRM:
    102       val &= 0x7;
    103       *reg = val;
    104       cpu->csr.fcsr = (cpu->csr.fcsr & ~0xe0) | (val << 5);
    105       break;
    106     case CSR_FFLAGS:
    107       val &= 0x1f;
    108       *reg = val;
    109       cpu->csr.fcsr = (cpu->csr.fcsr & ~0x1f) | val;
    110       break;
    111     /* Keep the sub-fields in sync.  */
    112     case CSR_FCSR:
    113       *reg = val;
    114       cpu->csr.frm = (val >> 5) & 0x7;
    115       cpu->csr.fflags = val & 0x1f;
    116       break;
    117 
    118     /* Allow certain registers only in respective modes.  */
    119     case CSR_CYCLEH:
    120     case CSR_INSTRETH:
    121     case CSR_TIMEH:
    122       RISCV_ASSERT_RV32 (cpu, "CSR: %s", name);
    123 
    124     /* All the rest are immutable.  */
    125     default:
    126       val = *reg;
    127       break;
    128     }
    129 
    130   TRACE_REGISTER (cpu, "wrote CSR %s = %#" PRIxTW, name, val);
    131 }
    132 
    133 static inline unsigned_word
    134 ashiftrt (unsigned_word val, unsigned_word shift)
    135 {
    136   uint32_t sign = (val & 0x80000000) ? ~(0xfffffffful >> shift) : 0;
    137   return (val >> shift) | sign;
    138 }
    139 
    140 static inline unsigned_word
    141 ashiftrt64 (unsigned_word val, unsigned_word shift)
    142 {
    143   uint64_t sign =
    144     (val & 0x8000000000000000ull) ? ~(0xffffffffffffffffull >> shift) : 0;
    145   return (val >> shift) | sign;
    146 }
    147 
    148 static sim_cia
    149 execute_i (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
    150 {
    151   SIM_DESC sd = CPU_STATE (cpu);
    152   int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
    153   int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
    154   int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
    155   const char *rd_name = riscv_gpr_names_abi[rd];
    156   const char *rs1_name = riscv_gpr_names_abi[rs1];
    157   const char *rs2_name = riscv_gpr_names_abi[rs2];
    158   unsigned int csr = (iw >> OP_SH_CSR) & OP_MASK_CSR;
    159   unsigned_word i_imm = EXTRACT_ITYPE_IMM (iw);
    160   unsigned_word u_imm = EXTRACT_UTYPE_IMM ((uint64_t) iw);
    161   unsigned_word s_imm = EXTRACT_STYPE_IMM (iw);
    162   unsigned_word sb_imm = EXTRACT_BTYPE_IMM (iw);
    163   unsigned_word shamt_imm = ((iw >> OP_SH_SHAMT) & OP_MASK_SHAMT);
    164   unsigned_word tmp;
    165   sim_cia pc = cpu->pc + 4;
    166 
    167   TRACE_EXTRACT (cpu,
    168 		 "rd:%-2i:%-4s  "
    169 		 "rs1:%-2i:%-4s %0*" PRIxTW "  "
    170 		 "rs2:%-2i:%-4s %0*" PRIxTW "  "
    171 		 "match:%#x mask:%#x",
    172 		 rd, rd_name,
    173 		 rs1, rs1_name, (int) sizeof (unsigned_word) * 2, cpu->regs[rs1],
    174 		 rs2, rs2_name, (int) sizeof (unsigned_word) * 2, cpu->regs[rs2],
    175 		 (unsigned) op->match, (unsigned) op->mask);
    176 
    177   switch (op->match)
    178     {
    179     case MATCH_ADD:
    180       TRACE_INSN (cpu, "add %s, %s, %s;  // %s = %s + %s",
    181 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    182       store_rd (cpu, rd, cpu->regs[rs1] + cpu->regs[rs2]);
    183       break;
    184     case MATCH_ADDW:
    185       TRACE_INSN (cpu, "addw %s, %s, %s;  // %s = %s + %s",
    186 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    187       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    188       store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + cpu->regs[rs2]));
    189       break;
    190     case MATCH_ADDI:
    191       TRACE_INSN (cpu, "addi %s, %s, %#" PRIxTW ";  // %s = %s + %#" PRIxTW,
    192 		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
    193       store_rd (cpu, rd, cpu->regs[rs1] + i_imm);
    194       break;
    195     case MATCH_ADDIW:
    196       TRACE_INSN (cpu, "addiw %s, %s, %#" PRIxTW ";  // %s = %s + %#" PRIxTW,
    197 		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
    198       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    199       store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + i_imm));
    200       break;
    201     case MATCH_AND:
    202       TRACE_INSN (cpu, "and %s, %s, %s;  // %s = %s & %s",
    203 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    204       store_rd (cpu, rd, cpu->regs[rs1] & cpu->regs[rs2]);
    205       break;
    206     case MATCH_ANDI:
    207       TRACE_INSN (cpu, "andi %s, %s, %" PRIiTW ";  // %s = %s & %#" PRIxTW,
    208 		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
    209       store_rd (cpu, rd, cpu->regs[rs1] & i_imm);
    210       break;
    211     case MATCH_OR:
    212       TRACE_INSN (cpu, "or %s, %s, %s;  // %s = %s | %s",
    213 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    214       store_rd (cpu, rd, cpu->regs[rs1] | cpu->regs[rs2]);
    215       break;
    216     case MATCH_ORI:
    217       TRACE_INSN (cpu, "ori %s, %s, %" PRIiTW ";  // %s = %s | %#" PRIxTW,
    218 		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
    219       store_rd (cpu, rd, cpu->regs[rs1] | i_imm);
    220       break;
    221     case MATCH_XOR:
    222       TRACE_INSN (cpu, "xor %s, %s, %s;  // %s = %s ^ %s",
    223 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    224       store_rd (cpu, rd, cpu->regs[rs1] ^ cpu->regs[rs2]);
    225       break;
    226     case MATCH_XORI:
    227       TRACE_INSN (cpu, "xori %s, %s, %" PRIiTW ";  // %s = %s ^ %#" PRIxTW,
    228 		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
    229       store_rd (cpu, rd, cpu->regs[rs1] ^ i_imm);
    230       break;
    231     case MATCH_SUB:
    232       TRACE_INSN (cpu, "sub %s, %s, %s;  // %s = %s - %s",
    233 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    234       store_rd (cpu, rd, cpu->regs[rs1] - cpu->regs[rs2]);
    235       break;
    236     case MATCH_SUBW:
    237       TRACE_INSN (cpu, "subw %s, %s, %s;  // %s = %s - %s",
    238 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    239       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    240       store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] - cpu->regs[rs2]));
    241       break;
    242     case MATCH_LUI:
    243       TRACE_INSN (cpu, "lui %s, %#" PRIxTW ";", rd_name, u_imm);
    244       store_rd (cpu, rd, u_imm);
    245       break;
    246     case MATCH_SLL:
    247       TRACE_INSN (cpu, "sll %s, %s, %s;  // %s = %s << %s",
    248 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    249       u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f;
    250       store_rd (cpu, rd, cpu->regs[rs1] << (cpu->regs[rs2] & u_imm));
    251       break;
    252     case MATCH_SLLW:
    253       TRACE_INSN (cpu, "sllw %s, %s, %s;  // %s = %s << %s",
    254 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    255       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    256       store_rd (cpu, rd, EXTEND32 (
    257 	(uint32_t) cpu->regs[rs1] << (cpu->regs[rs2] & 0x1f)));
    258       break;
    259     case MATCH_SLLI:
    260       TRACE_INSN (cpu, "slli %s, %s, %" PRIiTW ";  // %s = %s << %#" PRIxTW,
    261 		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
    262       if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f)
    263 	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
    264       store_rd (cpu, rd, cpu->regs[rs1] << shamt_imm);
    265       break;
    266     case MATCH_SLLIW:
    267       TRACE_INSN (cpu, "slliw %s, %s, %" PRIiTW ";  // %s = %s << %#" PRIxTW,
    268 		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
    269       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    270       store_rd (cpu, rd, EXTEND32 ((uint32_t) cpu->regs[rs1] << shamt_imm));
    271       break;
    272     case MATCH_SRL:
    273       TRACE_INSN (cpu, "srl %s, %s, %s;  // %s = %s >> %s",
    274 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    275       u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f;
    276       store_rd (cpu, rd, cpu->regs[rs1] >> (cpu->regs[rs2] & u_imm));
    277       break;
    278     case MATCH_SRLW:
    279       TRACE_INSN (cpu, "srlw %s, %s, %s;  // %s = %s >> %s",
    280 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    281       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    282       store_rd (cpu, rd, EXTEND32 (
    283 	(uint32_t) cpu->regs[rs1] >> (cpu->regs[rs2] & 0x1f)));
    284       break;
    285     case MATCH_SRLI:
    286       TRACE_INSN (cpu, "srli %s, %s, %" PRIiTW ";  // %s = %s >> %#" PRIxTW,
    287 		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
    288       if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f)
    289 	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
    290       store_rd (cpu, rd, cpu->regs[rs1] >> shamt_imm);
    291       break;
    292     case MATCH_SRLIW:
    293       TRACE_INSN (cpu, "srliw %s, %s, %" PRIiTW ";  // %s = %s >> %#" PRIxTW,
    294 		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
    295       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    296       store_rd (cpu, rd, EXTEND32 ((uint32_t) cpu->regs[rs1] >> shamt_imm));
    297       break;
    298     case MATCH_SRA:
    299       TRACE_INSN (cpu, "sra %s, %s, %s;  // %s = %s >>> %s",
    300 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    301       if (RISCV_XLEN (cpu) == 32)
    302 	tmp = ashiftrt (cpu->regs[rs1], cpu->regs[rs2] & 0x1f);
    303       else
    304 	tmp = ashiftrt64 (cpu->regs[rs1], cpu->regs[rs2] & 0x3f);
    305       store_rd (cpu, rd, tmp);
    306       break;
    307     case MATCH_SRAW:
    308       TRACE_INSN (cpu, "sraw %s, %s, %s;  // %s = %s >>> %s",
    309 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    310       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    311       store_rd (cpu, rd, EXTEND32 (
    312 	ashiftrt ((int32_t) cpu->regs[rs1], cpu->regs[rs2] & 0x1f)));
    313       break;
    314     case MATCH_SRAI:
    315       TRACE_INSN (cpu, "srai %s, %s, %" PRIiTW ";  // %s = %s >>> %#" PRIxTW,
    316 		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
    317       if (RISCV_XLEN (cpu) == 32)
    318 	{
    319 	  if (shamt_imm > 0x1f)
    320 	    sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
    321 	  tmp = ashiftrt (cpu->regs[rs1], shamt_imm);
    322 	}
    323       else
    324 	tmp = ashiftrt64 (cpu->regs[rs1], shamt_imm);
    325       store_rd (cpu, rd, tmp);
    326       break;
    327     case MATCH_SRAIW:
    328       TRACE_INSN (cpu, "sraiw %s, %s, %" PRIiTW ";  // %s = %s >>> %#" PRIxTW,
    329 		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
    330       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    331       store_rd (cpu, rd, EXTEND32 (
    332 	ashiftrt ((int32_t) cpu->regs[rs1], shamt_imm)));
    333       break;
    334     case MATCH_SLT:
    335       TRACE_INSN (cpu, "slt");
    336       store_rd (cpu, rd,
    337 		!!((signed_word) cpu->regs[rs1] < (signed_word) cpu->regs[rs2]));
    338       break;
    339     case MATCH_SLTU:
    340       TRACE_INSN (cpu, "sltu");
    341       store_rd (cpu, rd, !!((unsigned_word) cpu->regs[rs1] <
    342 			    (unsigned_word) cpu->regs[rs2]));
    343       break;
    344     case MATCH_SLTI:
    345       TRACE_INSN (cpu, "slti");
    346       store_rd (cpu, rd, !!((signed_word) cpu->regs[rs1] <
    347 			    (signed_word) i_imm));
    348       break;
    349     case MATCH_SLTIU:
    350       TRACE_INSN (cpu, "sltiu");
    351       store_rd (cpu, rd, !!((unsigned_word) cpu->regs[rs1] <
    352 			    (unsigned_word) i_imm));
    353       break;
    354     case MATCH_AUIPC:
    355       TRACE_INSN (cpu, "auipc %s, %" PRIiTW ";  // %s = pc + %" PRIiTW,
    356 		  rd_name, u_imm, rd_name, u_imm);
    357       store_rd (cpu, rd, cpu->pc + u_imm);
    358       break;
    359     case MATCH_BEQ:
    360       TRACE_INSN (cpu, "beq %s, %s, %#" PRIxTW ";  "
    361 		       "// if (%s == %s) goto %#" PRIxTW,
    362 		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
    363       if (cpu->regs[rs1] == cpu->regs[rs2])
    364 	{
    365 	  pc = cpu->pc + sb_imm;
    366 	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    367 	}
    368       break;
    369     case MATCH_BLT:
    370       TRACE_INSN (cpu, "blt %s, %s, %#" PRIxTW ";  "
    371 		       "// if (%s < %s) goto %#" PRIxTW,
    372 		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
    373       if ((signed_word) cpu->regs[rs1] < (signed_word) cpu->regs[rs2])
    374 	{
    375 	  pc = cpu->pc + sb_imm;
    376 	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    377 	}
    378       break;
    379     case MATCH_BLTU:
    380       TRACE_INSN (cpu, "bltu %s, %s, %#" PRIxTW ";  "
    381 		       "// if (%s < %s) goto %#" PRIxTW,
    382 		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
    383       if ((unsigned_word) cpu->regs[rs1] < (unsigned_word) cpu->regs[rs2])
    384 	{
    385 	  pc = cpu->pc + sb_imm;
    386 	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    387 	}
    388       break;
    389     case MATCH_BGE:
    390       TRACE_INSN (cpu, "bge %s, %s, %#" PRIxTW ";  "
    391 		       "// if (%s >= %s) goto %#" PRIxTW,
    392 		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
    393       if ((signed_word) cpu->regs[rs1] >= (signed_word) cpu->regs[rs2])
    394 	{
    395 	  pc = cpu->pc + sb_imm;
    396 	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    397 	}
    398       break;
    399     case MATCH_BGEU:
    400       TRACE_INSN (cpu, "bgeu %s, %s, %#" PRIxTW ";  "
    401 		       "// if (%s >= %s) goto %#" PRIxTW,
    402 		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
    403       if ((unsigned_word) cpu->regs[rs1] >= (unsigned_word) cpu->regs[rs2])
    404 	{
    405 	  pc = cpu->pc + sb_imm;
    406 	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    407 	}
    408       break;
    409     case MATCH_BNE:
    410       TRACE_INSN (cpu, "bne %s, %s, %#" PRIxTW ";  "
    411 		       "// if (%s != %s) goto %#" PRIxTW,
    412 		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
    413       if (cpu->regs[rs1] != cpu->regs[rs2])
    414 	{
    415 	  pc = cpu->pc + sb_imm;
    416 	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    417 	}
    418       break;
    419     case MATCH_JAL:
    420       TRACE_INSN (cpu, "jal %s, %" PRIiTW ";", rd_name,
    421 		  EXTRACT_JTYPE_IMM (iw));
    422       store_rd (cpu, rd, cpu->pc + 4);
    423       pc = cpu->pc + EXTRACT_JTYPE_IMM (iw);
    424       TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    425       break;
    426     case MATCH_JALR:
    427       TRACE_INSN (cpu, "jalr %s, %s, %" PRIiTW ";", rd_name, rs1_name, i_imm);
    428       store_rd (cpu, rd, cpu->pc + 4);
    429       pc = cpu->regs[rs1] + i_imm;
    430       TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
    431       break;
    432 
    433     case MATCH_LD:
    434       TRACE_INSN (cpu, "ld %s, %" PRIiTW "(%s);",
    435 		  rd_name, i_imm, rs1_name);
    436       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    437       store_rd (cpu, rd,
    438 	sim_core_read_unaligned_8 (cpu, cpu->pc, read_map,
    439 				   cpu->regs[rs1] + i_imm));
    440       break;
    441     case MATCH_LW:
    442       TRACE_INSN (cpu, "lw %s, %" PRIiTW "(%s);",
    443 		  rd_name, i_imm, rs1_name);
    444       store_rd (cpu, rd, EXTEND32 (
    445 	sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
    446 				   cpu->regs[rs1] + i_imm)));
    447       break;
    448     case MATCH_LWU:
    449       TRACE_INSN (cpu, "lwu %s, %" PRIiTW "(%s);",
    450 		  rd_name, i_imm, rs1_name);
    451       store_rd (cpu, rd,
    452 	sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
    453 				   cpu->regs[rs1] + i_imm));
    454       break;
    455     case MATCH_LH:
    456       TRACE_INSN (cpu, "lh %s, %" PRIiTW "(%s);",
    457 		  rd_name, i_imm, rs1_name);
    458       store_rd (cpu, rd, EXTEND16 (
    459 	sim_core_read_unaligned_2 (cpu, cpu->pc, read_map,
    460 				   cpu->regs[rs1] + i_imm)));
    461       break;
    462     case MATCH_LHU:
    463       TRACE_INSN (cpu, "lbu %s, %" PRIiTW "(%s);",
    464 		  rd_name, i_imm, rs1_name);
    465       store_rd (cpu, rd,
    466 	sim_core_read_unaligned_2 (cpu, cpu->pc, read_map,
    467 				   cpu->regs[rs1] + i_imm));
    468       break;
    469     case MATCH_LB:
    470       TRACE_INSN (cpu, "lb %s, %" PRIiTW "(%s);",
    471 		  rd_name, i_imm, rs1_name);
    472       store_rd (cpu, rd, EXTEND8 (
    473 	sim_core_read_unaligned_1 (cpu, cpu->pc, read_map,
    474 				   cpu->regs[rs1] + i_imm)));
    475       break;
    476     case MATCH_LBU:
    477       TRACE_INSN (cpu, "lbu %s, %" PRIiTW "(%s);",
    478 		  rd_name, i_imm, rs1_name);
    479       store_rd (cpu, rd,
    480 	sim_core_read_unaligned_1 (cpu, cpu->pc, read_map,
    481 				   cpu->regs[rs1] + i_imm));
    482       break;
    483     case MATCH_SD:
    484       TRACE_INSN (cpu, "sd %s, %" PRIiTW "(%s);",
    485 		  rs2_name, s_imm, rs1_name);
    486       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    487       sim_core_write_unaligned_8 (cpu, cpu->pc, write_map,
    488 				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
    489       break;
    490     case MATCH_SW:
    491       TRACE_INSN (cpu, "sw %s, %" PRIiTW "(%s);",
    492 		  rs2_name, s_imm, rs1_name);
    493       sim_core_write_unaligned_4 (cpu, cpu->pc, write_map,
    494 				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
    495       break;
    496     case MATCH_SH:
    497       TRACE_INSN (cpu, "sh %s, %" PRIiTW "(%s);",
    498 		  rs2_name, s_imm, rs1_name);
    499       sim_core_write_unaligned_2 (cpu, cpu->pc, write_map,
    500 				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
    501       break;
    502     case MATCH_SB:
    503       TRACE_INSN (cpu, "sb %s, %" PRIiTW "(%s);",
    504 		  rs2_name, s_imm, rs1_name);
    505       sim_core_write_unaligned_1 (cpu, cpu->pc, write_map,
    506 				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
    507       break;
    508 
    509     case MATCH_CSRRC:
    510       TRACE_INSN (cpu, "csrrc");
    511       switch (csr)
    512 	{
    513 #define DECLARE_CSR(name, num, ...) \
    514 	case num: \
    515 	  store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
    516 	  store_csr (cpu, #name, num, &cpu->csr.name, \
    517 		     cpu->csr.name & !cpu->regs[rs1]); \
    518 	  break;
    519 #include "opcode/riscv-opc.h"
    520 #undef DECLARE_CSR
    521 	}
    522       break;
    523     case MATCH_CSRRS:
    524       TRACE_INSN (cpu, "csrrs");
    525       switch (csr)
    526 	{
    527 #define DECLARE_CSR(name, num, ...) \
    528 	case num: \
    529 	  store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
    530 	  store_csr (cpu, #name, num, &cpu->csr.name, \
    531 		     cpu->csr.name | cpu->regs[rs1]); \
    532 	  break;
    533 #include "opcode/riscv-opc.h"
    534 #undef DECLARE_CSR
    535 	}
    536       break;
    537     case MATCH_CSRRW:
    538       TRACE_INSN (cpu, "csrrw");
    539       switch (csr)
    540 	{
    541 #define DECLARE_CSR(name, num, ...) \
    542 	case num: \
    543 	  store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
    544 	  store_csr (cpu, #name, num, &cpu->csr.name, cpu->regs[rs1]); \
    545 	  break;
    546 #include "opcode/riscv-opc.h"
    547 #undef DECLARE_CSR
    548 	}
    549       break;
    550 
    551     case MATCH_RDCYCLE:
    552       TRACE_INSN (cpu, "rdcycle %s;", rd_name);
    553       store_rd (cpu, rd, fetch_csr (cpu, "cycle", CSR_CYCLE, &cpu->csr.cycle));
    554       break;
    555     case MATCH_RDCYCLEH:
    556       TRACE_INSN (cpu, "rdcycleh %s;", rd_name);
    557       RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
    558       store_rd (cpu, rd,
    559 		fetch_csr (cpu, "cycleh", CSR_CYCLEH, &cpu->csr.cycleh));
    560       break;
    561     case MATCH_RDINSTRET:
    562       TRACE_INSN (cpu, "rdinstret %s;", rd_name);
    563       store_rd (cpu, rd,
    564 		fetch_csr (cpu, "instret", CSR_INSTRET, &cpu->csr.instret));
    565       break;
    566     case MATCH_RDINSTRETH:
    567       TRACE_INSN (cpu, "rdinstreth %s;", rd_name);
    568       RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
    569       store_rd (cpu, rd,
    570 		fetch_csr (cpu, "instreth", CSR_INSTRETH, &cpu->csr.instreth));
    571       break;
    572     case MATCH_RDTIME:
    573       TRACE_INSN (cpu, "rdtime %s;", rd_name);
    574       store_rd (cpu, rd, fetch_csr (cpu, "time", CSR_TIME, &cpu->csr.time));
    575       break;
    576     case MATCH_RDTIMEH:
    577       TRACE_INSN (cpu, "rdtimeh %s;", rd_name);
    578       RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
    579       store_rd (cpu, rd, fetch_csr (cpu, "timeh", CSR_TIMEH, &cpu->csr.timeh));
    580       break;
    581 
    582     case MATCH_FENCE:
    583       TRACE_INSN (cpu, "fence;");
    584       break;
    585     case MATCH_FENCE_I:
    586       TRACE_INSN (cpu, "fence.i;");
    587       break;
    588     case MATCH_EBREAK:
    589       TRACE_INSN (cpu, "ebreak;");
    590       /* GDB expects us to step over EBREAK.  */
    591       sim_engine_halt (sd, cpu, NULL, cpu->pc + 4, sim_stopped, SIM_SIGTRAP);
    592       break;
    593     case MATCH_ECALL:
    594       TRACE_INSN (cpu, "ecall;");
    595       cpu->a0 = sim_syscall (cpu, cpu->a7, cpu->a0, cpu->a1, cpu->a2, cpu->a3);
    596       break;
    597     default:
    598       TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
    599       sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
    600     }
    601 
    602   return pc;
    603 }
    604 
    605 static uint64_t
    606 mulhu (uint64_t a, uint64_t b)
    607 {
    608 #ifdef HAVE___INT128
    609   return ((__int128)a * b) >> 64;
    610 #else
    611   uint64_t t;
    612   uint32_t y1, y2, y3;
    613   uint64_t a0 = (uint32_t)a, a1 = a >> 32;
    614   uint64_t b0 = (uint32_t)b, b1 = b >> 32;
    615 
    616   t = a1*b0 + ((a0*b0) >> 32);
    617   y1 = t;
    618   y2 = t >> 32;
    619 
    620   t = a0*b1 + y1;
    621   y1 = t;
    622 
    623   t = a1*b1 + y2 + (t >> 32);
    624   y2 = t;
    625   y3 = t >> 32;
    626 
    627   return ((uint64_t)y3 << 32) | y2;
    628 #endif
    629 }
    630 
    631 static uint64_t
    632 mulh (int64_t a, int64_t b)
    633 {
    634   int negate = (a < 0) != (b < 0);
    635   uint64_t res = mulhu (a < 0 ? -a : a, b < 0 ? -b : b);
    636   return negate ? ~res + (a * b == 0) : res;
    637 }
    638 
    639 static uint64_t
    640 mulhsu (int64_t a, uint64_t b)
    641 {
    642   int negate = a < 0;
    643   uint64_t res = mulhu (a < 0 ? -a : a, b);
    644   return negate ? ~res + (a * b == 0) : res;
    645 }
    646 
    647 static sim_cia
    648 execute_m (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
    649 {
    650   SIM_DESC sd = CPU_STATE (cpu);
    651   int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
    652   int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
    653   int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
    654   const char *rd_name = riscv_gpr_names_abi[rd];
    655   const char *rs1_name = riscv_gpr_names_abi[rs1];
    656   const char *rs2_name = riscv_gpr_names_abi[rs2];
    657   unsigned_word tmp, dividend_max;
    658   sim_cia pc = cpu->pc + 4;
    659 
    660   dividend_max = -((unsigned_word) 1 << (WITH_TARGET_WORD_BITSIZE - 1));
    661 
    662   switch (op->match)
    663     {
    664     case MATCH_DIV:
    665       TRACE_INSN (cpu, "div %s, %s, %s;  // %s = %s / %s",
    666 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    667       if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1)
    668 	tmp = dividend_max;
    669       else if (cpu->regs[rs2])
    670 	tmp = (signed_word) cpu->regs[rs1] / (signed_word) cpu->regs[rs2];
    671       else
    672 	tmp = -1;
    673       store_rd (cpu, rd, tmp);
    674       break;
    675     case MATCH_DIVW:
    676       TRACE_INSN (cpu, "divw %s, %s, %s;  // %s = %s / %s",
    677 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    678       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    679       if (EXTEND32 (cpu->regs[rs2]) == -1)
    680 	tmp = 1 << 31;
    681       else if (EXTEND32 (cpu->regs[rs2]))
    682 	tmp = EXTEND32 (cpu->regs[rs1]) / EXTEND32 (cpu->regs[rs2]);
    683       else
    684 	tmp = -1;
    685       store_rd (cpu, rd, EXTEND32 (tmp));
    686       break;
    687     case MATCH_DIVU:
    688       TRACE_INSN (cpu, "divu %s, %s, %s;  // %s = %s / %s",
    689 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    690       if (cpu->regs[rs2])
    691 	store_rd (cpu, rd, (unsigned_word) cpu->regs[rs1]
    692 			   / (unsigned_word) cpu->regs[rs2]);
    693       else
    694 	store_rd (cpu, rd, -1);
    695       break;
    696     case MATCH_DIVUW:
    697       TRACE_INSN (cpu, "divuw %s, %s, %s;  // %s = %s / %s",
    698 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    699       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    700       if ((uint32_t) cpu->regs[rs2])
    701 	tmp = (uint32_t) cpu->regs[rs1] / (uint32_t) cpu->regs[rs2];
    702       else
    703 	tmp = -1;
    704       store_rd (cpu, rd, EXTEND32 (tmp));
    705       break;
    706     case MATCH_MUL:
    707       TRACE_INSN (cpu, "mul %s, %s, %s;  // %s = %s * %s",
    708 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    709       store_rd (cpu, rd, cpu->regs[rs1] * cpu->regs[rs2]);
    710       break;
    711     case MATCH_MULW:
    712       TRACE_INSN (cpu, "mulw %s, %s, %s;  // %s = %s * %s",
    713 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    714       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    715       store_rd (cpu, rd, EXTEND32 ((int32_t) cpu->regs[rs1]
    716 				   * (int32_t) cpu->regs[rs2]));
    717       break;
    718     case MATCH_MULH:
    719       TRACE_INSN (cpu, "mulh %s, %s, %s;  // %s = %s * %s",
    720 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    721       if (RISCV_XLEN (cpu) == 32)
    722 	store_rd (cpu, rd, ((int64_t)(signed_word) cpu->regs[rs1]
    723 			    * (int64_t)(signed_word) cpu->regs[rs2]) >> 32);
    724       else
    725 	store_rd (cpu, rd, mulh (cpu->regs[rs1], cpu->regs[rs2]));
    726       break;
    727     case MATCH_MULHU:
    728       TRACE_INSN (cpu, "mulhu %s, %s, %s;  // %s = %s * %s",
    729 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    730       if (RISCV_XLEN (cpu) == 32)
    731 	store_rd (cpu, rd, ((uint64_t)cpu->regs[rs1]
    732 			    * (uint64_t)cpu->regs[rs2]) >> 32);
    733       else
    734 	store_rd (cpu, rd, mulhu (cpu->regs[rs1], cpu->regs[rs2]));
    735       break;
    736     case MATCH_MULHSU:
    737       TRACE_INSN (cpu, "mulhsu %s, %s, %s;  // %s = %s * %s",
    738 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    739       if (RISCV_XLEN (cpu) == 32)
    740 	store_rd (cpu, rd, ((int64_t)(signed_word) cpu->regs[rs1]
    741 			    * (uint64_t)cpu->regs[rs2]) >> 32);
    742       else
    743 	store_rd (cpu, rd, mulhsu (cpu->regs[rs1], cpu->regs[rs2]));
    744       break;
    745     case MATCH_REM:
    746       TRACE_INSN (cpu, "rem %s, %s, %s;  // %s = %s %% %s",
    747 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    748       if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1)
    749 	tmp = 0;
    750       else if (cpu->regs[rs2])
    751 	tmp = (signed_word) cpu->regs[rs1] % (signed_word) cpu->regs[rs2];
    752       else
    753 	tmp = cpu->regs[rs1];
    754       store_rd (cpu, rd, tmp);
    755       break;
    756     case MATCH_REMW:
    757       TRACE_INSN (cpu, "remw %s, %s, %s;  // %s = %s %% %s",
    758 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    759       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    760       if (EXTEND32 (cpu->regs[rs2]) == -1)
    761 	tmp = 0;
    762       else if (EXTEND32 (cpu->regs[rs2]))
    763 	tmp = EXTEND32 (cpu->regs[rs1]) % EXTEND32 (cpu->regs[rs2]);
    764       else
    765 	tmp = cpu->regs[rs1];
    766       store_rd (cpu, rd, EXTEND32 (tmp));
    767       break;
    768     case MATCH_REMU:
    769       TRACE_INSN (cpu, "remu %s, %s, %s;  // %s = %s %% %s",
    770 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    771       if (cpu->regs[rs2])
    772 	store_rd (cpu, rd, cpu->regs[rs1] % cpu->regs[rs2]);
    773       else
    774 	store_rd (cpu, rd, cpu->regs[rs1]);
    775       break;
    776     case MATCH_REMUW:
    777       TRACE_INSN (cpu, "remuw %s, %s, %s;  // %s = %s %% %s",
    778 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
    779       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    780       if ((uint32_t) cpu->regs[rs2])
    781 	tmp = (uint32_t) cpu->regs[rs1] % (uint32_t) cpu->regs[rs2];
    782       else
    783 	tmp = cpu->regs[rs1];
    784       store_rd (cpu, rd, EXTEND32 (tmp));
    785       break;
    786     default:
    787       TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
    788       sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
    789     }
    790 
    791   return pc;
    792 }
    793 
    794 static sim_cia
    795 execute_a (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
    796 {
    797   SIM_DESC sd = CPU_STATE (cpu);
    798   struct riscv_sim_state *state = RISCV_SIM_STATE (sd);
    799   int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
    800   int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
    801   int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
    802   const char *rd_name = riscv_gpr_names_abi[rd];
    803   const char *rs1_name = riscv_gpr_names_abi[rs1];
    804   const char *rs2_name = riscv_gpr_names_abi[rs2];
    805   struct atomic_mem_reserved_list *amo_prev, *amo_curr;
    806   unsigned_word tmp;
    807   sim_cia pc = cpu->pc + 4;
    808 
    809   /* Handle these two load/store operations specifically.  */
    810   switch (op->match)
    811     {
    812     case MATCH_LR_W:
    813       TRACE_INSN (cpu, "%s %s, (%s);", op->name, rd_name, rs1_name);
    814       store_rd (cpu, rd,
    815 	sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, cpu->regs[rs1]));
    816 
    817       /* Walk the reservation list to find an existing match.  */
    818       amo_curr = state->amo_reserved_list;
    819       while (amo_curr)
    820 	{
    821 	  if (amo_curr->addr == cpu->regs[rs1])
    822 	    goto done;
    823 	  amo_curr = amo_curr->next;
    824 	}
    825 
    826       /* No reservation exists, so add one.  */
    827       amo_curr = xmalloc (sizeof (*amo_curr));
    828       amo_curr->addr = cpu->regs[rs1];
    829       amo_curr->next = state->amo_reserved_list;
    830       state->amo_reserved_list = amo_curr;
    831       goto done;
    832     case MATCH_SC_W:
    833       TRACE_INSN (cpu, "%s %s, %s, (%s);", op->name, rd_name, rs2_name,
    834 		  rs1_name);
    835 
    836       /* Walk the reservation list to find a match.  */
    837       amo_curr = amo_prev = state->amo_reserved_list;
    838       while (amo_curr)
    839 	{
    840 	  if (amo_curr->addr == cpu->regs[rs1])
    841 	    {
    842 	      /* We found a reservation, so operate it.  */
    843 	      sim_core_write_unaligned_4 (cpu, cpu->pc, write_map,
    844 					  cpu->regs[rs1], cpu->regs[rs2]);
    845 	      store_rd (cpu, rd, 0);
    846 	      if (amo_curr == state->amo_reserved_list)
    847 		state->amo_reserved_list = amo_curr->next;
    848 	      else
    849 		amo_prev->next = amo_curr->next;
    850 	      free (amo_curr);
    851 	      goto done;
    852 	    }
    853 	  amo_prev = amo_curr;
    854 	  amo_curr = amo_curr->next;
    855 	}
    856 
    857       /* If we're still here, then no reservation exists, so mark as failed.  */
    858       store_rd (cpu, rd, 1);
    859       goto done;
    860     }
    861 
    862   /* Handle the rest of the atomic insns with common code paths.  */
    863   TRACE_INSN (cpu, "%s %s, %s, (%s);",
    864 	      op->name, rd_name, rs2_name, rs1_name);
    865   if (op->xlen_requirement == 64)
    866     tmp = sim_core_read_unaligned_8 (cpu, cpu->pc, read_map, cpu->regs[rs1]);
    867   else
    868     tmp = EXTEND32 (sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
    869 					       cpu->regs[rs1]));
    870   store_rd (cpu, rd, tmp);
    871 
    872   switch (op->match)
    873     {
    874     case MATCH_AMOADD_D:
    875     case MATCH_AMOADD_W:
    876       tmp = cpu->regs[rd] + cpu->regs[rs2];
    877       break;
    878     case MATCH_AMOAND_D:
    879     case MATCH_AMOAND_W:
    880       tmp = cpu->regs[rd] & cpu->regs[rs2];
    881       break;
    882     case MATCH_AMOMAX_D:
    883     case MATCH_AMOMAX_W:
    884       tmp = max ((signed_word) cpu->regs[rd], (signed_word) cpu->regs[rs2]);
    885       break;
    886     case MATCH_AMOMAXU_D:
    887     case MATCH_AMOMAXU_W:
    888       tmp = max ((unsigned_word) cpu->regs[rd], (unsigned_word) cpu->regs[rs2]);
    889       break;
    890     case MATCH_AMOMIN_D:
    891     case MATCH_AMOMIN_W:
    892       tmp = min ((signed_word) cpu->regs[rd], (signed_word) cpu->regs[rs2]);
    893       break;
    894     case MATCH_AMOMINU_D:
    895     case MATCH_AMOMINU_W:
    896       tmp = min ((unsigned_word) cpu->regs[rd], (unsigned_word) cpu->regs[rs2]);
    897       break;
    898     case MATCH_AMOOR_D:
    899     case MATCH_AMOOR_W:
    900       tmp = cpu->regs[rd] | cpu->regs[rs2];
    901       break;
    902     case MATCH_AMOSWAP_D:
    903     case MATCH_AMOSWAP_W:
    904       tmp = cpu->regs[rs2];
    905       break;
    906     case MATCH_AMOXOR_D:
    907     case MATCH_AMOXOR_W:
    908       tmp = cpu->regs[rd] ^ cpu->regs[rs2];
    909       break;
    910     default:
    911       TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
    912       sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
    913     }
    914 
    915   if (op->xlen_requirement == 64)
    916     sim_core_write_unaligned_8 (cpu, cpu->pc, write_map, cpu->regs[rs1], tmp);
    917   else
    918     sim_core_write_unaligned_4 (cpu, cpu->pc, write_map, cpu->regs[rs1], tmp);
    919 
    920  done:
    921   return pc;
    922 }
    923 
    924 static sim_cia
    925 execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
    926 {
    927   SIM_DESC sd = CPU_STATE (cpu);
    928 
    929   if (op->xlen_requirement == 32)
    930     RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
    931   else if (op->xlen_requirement == 64)
    932     RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
    933 
    934   switch (op->insn_class)
    935     {
    936     case INSN_CLASS_A:
    937       return execute_a (cpu, iw, op);
    938     case INSN_CLASS_I:
    939       return execute_i (cpu, iw, op);
    940     case INSN_CLASS_M:
    941     case INSN_CLASS_ZMMUL:
    942       return execute_m (cpu, iw, op);
    943     default:
    944       TRACE_INSN (cpu, "UNHANDLED EXTENSION: %d", op->insn_class);
    945       sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
    946     }
    947 
    948   return cpu->pc + riscv_insn_length (iw);
    949 }
    950 
    951 /* Decode & execute a single instruction.  */
    952 void step_once (SIM_CPU *cpu)
    953 {
    954   SIM_DESC sd = CPU_STATE (cpu);
    955   unsigned_word iw;
    956   unsigned int len;
    957   sim_cia pc = cpu->pc;
    958   const struct riscv_opcode *op;
    959   int xlen = RISCV_XLEN (cpu);
    960 
    961   if (TRACE_ANY_P (cpu))
    962     trace_prefix (sd, cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
    963 		  NULL, 0, " "); /* Use a space for gcc warnings.  */
    964 
    965   iw = sim_core_read_aligned_2 (cpu, pc, exec_map, pc);
    966 
    967   /* Reject non-32-bit opcodes first.  */
    968   len = riscv_insn_length (iw);
    969   if (len != 4)
    970     {
    971       sim_io_printf (sd, "sim: bad insn len %#x @ %#" PRIxTA ": %#" PRIxTW "\n",
    972 		     len, pc, iw);
    973       sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
    974     }
    975 
    976   iw |= ((unsigned_word) sim_core_read_aligned_2 (
    977     cpu, pc, exec_map, pc + 2) << 16);
    978 
    979   TRACE_CORE (cpu, "0x%08" PRIxTW, iw);
    980 
    981   op = riscv_hash[OP_HASH_IDX (iw)];
    982   if (!op)
    983     sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
    984 
    985   /* NB: Same loop logic as riscv_disassemble_insn.  */
    986   for (; op->name; op++)
    987     {
    988       /* Does the opcode match?  */
    989       if (! op->match_func (op, iw))
    990 	continue;
    991       /* Is this a pseudo-instruction and may we print it as such?  */
    992       if (op->pinfo & INSN_ALIAS)
    993 	continue;
    994       /* Is this instruction restricted to a certain value of XLEN?  */
    995       if (op->xlen_requirement != 0 && op->xlen_requirement != xlen)
    996 	continue;
    997 
    998       /* It's a match.  */
    999       pc = execute_one (cpu, iw, op);
   1000       break;
   1001     }
   1002 
   1003   /* TODO: Handle overflow into high 32 bits.  */
   1004   /* TODO: Try to use a common counter and only update on demand (reads).  */
   1005   ++cpu->csr.cycle;
   1006   ++cpu->csr.instret;
   1007 
   1008   cpu->pc = pc;
   1009 }
   1010 
   1011 /* Return the program counter for this cpu. */
   1013 static sim_cia
   1014 pc_get (sim_cpu *cpu)
   1015 {
   1016   return cpu->pc;
   1017 }
   1018 
   1019 /* Set the program counter for this cpu to the new pc value. */
   1020 static void
   1021 pc_set (sim_cpu *cpu, sim_cia pc)
   1022 {
   1023   cpu->pc = pc;
   1024 }
   1025 
   1026 static int
   1027 reg_fetch (sim_cpu *cpu, int rn, void *buf, int len)
   1028 {
   1029   if (len <= 0 || len > sizeof (unsigned_word))
   1030     return -1;
   1031 
   1032   switch (rn)
   1033     {
   1034     case SIM_RISCV_ZERO_REGNUM:
   1035       memset (buf, 0, len);
   1036       return len;
   1037     case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM:
   1038       memcpy (buf, &cpu->regs[rn], len);
   1039       return len;
   1040     case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM:
   1041       memcpy (buf, &cpu->fpregs[rn - SIM_RISCV_FIRST_FP_REGNUM], len);
   1042       return len;
   1043     case SIM_RISCV_PC_REGNUM:
   1044       memcpy (buf, &cpu->pc, len);
   1045       return len;
   1046 
   1047 #define DECLARE_CSR(name, num, ...) \
   1048     case SIM_RISCV_ ## num ## _REGNUM: \
   1049       memcpy (buf, &cpu->csr.name, len); \
   1050       return len;
   1051 #include "opcode/riscv-opc.h"
   1052 #undef DECLARE_CSR
   1053 
   1054     default:
   1055       return -1;
   1056     }
   1057 }
   1058 
   1059 static int
   1060 reg_store (sim_cpu *cpu, int rn, const void *buf, int len)
   1061 {
   1062   if (len <= 0 || len > sizeof (unsigned_word))
   1063     return -1;
   1064 
   1065   switch (rn)
   1066     {
   1067     case SIM_RISCV_ZERO_REGNUM:
   1068       /* Ignore writes.  */
   1069       return len;
   1070     case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM:
   1071       memcpy (&cpu->regs[rn], buf, len);
   1072       return len;
   1073     case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM:
   1074       memcpy (&cpu->fpregs[rn - SIM_RISCV_FIRST_FP_REGNUM], buf, len);
   1075       return len;
   1076     case SIM_RISCV_PC_REGNUM:
   1077       memcpy (&cpu->pc, buf, len);
   1078       return len;
   1079 
   1080 #define DECLARE_CSR(name, num, ...) \
   1081     case SIM_RISCV_ ## num ## _REGNUM: \
   1082       memcpy (&cpu->csr.name, buf, len); \
   1083       return len;
   1084 #include "opcode/riscv-opc.h"
   1085 #undef DECLARE_CSR
   1086 
   1087     default:
   1088       return -1;
   1089     }
   1090 }
   1091 
   1092 /* Initialize the state for a single cpu.  Usuaully this involves clearing all
   1093    registers back to their reset state.  Should also hook up the fetch/store
   1094    helper functions too.  */
   1095 void
   1096 initialize_cpu (SIM_DESC sd, SIM_CPU *cpu, int mhartid)
   1097 {
   1098   const char *extensions;
   1099   int i;
   1100 
   1101   memset (cpu->regs, 0, sizeof (cpu->regs));
   1102 
   1103   CPU_PC_FETCH (cpu) = pc_get;
   1104   CPU_PC_STORE (cpu) = pc_set;
   1105   CPU_REG_FETCH (cpu) = reg_fetch;
   1106   CPU_REG_STORE (cpu) = reg_store;
   1107 
   1108   if (!riscv_hash[0])
   1109     {
   1110       const struct riscv_opcode *op;
   1111 
   1112       for (op = riscv_opcodes; op->name; op++)
   1113 	if (!riscv_hash[OP_HASH_IDX (op->match)])
   1114 	  riscv_hash[OP_HASH_IDX (op->match)] = op;
   1115     }
   1116 
   1117   cpu->csr.misa = 0;
   1118   /* RV32 sets this field to 0, and we don't really support RV128 yet.  */
   1119   if (RISCV_XLEN (cpu) == 64)
   1120     cpu->csr.misa |= (uint64_t)2 << 62;
   1121 
   1122   /* Skip the leading "rv" prefix and the two numbers.  */
   1123   extensions = MODEL_NAME (CPU_MODEL (cpu)) + 4;
   1124   for (i = 0; i < 26; ++i)
   1125     {
   1126       char ext = 'A' + i;
   1127 
   1128       if (ext == 'X')
   1129 	continue;
   1130       else if (strchr (extensions, ext) != NULL)
   1131 	{
   1132 	  if (ext == 'G')
   1133 	    cpu->csr.misa |= 0x1129;  /* G = IMAFD.  */
   1134 	  else
   1135 	    cpu->csr.misa |= (1 << i);
   1136 	}
   1137     }
   1138 
   1139   cpu->csr.mimpid = 0x8000;
   1140   cpu->csr.mhartid = mhartid;
   1141 }
   1142 
   1143 /* Some utils don't like having a NULL environ.  */
   1145 static const char * const simple_env[] = { "HOME=/", "PATH=/bin", NULL };
   1146 
   1147 /* Count the number of arguments in an argv.  */
   1148 static int
   1149 count_argv (const char * const *argv)
   1150 {
   1151   int i;
   1152 
   1153   if (!argv)
   1154     return -1;
   1155 
   1156   for (i = 0; argv[i] != NULL; ++i)
   1157     continue;
   1158   return i;
   1159 }
   1160 
   1161 void
   1162 initialize_env (SIM_DESC sd, const char * const *argv, const char * const *env)
   1163 {
   1164   SIM_CPU *cpu = STATE_CPU (sd, 0);
   1165   int i;
   1166   int argc, argv_flat;
   1167   int envc, env_flat;
   1168   address_word sp, sp_flat;
   1169   unsigned char null[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
   1170 
   1171   /* Figure out how many bytes the argv strings take up.  */
   1172   argc = count_argv (argv);
   1173   if (argc == -1)
   1174     argc = 0;
   1175   argv_flat = argc; /* NUL bytes.  */
   1176   for (i = 0; i < argc; ++i)
   1177     argv_flat += strlen (argv[i]);
   1178 
   1179   /* Figure out how many bytes the environ strings take up.  */
   1180   if (!env)
   1181     env = simple_env;
   1182   envc = count_argv (env);
   1183   env_flat = envc; /* NUL bytes.  */
   1184   for (i = 0; i < envc; ++i)
   1185     env_flat += strlen (env[i]);
   1186 
   1187   /* Make space for the strings themselves.  */
   1188   sp_flat = (DEFAULT_MEM_SIZE - argv_flat - env_flat) & -sizeof (address_word);
   1189   /* Then the pointers to the strings.  */
   1190   sp = sp_flat - ((argc + 1 + envc + 1) * sizeof (address_word));
   1191   /* Then the argc.  */
   1192   sp -= sizeof (unsigned_word);
   1193 
   1194   /* Set up the regs the libgloss crt0 expects.  */
   1195   cpu->a0 = argc;
   1196   cpu->sp = sp;
   1197 
   1198   /* First push the argc value.  */
   1199   sim_write (sd, sp, &argc, sizeof (unsigned_word));
   1200   sp += sizeof (unsigned_word);
   1201 
   1202   /* Then the actual argv strings so we know where to point argv[].  */
   1203   for (i = 0; i < argc; ++i)
   1204     {
   1205       unsigned len = strlen (argv[i]) + 1;
   1206       sim_write (sd, sp_flat, argv[i], len);
   1207       sim_write (sd, sp, &sp_flat, sizeof (address_word));
   1208       sp_flat += len;
   1209       sp += sizeof (address_word);
   1210     }
   1211   sim_write (sd, sp, null, sizeof (address_word));
   1212   sp += sizeof (address_word);
   1213 
   1214   /* Then the actual env strings so we know where to point env[].  */
   1215   for (i = 0; i < envc; ++i)
   1216     {
   1217       unsigned len = strlen (env[i]) + 1;
   1218       sim_write (sd, sp_flat, env[i], len);
   1219       sim_write (sd, sp, &sp_flat, sizeof (address_word));
   1220       sp_flat += len;
   1221       sp += sizeof (address_word);
   1222     }
   1223 }
   1224