sim: riscv: new port
[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 "targ-vals.h"
35 \f
36 #define TRACE_REG(cpu, reg) \
37 TRACE_REGISTER (cpu, "wrote %s = %#" PRIxTW, riscv_gpr_names_abi[reg], \
38 cpu->regs[reg])
39 \f
40 static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
41 #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : 0x7f))
42
43 #define RISCV_ASSERT_RV32(cpu, fmt, args...) \
44 do { \
45 if (RISCV_XLEN (cpu) != 32) \
46 { \
47 SIM_DESC sd = CPU_STATE (cpu); \
48 TRACE_INSN (cpu, "RV32I-only " fmt, ## args); \
49 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
50 } \
51 } while (0)
52
53 #define RISCV_ASSERT_RV64(cpu, fmt, args...) \
54 do { \
55 if (RISCV_XLEN (cpu) != 64) \
56 { \
57 SIM_DESC sd = CPU_STATE (cpu); \
58 TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \
59 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
60 } \
61 } while (0)
62
63 static INLINE void
64 store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
65 {
66 if (rd)
67 {
68 cpu->regs[rd] = val;
69 TRACE_REG (cpu, rd);
70 }
71 }
72
73 static INLINE unsigned_word
74 fetch_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg)
75 {
76 /* Handle pseudo registers. */
77 switch (csr)
78 {
79 /* Allow certain registers only in respective modes. */
80 case CSR_CYCLEH:
81 case CSR_INSTRETH:
82 case CSR_TIMEH:
83 RISCV_ASSERT_RV32 (cpu, "CSR: %s", name);
84 break;
85 }
86
87 return *reg;
88 }
89
90 static INLINE void
91 store_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg,
92 unsigned_word val)
93 {
94 switch (csr)
95 {
96 /* These are pseudo registers that modify sub-fields of fcsr. */
97 case CSR_FRM:
98 val &= 0x7;
99 *reg = val;
100 cpu->csr.fcsr = (cpu->csr.fcsr & ~0xe0) | (val << 5);
101 break;
102 case CSR_FFLAGS:
103 val &= 0x1f;
104 *reg = val;
105 cpu->csr.fcsr = (cpu->csr.fcsr & ~0x1f) | val;
106 break;
107 /* Keep the sub-fields in sync. */
108 case CSR_FCSR:
109 *reg = val;
110 cpu->csr.frm = (val >> 5) & 0x7;
111 cpu->csr.fflags = val & 0x1f;
112 break;
113
114 /* Allow certain registers only in respective modes. */
115 case CSR_CYCLEH:
116 case CSR_INSTRETH:
117 case CSR_TIMEH:
118 RISCV_ASSERT_RV32 (cpu, "CSR: %s", name);
119
120 /* All the rest are immutable. */
121 default:
122 val = *reg;
123 break;
124 }
125
126 TRACE_REGISTER (cpu, "wrote CSR %s = %#" PRIxTW, name, val);
127 }
128
129 static inline unsigned_word
130 ashiftrt (unsigned_word val, unsigned_word shift)
131 {
132 unsigned32 sign = (val & 0x80000000) ? ~(0xfffffffful >> shift) : 0;
133 return (val >> shift) | sign;
134 }
135
136 static inline unsigned_word
137 ashiftrt64 (unsigned_word val, unsigned_word shift)
138 {
139 unsigned64 sign =
140 (val & 0x8000000000000000ull) ? ~(0xffffffffffffffffull >> shift) : 0;
141 return (val >> shift) | sign;
142 }
143
144 static sim_cia
145 execute_i (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
146 {
147 SIM_DESC sd = CPU_STATE (cpu);
148 int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
149 int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
150 int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
151 const char *rd_name = riscv_gpr_names_abi[rd];
152 const char *rs1_name = riscv_gpr_names_abi[rs1];
153 const char *rs2_name = riscv_gpr_names_abi[rs2];
154 unsigned int csr = (iw >> OP_SH_CSR) & OP_MASK_CSR;
155 unsigned_word i_imm = EXTRACT_ITYPE_IMM (iw);
156 unsigned_word u_imm = EXTRACT_UTYPE_IMM ((unsigned64) iw);
157 unsigned_word s_imm = EXTRACT_STYPE_IMM (iw);
158 unsigned_word sb_imm = EXTRACT_SBTYPE_IMM (iw);
159 unsigned_word shamt_imm = ((iw >> OP_SH_SHAMT) & OP_MASK_SHAMT);
160 unsigned_word tmp;
161 sim_cia pc = cpu->pc + 4;
162
163 TRACE_EXTRACT (cpu,
164 "rd:%-2i:%-4s "
165 "rs1:%-2i:%-4s %0*" PRIxTW " "
166 "rs2:%-2i:%-4s %0*" PRIxTW " "
167 "match:%#x mask:%#x",
168 rd, rd_name,
169 rs1, rs1_name, (int) sizeof (unsigned_word) * 2, cpu->regs[rs1],
170 rs2, rs2_name, (int) sizeof (unsigned_word) * 2, cpu->regs[rs2],
171 (unsigned) op->match, (unsigned) op->mask);
172
173 switch (op->match)
174 {
175 case MATCH_ADD:
176 TRACE_INSN (cpu, "add %s, %s, %s; // %s = %s + %s",
177 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
178 store_rd (cpu, rd, cpu->regs[rs1] + cpu->regs[rs2]);
179 break;
180 case MATCH_ADDW:
181 TRACE_INSN (cpu, "addw %s, %s, %s; // %s = %s + %s",
182 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
183 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
184 store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + cpu->regs[rs2]));
185 break;
186 case MATCH_ADDI:
187 TRACE_INSN (cpu, "addi %s, %s, %#" PRIxTW "; // %s = %s + %#" PRIxTW,
188 rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
189 store_rd (cpu, rd, cpu->regs[rs1] + i_imm);
190 break;
191 case MATCH_ADDIW:
192 TRACE_INSN (cpu, "addiw %s, %s, %#" PRIxTW "; // %s = %s + %#" PRIxTW,
193 rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
194 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
195 store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + i_imm));
196 break;
197 case MATCH_AND:
198 TRACE_INSN (cpu, "and %s, %s, %s; // %s = %s & %s",
199 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
200 store_rd (cpu, rd, cpu->regs[rs1] & cpu->regs[rs2]);
201 break;
202 case MATCH_ANDI:
203 TRACE_INSN (cpu, "andi %s, %s, %" PRIiTW "; // %s = %s & %#" PRIxTW,
204 rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
205 store_rd (cpu, rd, cpu->regs[rs1] & i_imm);
206 break;
207 case MATCH_OR:
208 TRACE_INSN (cpu, "or %s, %s, %s; // %s = %s | %s",
209 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
210 store_rd (cpu, rd, cpu->regs[rs1] | cpu->regs[rs2]);
211 break;
212 case MATCH_ORI:
213 TRACE_INSN (cpu, "ori %s, %s, %" PRIiTW "; // %s = %s | %#" PRIxTW,
214 rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
215 store_rd (cpu, rd, cpu->regs[rs1] | i_imm);
216 break;
217 case MATCH_XOR:
218 TRACE_INSN (cpu, "xor %s, %s, %s; // %s = %s ^ %s",
219 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
220 store_rd (cpu, rd, cpu->regs[rs1] ^ cpu->regs[rs2]);
221 break;
222 case MATCH_XORI:
223 TRACE_INSN (cpu, "xori %s, %s, %" PRIiTW "; // %s = %s ^ %#" PRIxTW,
224 rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
225 store_rd (cpu, rd, cpu->regs[rs1] ^ i_imm);
226 break;
227 case MATCH_SUB:
228 TRACE_INSN (cpu, "sub %s, %s, %s; // %s = %s - %s",
229 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
230 store_rd (cpu, rd, cpu->regs[rs1] - cpu->regs[rs2]);
231 break;
232 case MATCH_SUBW:
233 TRACE_INSN (cpu, "subw %s, %s, %s; // %s = %s - %s",
234 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
235 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
236 store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] - cpu->regs[rs2]));
237 break;
238 case MATCH_LUI:
239 TRACE_INSN (cpu, "lui %s, %#" PRIxTW ";", rd_name, u_imm);
240 store_rd (cpu, rd, u_imm);
241 break;
242 case MATCH_SLL:
243 TRACE_INSN (cpu, "sll %s, %s, %s; // %s = %s << %s",
244 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
245 u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f;
246 store_rd (cpu, rd, cpu->regs[rs1] << (cpu->regs[rs2] & u_imm));
247 break;
248 case MATCH_SLLW:
249 TRACE_INSN (cpu, "sllw %s, %s, %s; // %s = %s << %s",
250 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
251 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
252 store_rd (cpu, rd, EXTEND32 (
253 (unsigned32) cpu->regs[rs1] << (cpu->regs[rs2] & 0x1f)));
254 break;
255 case MATCH_SLLI:
256 TRACE_INSN (cpu, "slli %s, %s, %" PRIiTW "; // %s = %s << %#" PRIxTW,
257 rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
258 if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f)
259 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
260 store_rd (cpu, rd, cpu->regs[rs1] << shamt_imm);
261 break;
262 case MATCH_SLLIW:
263 TRACE_INSN (cpu, "slliw %s, %s, %" PRIiTW "; // %s = %s << %#" PRIxTW,
264 rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
265 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
266 store_rd (cpu, rd, EXTEND32 ((unsigned32) cpu->regs[rs1] << shamt_imm));
267 break;
268 case MATCH_SRL:
269 TRACE_INSN (cpu, "srl %s, %s, %s; // %s = %s >> %s",
270 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
271 u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f;
272 store_rd (cpu, rd, cpu->regs[rs1] >> (cpu->regs[rs2] & u_imm));
273 break;
274 case MATCH_SRLW:
275 TRACE_INSN (cpu, "srlw %s, %s, %s; // %s = %s >> %s",
276 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
277 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
278 store_rd (cpu, rd, EXTEND32 (
279 (unsigned32) cpu->regs[rs1] >> (cpu->regs[rs2] & 0x1f)));
280 break;
281 case MATCH_SRLI:
282 TRACE_INSN (cpu, "srli %s, %s, %" PRIiTW "; // %s = %s >> %#" PRIxTW,
283 rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
284 if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f)
285 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
286 store_rd (cpu, rd, cpu->regs[rs1] >> shamt_imm);
287 break;
288 case MATCH_SRLIW:
289 TRACE_INSN (cpu, "srliw %s, %s, %" PRIiTW "; // %s = %s >> %#" PRIxTW,
290 rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
291 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
292 store_rd (cpu, rd, EXTEND32 ((unsigned32) cpu->regs[rs1] >> shamt_imm));
293 break;
294 case MATCH_SRA:
295 TRACE_INSN (cpu, "sra %s, %s, %s; // %s = %s >>> %s",
296 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
297 if (RISCV_XLEN (cpu) == 32)
298 tmp = ashiftrt (cpu->regs[rs1], cpu->regs[rs2] & 0x1f);
299 else
300 tmp = ashiftrt64 (cpu->regs[rs1], cpu->regs[rs2] & 0x3f);
301 store_rd (cpu, rd, tmp);
302 break;
303 case MATCH_SRAW:
304 TRACE_INSN (cpu, "sraw %s, %s, %s; // %s = %s >>> %s",
305 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
306 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
307 store_rd (cpu, rd, EXTEND32 (
308 ashiftrt ((signed32) cpu->regs[rs1], cpu->regs[rs2] & 0x1f)));
309 break;
310 case MATCH_SRAI:
311 TRACE_INSN (cpu, "srai %s, %s, %" PRIiTW "; // %s = %s >>> %#" PRIxTW,
312 rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
313 if (RISCV_XLEN (cpu) == 32)
314 {
315 if (shamt_imm > 0x1f)
316 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
317 tmp = ashiftrt (cpu->regs[rs1], shamt_imm);
318 }
319 else
320 tmp = ashiftrt64 (cpu->regs[rs1], shamt_imm);
321 store_rd (cpu, rd, tmp);
322 break;
323 case MATCH_SRAIW:
324 TRACE_INSN (cpu, "sraiw %s, %s, %" PRIiTW "; // %s = %s >>> %#" PRIxTW,
325 rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
326 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
327 store_rd (cpu, rd, EXTEND32 (
328 ashiftrt ((signed32) cpu->regs[rs1], shamt_imm)));
329 break;
330 case MATCH_SLT:
331 TRACE_INSN (cpu, "slt");
332 store_rd (cpu, rd,
333 !!((signed_word) cpu->regs[rs1] < (signed_word) cpu->regs[rs2]));
334 break;
335 case MATCH_SLTU:
336 TRACE_INSN (cpu, "sltu");
337 store_rd (cpu, rd, !!((unsigned_word) cpu->regs[rs1] <
338 (unsigned_word) cpu->regs[rs2]));
339 break;
340 case MATCH_SLTI:
341 TRACE_INSN (cpu, "slti");
342 store_rd (cpu, rd, !!((signed_word) cpu->regs[rs1] <
343 (signed_word) i_imm));
344 break;
345 case MATCH_SLTIU:
346 TRACE_INSN (cpu, "sltiu");
347 store_rd (cpu, rd, !!((unsigned_word) cpu->regs[rs1] <
348 (unsigned_word) i_imm));
349 break;
350 case MATCH_AUIPC:
351 TRACE_INSN (cpu, "auipc %s, %" PRIiTW "; // %s = pc + %" PRIiTW,
352 rd_name, u_imm, rd_name, u_imm);
353 store_rd (cpu, rd, cpu->pc + u_imm);
354 break;
355 case MATCH_BEQ:
356 TRACE_INSN (cpu, "beq %s, %s, %#" PRIxTW "; "
357 "// if (%s == %s) goto %#" PRIxTW,
358 rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
359 if (cpu->regs[rs1] == cpu->regs[rs2])
360 {
361 pc = cpu->pc + sb_imm;
362 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
363 }
364 break;
365 case MATCH_BLT:
366 TRACE_INSN (cpu, "blt %s, %s, %#" PRIxTW "; "
367 "// if (%s < %s) goto %#" PRIxTW,
368 rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
369 if ((signed_word) cpu->regs[rs1] < (signed_word) cpu->regs[rs2])
370 {
371 pc = cpu->pc + sb_imm;
372 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
373 }
374 break;
375 case MATCH_BLTU:
376 TRACE_INSN (cpu, "bltu %s, %s, %#" PRIxTW "; "
377 "// if (%s < %s) goto %#" PRIxTW,
378 rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
379 if ((unsigned_word) cpu->regs[rs1] < (unsigned_word) cpu->regs[rs2])
380 {
381 pc = cpu->pc + sb_imm;
382 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
383 }
384 break;
385 case MATCH_BGE:
386 TRACE_INSN (cpu, "bge %s, %s, %#" PRIxTW "; "
387 "// if (%s >= %s) goto %#" PRIxTW,
388 rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
389 if ((signed_word) cpu->regs[rs1] >= (signed_word) cpu->regs[rs2])
390 {
391 pc = cpu->pc + sb_imm;
392 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
393 }
394 break;
395 case MATCH_BGEU:
396 TRACE_INSN (cpu, "bgeu %s, %s, %#" PRIxTW "; "
397 "// if (%s >= %s) goto %#" PRIxTW,
398 rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
399 if ((unsigned_word) cpu->regs[rs1] >= (unsigned_word) cpu->regs[rs2])
400 {
401 pc = cpu->pc + sb_imm;
402 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
403 }
404 break;
405 case MATCH_BNE:
406 TRACE_INSN (cpu, "bne %s, %s, %#" PRIxTW "; "
407 "// if (%s != %s) goto %#" PRIxTW,
408 rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
409 if (cpu->regs[rs1] != cpu->regs[rs2])
410 {
411 pc = cpu->pc + sb_imm;
412 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
413 }
414 break;
415 case MATCH_JAL:
416 TRACE_INSN (cpu, "jal %s, %" PRIiTW ";", rd_name,
417 EXTRACT_UJTYPE_IMM (iw));
418 store_rd (cpu, rd, cpu->pc + 4);
419 pc = cpu->pc + EXTRACT_UJTYPE_IMM (iw);
420 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
421 break;
422 case MATCH_JALR:
423 TRACE_INSN (cpu, "jalr %s, %s, %" PRIiTW ";", rd_name, rs1_name, i_imm);
424 store_rd (cpu, rd, cpu->pc + 4);
425 pc = cpu->regs[rs1] + i_imm;
426 TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
427 break;
428
429 case MATCH_LD:
430 TRACE_INSN (cpu, "ld %s, %" PRIiTW "(%s);",
431 rd_name, i_imm, rs1_name);
432 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
433 store_rd (cpu, rd,
434 sim_core_read_unaligned_8 (cpu, cpu->pc, read_map,
435 cpu->regs[rs1] + i_imm));
436 break;
437 case MATCH_LW:
438 TRACE_INSN (cpu, "lw %s, %" PRIiTW "(%s);",
439 rd_name, i_imm, rs1_name);
440 store_rd (cpu, rd, EXTEND32 (
441 sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
442 cpu->regs[rs1] + i_imm)));
443 break;
444 case MATCH_LWU:
445 TRACE_INSN (cpu, "lwu %s, %" PRIiTW "(%s);",
446 rd_name, i_imm, rs1_name);
447 store_rd (cpu, rd,
448 sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
449 cpu->regs[rs1] + i_imm));
450 break;
451 case MATCH_LH:
452 TRACE_INSN (cpu, "lh %s, %" PRIiTW "(%s);",
453 rd_name, i_imm, rs1_name);
454 store_rd (cpu, rd, EXTEND16 (
455 sim_core_read_unaligned_2 (cpu, cpu->pc, read_map,
456 cpu->regs[rs1] + i_imm)));
457 break;
458 case MATCH_LHU:
459 TRACE_INSN (cpu, "lbu %s, %" PRIiTW "(%s);",
460 rd_name, i_imm, rs1_name);
461 store_rd (cpu, rd,
462 sim_core_read_unaligned_2 (cpu, cpu->pc, read_map,
463 cpu->regs[rs1] + i_imm));
464 break;
465 case MATCH_LB:
466 TRACE_INSN (cpu, "lb %s, %" PRIiTW "(%s);",
467 rd_name, i_imm, rs1_name);
468 store_rd (cpu, rd, EXTEND8 (
469 sim_core_read_unaligned_1 (cpu, cpu->pc, read_map,
470 cpu->regs[rs1] + i_imm)));
471 break;
472 case MATCH_LBU:
473 TRACE_INSN (cpu, "lbu %s, %" PRIiTW "(%s);",
474 rd_name, i_imm, rs1_name);
475 store_rd (cpu, rd,
476 sim_core_read_unaligned_1 (cpu, cpu->pc, read_map,
477 cpu->regs[rs1] + i_imm));
478 break;
479 case MATCH_SD:
480 TRACE_INSN (cpu, "sd %s, %" PRIiTW "(%s);",
481 rs2_name, s_imm, rs1_name);
482 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
483 sim_core_write_unaligned_8 (cpu, cpu->pc, write_map,
484 cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
485 break;
486 case MATCH_SW:
487 TRACE_INSN (cpu, "sw %s, %" PRIiTW "(%s);",
488 rs2_name, s_imm, rs1_name);
489 sim_core_write_unaligned_4 (cpu, cpu->pc, write_map,
490 cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
491 break;
492 case MATCH_SH:
493 TRACE_INSN (cpu, "sh %s, %" PRIiTW "(%s);",
494 rs2_name, s_imm, rs1_name);
495 sim_core_write_unaligned_2 (cpu, cpu->pc, write_map,
496 cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
497 break;
498 case MATCH_SB:
499 TRACE_INSN (cpu, "sb %s, %" PRIiTW "(%s);",
500 rs2_name, s_imm, rs1_name);
501 sim_core_write_unaligned_1 (cpu, cpu->pc, write_map,
502 cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
503 break;
504
505 case MATCH_CSRRC:
506 TRACE_INSN (cpu, "csrrc");
507 switch (csr)
508 {
509 #define DECLARE_CSR(name, num, ...) \
510 case num: \
511 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
512 store_csr (cpu, #name, num, &cpu->csr.name, \
513 cpu->csr.name & !cpu->regs[rs1]); \
514 break;
515 #include "opcode/riscv-opc.h"
516 #undef DECLARE_CSR
517 }
518 break;
519 case MATCH_CSRRS:
520 TRACE_INSN (cpu, "csrrs");
521 switch (csr)
522 {
523 #define DECLARE_CSR(name, num, ...) \
524 case num: \
525 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
526 store_csr (cpu, #name, num, &cpu->csr.name, \
527 cpu->csr.name | cpu->regs[rs1]); \
528 break;
529 #include "opcode/riscv-opc.h"
530 #undef DECLARE_CSR
531 }
532 break;
533 case MATCH_CSRRW:
534 TRACE_INSN (cpu, "csrrw");
535 switch (csr)
536 {
537 #define DECLARE_CSR(name, num, ...) \
538 case num: \
539 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
540 store_csr (cpu, #name, num, &cpu->csr.name, cpu->regs[rs1]); \
541 break;
542 #include "opcode/riscv-opc.h"
543 #undef DECLARE_CSR
544 }
545 break;
546
547 case MATCH_RDCYCLE:
548 TRACE_INSN (cpu, "rdcycle %s;", rd_name);
549 store_rd (cpu, rd, fetch_csr (cpu, "cycle", CSR_CYCLE, &cpu->csr.cycle));
550 break;
551 case MATCH_RDCYCLEH:
552 TRACE_INSN (cpu, "rdcycleh %s;", rd_name);
553 RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
554 store_rd (cpu, rd,
555 fetch_csr (cpu, "cycleh", CSR_CYCLEH, &cpu->csr.cycleh));
556 break;
557 case MATCH_RDINSTRET:
558 TRACE_INSN (cpu, "rdinstret %s;", rd_name);
559 store_rd (cpu, rd,
560 fetch_csr (cpu, "instret", CSR_INSTRET, &cpu->csr.instret));
561 break;
562 case MATCH_RDINSTRETH:
563 TRACE_INSN (cpu, "rdinstreth %s;", rd_name);
564 RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
565 store_rd (cpu, rd,
566 fetch_csr (cpu, "instreth", CSR_INSTRETH, &cpu->csr.instreth));
567 break;
568 case MATCH_RDTIME:
569 TRACE_INSN (cpu, "rdtime %s;", rd_name);
570 store_rd (cpu, rd, fetch_csr (cpu, "time", CSR_TIME, &cpu->csr.time));
571 break;
572 case MATCH_RDTIMEH:
573 TRACE_INSN (cpu, "rdtimeh %s;", rd_name);
574 RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
575 store_rd (cpu, rd, fetch_csr (cpu, "timeh", CSR_TIMEH, &cpu->csr.timeh));
576 break;
577
578 case MATCH_FENCE:
579 TRACE_INSN (cpu, "fence;");
580 break;
581 case MATCH_FENCE_I:
582 TRACE_INSN (cpu, "fence.i;");
583 break;
584 case MATCH_SBREAK:
585 TRACE_INSN (cpu, "sbreak;");
586 /* GDB expects us to step over SBREAK. */
587 sim_engine_halt (sd, cpu, NULL, cpu->pc + 4, sim_stopped, SIM_SIGTRAP);
588 break;
589 case MATCH_ECALL:
590 TRACE_INSN (cpu, "ecall;");
591 cpu->a0 = sim_syscall (cpu, cpu->a7, cpu->a0, cpu->a1, cpu->a2, cpu->a3);
592 break;
593 default:
594 TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
595 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
596 }
597
598 return pc;
599 }
600
601 static unsigned64
602 mulhu (unsigned64 a, unsigned64 b)
603 {
604 #ifdef __GNUC__
605 return ((__int128)a * b) >> 64;
606 #else
607 uint64_t t;
608 uint32_t y1, y2, y3;
609 uint64_t a0 = (uint32_t)a, a1 = a >> 32;
610 uint64_t b0 = (uint32_t)b, b1 = b >> 32;
611
612 t = a1*b0 + ((a0*b0) >> 32);
613 y1 = t;
614 y2 = t >> 32;
615
616 t = a0*b1 + y1;
617 y1 = t;
618
619 t = a1*b1 + y2 + (t >> 32);
620 y2 = t;
621 y3 = t >> 32;
622
623 return ((uint64_t)y3 << 32) | y2;
624 #endif
625 }
626
627 static unsigned64
628 mulh (signed64 a, signed64 b)
629 {
630 int negate = (a < 0) != (b < 0);
631 uint64_t res = mulhu (a < 0 ? -a : a, b < 0 ? -b : b);
632 return negate ? ~res + (a * b == 0) : res;
633 }
634
635 static unsigned64
636 mulhsu (signed64 a, unsigned64 b)
637 {
638 int negate = a < 0;
639 uint64_t res = mulhu (a < 0 ? -a : a, b);
640 return negate ? ~res + (a * b == 0) : res;
641 }
642
643 static sim_cia
644 execute_m (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
645 {
646 SIM_DESC sd = CPU_STATE (cpu);
647 int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
648 int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
649 int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
650 const char *rd_name = riscv_gpr_names_abi[rd];
651 const char *rs1_name = riscv_gpr_names_abi[rs1];
652 const char *rs2_name = riscv_gpr_names_abi[rs2];
653 unsigned_word tmp, dividend_max;
654 sim_cia pc = cpu->pc + 4;
655
656 dividend_max = -((unsigned_word) 1 << (WITH_TARGET_WORD_BITSIZE - 1));
657
658 switch (op->match)
659 {
660 case MATCH_DIV:
661 TRACE_INSN (cpu, "div %s, %s, %s; // %s = %s / %s",
662 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
663 if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1)
664 tmp = dividend_max;
665 else if (cpu->regs[rs2])
666 tmp = (signed_word) cpu->regs[rs1] / (signed_word) cpu->regs[rs2];
667 else
668 tmp = -1;
669 store_rd (cpu, rd, tmp);
670 break;
671 case MATCH_DIVW:
672 TRACE_INSN (cpu, "divw %s, %s, %s; // %s = %s / %s",
673 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
674 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
675 if (EXTEND32 (cpu->regs[rs2]) == -1)
676 tmp = 1 << 31;
677 else if (EXTEND32 (cpu->regs[rs2]))
678 tmp = EXTEND32 (cpu->regs[rs1]) / EXTEND32 (cpu->regs[rs2]);
679 else
680 tmp = -1;
681 store_rd (cpu, rd, EXTEND32 (tmp));
682 break;
683 case MATCH_DIVU:
684 TRACE_INSN (cpu, "divu %s, %s, %s; // %s = %s / %s",
685 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
686 if (cpu->regs[rs2])
687 store_rd (cpu, rd, (unsigned_word) cpu->regs[rs1]
688 / (unsigned_word) cpu->regs[rs2]);
689 else
690 store_rd (cpu, rd, -1);
691 break;
692 case MATCH_DIVUW:
693 TRACE_INSN (cpu, "divuw %s, %s, %s; // %s = %s / %s",
694 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
695 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
696 if ((unsigned32) cpu->regs[rs2])
697 tmp = (unsigned32) cpu->regs[rs1] / (unsigned32) cpu->regs[rs2];
698 else
699 tmp = -1;
700 store_rd (cpu, rd, EXTEND32 (tmp));
701 break;
702 case MATCH_MUL:
703 TRACE_INSN (cpu, "mul %s, %s, %s; // %s = %s * %s",
704 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
705 store_rd (cpu, rd, cpu->regs[rs1] * cpu->regs[rs2]);
706 break;
707 case MATCH_MULW:
708 TRACE_INSN (cpu, "mulw %s, %s, %s; // %s = %s * %s",
709 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
710 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
711 store_rd (cpu, rd, EXTEND32 ((signed32) cpu->regs[rs1]
712 * (signed32) cpu->regs[rs2]));
713 break;
714 case MATCH_MULH:
715 TRACE_INSN (cpu, "mulh %s, %s, %s; // %s = %s * %s",
716 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
717 if (RISCV_XLEN (cpu) == 32)
718 store_rd (cpu, rd, ((signed64)(signed_word) cpu->regs[rs1]
719 * (signed64)(signed_word) cpu->regs[rs2]) >> 32);
720 else
721 store_rd (cpu, rd, mulh (cpu->regs[rs1], cpu->regs[rs2]));
722 break;
723 case MATCH_MULHU:
724 TRACE_INSN (cpu, "mulhu %s, %s, %s; // %s = %s * %s",
725 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
726 if (RISCV_XLEN (cpu) == 32)
727 store_rd (cpu, rd, ((unsigned64)cpu->regs[rs1]
728 * (unsigned64)cpu->regs[rs2]) >> 32);
729 else
730 store_rd (cpu, rd, mulhu (cpu->regs[rs1], cpu->regs[rs2]));
731 break;
732 case MATCH_MULHSU:
733 TRACE_INSN (cpu, "mulhsu %s, %s, %s; // %s = %s * %s",
734 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
735 if (RISCV_XLEN (cpu) == 32)
736 store_rd (cpu, rd, ((signed64)(signed_word) cpu->regs[rs1]
737 * (unsigned64)cpu->regs[rs2]) >> 32);
738 else
739 store_rd (cpu, rd, mulhsu (cpu->regs[rs1], cpu->regs[rs2]));
740 break;
741 case MATCH_REM:
742 TRACE_INSN (cpu, "rem %s, %s, %s; // %s = %s %% %s",
743 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
744 if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1)
745 tmp = 0;
746 else if (cpu->regs[rs2])
747 tmp = (signed_word) cpu->regs[rs1] % (signed_word) cpu->regs[rs2];
748 else
749 tmp = cpu->regs[rs1];
750 store_rd (cpu, rd, tmp);
751 break;
752 case MATCH_REMW:
753 TRACE_INSN (cpu, "remw %s, %s, %s; // %s = %s %% %s",
754 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
755 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
756 if (EXTEND32 (cpu->regs[rs2]) == -1)
757 tmp = 0;
758 else if (EXTEND32 (cpu->regs[rs2]))
759 tmp = EXTEND32 (cpu->regs[rs1]) % EXTEND32 (cpu->regs[rs2]);
760 else
761 tmp = cpu->regs[rs1];
762 store_rd (cpu, rd, EXTEND32 (tmp));
763 break;
764 case MATCH_REMU:
765 TRACE_INSN (cpu, "remu %s, %s, %s; // %s = %s %% %s",
766 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
767 if (cpu->regs[rs2])
768 store_rd (cpu, rd, cpu->regs[rs1] % cpu->regs[rs2]);
769 else
770 store_rd (cpu, rd, cpu->regs[rs1]);
771 break;
772 case MATCH_REMUW:
773 TRACE_INSN (cpu, "remuw %s, %s, %s; // %s = %s %% %s",
774 rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
775 RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
776 if ((unsigned32) cpu->regs[rs2])
777 tmp = (unsigned32) cpu->regs[rs1] % (unsigned32) cpu->regs[rs2];
778 else
779 tmp = cpu->regs[rs1];
780 store_rd (cpu, rd, EXTEND32 (tmp));
781 break;
782 default:
783 TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
784 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
785 }
786
787 return pc;
788 }
789
790 #define MAX(a, b) ((a) > (b) ? (a) : (b))
791 #define MIN(a, b) ((a) < (b) ? (a) : (b))
792
793 static sim_cia
794 execute_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:
882 tmp = MAX ((signed_word) cpu->regs[rd], (signed_word) cpu->regs[rs2]);
883 break;
884 case MATCH_AMOMAXU_D:
885 case MATCH_AMOMAXU_W:
886 tmp = MAX ((unsigned_word) cpu->regs[rd], (unsigned_word) cpu->regs[rs2]);
887 break;
888 case MATCH_AMOMIN_D:
889 case MATCH_AMOMIN_W:
890 tmp = MIN ((signed_word) cpu->regs[rd], (signed_word) cpu->regs[rs2]);
891 break;
892 case MATCH_AMOMINU_D:
893 case MATCH_AMOMINU_W:
894 tmp = MIN ((unsigned_word) cpu->regs[rd], (unsigned_word) cpu->regs[rs2]);
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
922 static sim_cia
923 execute_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. */
949 void 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. */
1009 static sim_cia
1010 pc_get (sim_cpu *cpu)
1011 {
1012 return cpu->pc;
1013 }
1014
1015 /* Set the program counter for this cpu to the new pc value. */
1016 static void
1017 pc_set (sim_cpu *cpu, sim_cia pc)
1018 {
1019 cpu->pc = pc;
1020 }
1021
1022 /* Initialize the state for a single cpu. Usuaully this involves clearing all
1023 registers back to their reset state. Should also hook up the fetch/store
1024 helper functions too. */
1025 void
1026 initialize_cpu (SIM_DESC sd, SIM_CPU *cpu, int mhartid)
1027 {
1028 const char *extensions;
1029 int i;
1030
1031 memset (cpu->regs, 0, sizeof (cpu->regs));
1032
1033 CPU_PC_FETCH (cpu) = pc_get;
1034 CPU_PC_STORE (cpu) = pc_set;
1035
1036 if (!riscv_hash[0])
1037 {
1038 const struct riscv_opcode *op;
1039
1040 for (op = riscv_opcodes; op->name; op++)
1041 if (!riscv_hash[OP_HASH_IDX (op->match)])
1042 riscv_hash[OP_HASH_IDX (op->match)] = op;
1043 }
1044
1045 cpu->csr.misa = 0;
1046 /* RV32 sets this field to 0, and we don't really support RV128 yet. */
1047 if (RISCV_XLEN (cpu) == 64)
1048 cpu->csr.misa |= (unsigned64)2 << 62;
1049
1050 /* Skip the leading "rv" prefix and the two numbers. */
1051 extensions = MODEL_NAME (CPU_MODEL (cpu)) + 4;
1052 for (i = 0; i < 26; ++i)
1053 {
1054 char ext = 'A' + i;
1055
1056 if (ext == 'X')
1057 continue;
1058 else if (strchr (extensions, ext) != NULL)
1059 {
1060 if (ext == 'G')
1061 cpu->csr.misa |= 0x1129; /* G = IMAFD. */
1062 else
1063 cpu->csr.misa |= (1 << i);
1064 }
1065 }
1066
1067 cpu->csr.mimpid = 0x8000;
1068 cpu->csr.mhartid = mhartid;
1069 }
1070 \f
1071 /* Some utils don't like having a NULL environ. */
1072 static const char * const simple_env[] = { "HOME=/", "PATH=/bin", NULL };
1073
1074 /* Count the number of arguments in an argv. */
1075 static int
1076 count_argv (const char * const *argv)
1077 {
1078 int i;
1079
1080 if (!argv)
1081 return -1;
1082
1083 for (i = 0; argv[i] != NULL; ++i)
1084 continue;
1085 return i;
1086 }
1087
1088 void
1089 initialize_env (SIM_DESC sd, const char * const *argv, const char * const *env)
1090 {
1091 SIM_CPU *cpu = STATE_CPU (sd, 0);
1092 int i;
1093 int argc, argv_flat;
1094 int envc, env_flat;
1095 address_word sp, sp_flat;
1096 unsigned char null[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
1097
1098 /* Figure out how many bytes the argv strings take up. */
1099 argc = count_argv (argv);
1100 if (argc == -1)
1101 argc = 0;
1102 argv_flat = argc; /* NUL bytes. */
1103 for (i = 0; i < argc; ++i)
1104 argv_flat += strlen (argv[i]);
1105
1106 /* Figure out how many bytes the environ strings take up. */
1107 if (!env)
1108 env = simple_env;
1109 envc = count_argv (env);
1110 env_flat = envc; /* NUL bytes. */
1111 for (i = 0; i < envc; ++i)
1112 env_flat += strlen (env[i]);
1113
1114 /* Make space for the strings themselves. */
1115 sp_flat = (DEFAULT_MEM_SIZE - argv_flat - env_flat) & -sizeof (address_word);
1116 /* Then the pointers to the strings. */
1117 sp = sp_flat - ((argc + 1 + envc + 1) * sizeof (address_word));
1118 /* Then the argc. */
1119 sp -= sizeof (unsigned_word);
1120
1121 /* Set up the regs the libgloss crt0 expects. */
1122 cpu->a0 = argc;
1123 cpu->sp = sp;
1124
1125 /* First push the argc value. */
1126 sim_write (sd, sp, (void *)&argc, sizeof (unsigned_word));
1127 sp += sizeof (unsigned_word);
1128
1129 /* Then the actual argv strings so we know where to point argv[]. */
1130 for (i = 0; i < argc; ++i)
1131 {
1132 unsigned len = strlen (argv[i]) + 1;
1133 sim_write (sd, sp_flat, (void *)argv[i], len);
1134 sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word));
1135 sp_flat += len;
1136 sp += sizeof (address_word);
1137 }
1138 sim_write (sd, sp, null, sizeof (address_word));
1139 sp += sizeof (address_word);
1140
1141 /* Then the actual env strings so we know where to point env[]. */
1142 for (i = 0; i < envc; ++i)
1143 {
1144 unsigned len = strlen (env[i]) + 1;
1145 sim_write (sd, sp_flat, (void *)env[i], len);
1146 sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word));
1147 sp_flat += len;
1148 sp += sizeof (address_word);
1149 }
1150 }
This page took 0.059108 seconds and 5 git commands to generate.