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