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