]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/riscv/sim-main.c
sim: split sim-signal.h include out
[thirdparty/binutils-gdb.git] / sim / riscv / sim-main.c
CommitLineData
b9249c46
MF
1/* RISC-V simulator.
2
3 Copyright (C) 2005-2021 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
6df01ab8
MF
24/* This must come before any other includes. */
25#include "defs.h"
b9249c46
MF
26
27#include <inttypes.h>
28#include <time.h>
29
30#include "sim-main.h"
1fef66b0 31#include "sim-signal.h"
b9249c46
MF
32#include "sim-syscall.h"
33
34#include "opcode/riscv.h"
35
04b4939b
MF
36#include "gdb/sim-riscv.h"
37
b9249c46
MF
38#include "targ-vals.h"
39\f
40#define TRACE_REG(cpu, reg) \
41 TRACE_REGISTER (cpu, "wrote %s = %#" PRIxTW, riscv_gpr_names_abi[reg], \
42 cpu->regs[reg])
43\f
44static 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
67static INLINE void
68store_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
77static INLINE unsigned_word
78fetch_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
94static INLINE void
95store_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
133static inline unsigned_word
134ashiftrt (unsigned_word val, unsigned_word shift)
135{
136 unsigned32 sign = (val & 0x80000000) ? ~(0xfffffffful >> shift) : 0;
137 return (val >> shift) | sign;
138}
139
140static inline unsigned_word
141ashiftrt64 (unsigned_word val, unsigned_word shift)
142{
143 unsigned64 sign =
144 (val & 0x8000000000000000ull) ? ~(0xffffffffffffffffull >> shift) : 0;
145 return (val >> shift) | sign;
146}
147
148static sim_cia
149execute_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 ((unsigned64) iw);
161 unsigned_word s_imm = EXTRACT_STYPE_IMM (iw);
5a9f5403 162 unsigned_word sb_imm = EXTRACT_BTYPE_IMM (iw);
b9249c46
MF
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 (unsigned32) 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 ((unsigned32) 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 (unsigned32) 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 ((unsigned32) 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 ((signed32) 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 ((signed32) 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,
5a9f5403 421 EXTRACT_JTYPE_IMM (iw));
b9249c46 422 store_rd (cpu, rd, cpu->pc + 4);
5a9f5403 423 pc = cpu->pc + EXTRACT_JTYPE_IMM (iw);
b9249c46
MF
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_SBREAK:
589 TRACE_INSN (cpu, "sbreak;");
590 /* GDB expects us to step over SBREAK. */
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
605static unsigned64
606mulhu (unsigned64 a, unsigned64 b)
607{
79633c12 608#ifdef HAVE___INT128
b9249c46
MF
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
631static unsigned64
632mulh (signed64 a, signed64 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
639static unsigned64
640mulhsu (signed64 a, unsigned64 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
647static sim_cia
648execute_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 ((unsigned32) cpu->regs[rs2])
701 tmp = (unsigned32) cpu->regs[rs1] / (unsigned32) 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 ((signed32) cpu->regs[rs1]
716 * (signed32) 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, ((signed64)(signed_word) cpu->regs[rs1]
723 * (signed64)(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, ((unsigned64)cpu->regs[rs1]
732 * (unsigned64)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, ((signed64)(signed_word) cpu->regs[rs1]
741 * (unsigned64)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 ((unsigned32) cpu->regs[rs2])
781 tmp = (unsigned32) cpu->regs[rs1] % (unsigned32) 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
b9249c46
MF
794static sim_cia
795execute_a (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
796{
797 SIM_DESC sd = CPU_STATE (cpu);
10c23a2c 798 struct riscv_sim_state *state = RISCV_SIM_STATE (sd);
b9249c46
MF
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. */
10c23a2c 818 amo_curr = state->amo_reserved_list;
b9249c46
MF
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];
10c23a2c
MF
829 amo_curr->next = state->amo_reserved_list;
830 state->amo_reserved_list = amo_curr;
b9249c46
MF
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. */
10c23a2c 837 amo_curr = amo_prev = state->amo_reserved_list;
b9249c46
MF
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);
10c23a2c
MF
846 if (amo_curr == state->amo_reserved_list)
847 state->amo_reserved_list = amo_curr->next;
b9249c46
MF
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:
2045d9d1 884 tmp = max ((signed_word) cpu->regs[rd], (signed_word) cpu->regs[rs2]);
b9249c46
MF
885 break;
886 case MATCH_AMOMAXU_D:
887 case MATCH_AMOMAXU_W:
2045d9d1 888 tmp = max ((unsigned_word) cpu->regs[rd], (unsigned_word) cpu->regs[rs2]);
b9249c46
MF
889 break;
890 case MATCH_AMOMIN_D:
891 case MATCH_AMOMIN_W:
2045d9d1 892 tmp = min ((signed_word) cpu->regs[rd], (signed_word) cpu->regs[rs2]);
b9249c46
MF
893 break;
894 case MATCH_AMOMINU_D:
895 case MATCH_AMOMINU_W:
2045d9d1 896 tmp = min ((unsigned_word) cpu->regs[rd], (unsigned_word) cpu->regs[rs2]);
b9249c46
MF
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
924static sim_cia
925execute_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 return execute_m (cpu, iw, op);
942 default:
943 TRACE_INSN (cpu, "UNHANDLED EXTENSION: %d", op->insn_class);
944 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
945 }
946
947 return cpu->pc + riscv_insn_length (iw);
948}
949
950/* Decode & execute a single instruction. */
951void step_once (SIM_CPU *cpu)
952{
953 SIM_DESC sd = CPU_STATE (cpu);
954 unsigned_word iw;
955 unsigned int len;
956 sim_cia pc = cpu->pc;
957 const struct riscv_opcode *op;
958 int xlen = RISCV_XLEN (cpu);
959
960 if (TRACE_ANY_P (cpu))
961 trace_prefix (sd, cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
962 NULL, 0, " "); /* Use a space for gcc warnings. */
963
964 iw = sim_core_read_aligned_2 (cpu, pc, exec_map, pc);
965
966 /* Reject non-32-bit opcodes first. */
967 len = riscv_insn_length (iw);
968 if (len != 4)
969 {
970 sim_io_printf (sd, "sim: bad insn len %#x @ %#" PRIxTA ": %#" PRIxTW "\n",
971 len, pc, iw);
972 sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
973 }
974
975 iw |= ((unsigned_word) sim_core_read_aligned_2 (
976 cpu, pc, exec_map, pc + 2) << 16);
977
978 TRACE_CORE (cpu, "0x%08" PRIxTW, iw);
979
980 op = riscv_hash[OP_HASH_IDX (iw)];
981 if (!op)
982 sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
983
984 /* NB: Same loop logic as riscv_disassemble_insn. */
985 for (; op->name; op++)
986 {
987 /* Does the opcode match? */
988 if (! op->match_func (op, iw))
989 continue;
990 /* Is this a pseudo-instruction and may we print it as such? */
991 if (op->pinfo & INSN_ALIAS)
992 continue;
993 /* Is this instruction restricted to a certain value of XLEN? */
994 if (op->xlen_requirement != 0 && op->xlen_requirement != xlen)
995 continue;
996
997 /* It's a match. */
998 pc = execute_one (cpu, iw, op);
999 break;
1000 }
1001
1002 /* TODO: Handle overflow into high 32 bits. */
1003 /* TODO: Try to use a common counter and only update on demand (reads). */
1004 ++cpu->csr.cycle;
1005 ++cpu->csr.instret;
1006
1007 cpu->pc = pc;
1008}
1009\f
1010/* Return the program counter for this cpu. */
1011static sim_cia
1012pc_get (sim_cpu *cpu)
1013{
1014 return cpu->pc;
1015}
1016
1017/* Set the program counter for this cpu to the new pc value. */
1018static void
1019pc_set (sim_cpu *cpu, sim_cia pc)
1020{
1021 cpu->pc = pc;
1022}
1023
04b4939b
MF
1024static int
1025reg_fetch (sim_cpu *cpu, int rn, unsigned char *buf, int len)
1026{
1027 if (len <= 0 || len > sizeof (unsigned_word))
1028 return -1;
1029
1030 switch (rn)
1031 {
1032 case SIM_RISCV_ZERO_REGNUM:
1033 memset (buf, 0, len);
1034 return len;
1035 case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM:
1036 memcpy (buf, &cpu->regs[rn], len);
1037 return len;
1038 case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM:
1039 memcpy (buf, &cpu->fpregs[rn - SIM_RISCV_FIRST_FP_REGNUM], len);
1040 return len;
1041 case SIM_RISCV_PC_REGNUM:
1042 memcpy (buf, &cpu->pc, len);
1043 return len;
1044
1045#define DECLARE_CSR(name, num, ...) \
1046 case SIM_RISCV_ ## num ## _REGNUM: \
1047 memcpy (buf, &cpu->csr.name, len); \
1048 return len;
1049#include "opcode/riscv-opc.h"
1050#undef DECLARE_CSR
1051
1052 default:
1053 return -1;
1054 }
1055}
1056
1057static int
1058reg_store (sim_cpu *cpu, int rn, unsigned char *buf, int len)
1059{
1060 if (len <= 0 || len > sizeof (unsigned_word))
1061 return -1;
1062
1063 switch (rn)
1064 {
1065 case SIM_RISCV_ZERO_REGNUM:
1066 /* Ignore writes. */
1067 return len;
1068 case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM:
1069 memcpy (&cpu->regs[rn], buf, len);
1070 return len;
1071 case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM:
1072 memcpy (&cpu->fpregs[rn - SIM_RISCV_FIRST_FP_REGNUM], buf, len);
1073 return len;
1074 case SIM_RISCV_PC_REGNUM:
1075 memcpy (&cpu->pc, buf, len);
1076 return len;
1077
1078#define DECLARE_CSR(name, num, ...) \
1079 case SIM_RISCV_ ## num ## _REGNUM: \
1080 memcpy (&cpu->csr.name, buf, len); \
1081 return len;
1082#include "opcode/riscv-opc.h"
1083#undef DECLARE_CSR
1084
1085 default:
1086 return -1;
1087 }
1088}
1089
b9249c46
MF
1090/* Initialize the state for a single cpu. Usuaully this involves clearing all
1091 registers back to their reset state. Should also hook up the fetch/store
1092 helper functions too. */
1093void
1094initialize_cpu (SIM_DESC sd, SIM_CPU *cpu, int mhartid)
1095{
1096 const char *extensions;
1097 int i;
1098
1099 memset (cpu->regs, 0, sizeof (cpu->regs));
1100
1101 CPU_PC_FETCH (cpu) = pc_get;
1102 CPU_PC_STORE (cpu) = pc_set;
04b4939b
MF
1103 CPU_REG_FETCH (cpu) = reg_fetch;
1104 CPU_REG_STORE (cpu) = reg_store;
b9249c46
MF
1105
1106 if (!riscv_hash[0])
1107 {
1108 const struct riscv_opcode *op;
1109
1110 for (op = riscv_opcodes; op->name; op++)
1111 if (!riscv_hash[OP_HASH_IDX (op->match)])
1112 riscv_hash[OP_HASH_IDX (op->match)] = op;
1113 }
1114
1115 cpu->csr.misa = 0;
1116 /* RV32 sets this field to 0, and we don't really support RV128 yet. */
1117 if (RISCV_XLEN (cpu) == 64)
1118 cpu->csr.misa |= (unsigned64)2 << 62;
1119
1120 /* Skip the leading "rv" prefix and the two numbers. */
1121 extensions = MODEL_NAME (CPU_MODEL (cpu)) + 4;
1122 for (i = 0; i < 26; ++i)
1123 {
1124 char ext = 'A' + i;
1125
1126 if (ext == 'X')
1127 continue;
1128 else if (strchr (extensions, ext) != NULL)
1129 {
1130 if (ext == 'G')
1131 cpu->csr.misa |= 0x1129; /* G = IMAFD. */
1132 else
1133 cpu->csr.misa |= (1 << i);
1134 }
1135 }
1136
1137 cpu->csr.mimpid = 0x8000;
1138 cpu->csr.mhartid = mhartid;
1139}
1140\f
1141/* Some utils don't like having a NULL environ. */
1142static const char * const simple_env[] = { "HOME=/", "PATH=/bin", NULL };
1143
1144/* Count the number of arguments in an argv. */
1145static int
1146count_argv (const char * const *argv)
1147{
1148 int i;
1149
1150 if (!argv)
1151 return -1;
1152
1153 for (i = 0; argv[i] != NULL; ++i)
1154 continue;
1155 return i;
1156}
1157
1158void
1159initialize_env (SIM_DESC sd, const char * const *argv, const char * const *env)
1160{
1161 SIM_CPU *cpu = STATE_CPU (sd, 0);
1162 int i;
1163 int argc, argv_flat;
1164 int envc, env_flat;
1165 address_word sp, sp_flat;
1166 unsigned char null[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
1167
1168 /* Figure out how many bytes the argv strings take up. */
1169 argc = count_argv (argv);
1170 if (argc == -1)
1171 argc = 0;
1172 argv_flat = argc; /* NUL bytes. */
1173 for (i = 0; i < argc; ++i)
1174 argv_flat += strlen (argv[i]);
1175
1176 /* Figure out how many bytes the environ strings take up. */
1177 if (!env)
1178 env = simple_env;
1179 envc = count_argv (env);
1180 env_flat = envc; /* NUL bytes. */
1181 for (i = 0; i < envc; ++i)
1182 env_flat += strlen (env[i]);
1183
1184 /* Make space for the strings themselves. */
1185 sp_flat = (DEFAULT_MEM_SIZE - argv_flat - env_flat) & -sizeof (address_word);
1186 /* Then the pointers to the strings. */
1187 sp = sp_flat - ((argc + 1 + envc + 1) * sizeof (address_word));
1188 /* Then the argc. */
1189 sp -= sizeof (unsigned_word);
1190
1191 /* Set up the regs the libgloss crt0 expects. */
1192 cpu->a0 = argc;
1193 cpu->sp = sp;
1194
1195 /* First push the argc value. */
1196 sim_write (sd, sp, (void *)&argc, sizeof (unsigned_word));
1197 sp += sizeof (unsigned_word);
1198
1199 /* Then the actual argv strings so we know where to point argv[]. */
1200 for (i = 0; i < argc; ++i)
1201 {
1202 unsigned len = strlen (argv[i]) + 1;
1203 sim_write (sd, sp_flat, (void *)argv[i], len);
1204 sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word));
1205 sp_flat += len;
1206 sp += sizeof (address_word);
1207 }
1208 sim_write (sd, sp, null, sizeof (address_word));
1209 sp += sizeof (address_word);
1210
1211 /* Then the actual env strings so we know where to point env[]. */
1212 for (i = 0; i < envc; ++i)
1213 {
1214 unsigned len = strlen (env[i]) + 1;
1215 sim_write (sd, sp_flat, (void *)env[i], len);
1216 sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word));
1217 sp_flat += len;
1218 sp += sizeof (address_word);
1219 }
1220}