3 Copyright (C) 2005-2023 Free Software Foundation, Inc.
4 Contributed by Mike Frysinger.
6 This file is part of simulators.
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.
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.
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/>. */
21 /* This file contains the main simulator decoding logic. i.e. everything that
22 is architecture specific. */
24 /* This must come before any other includes. */
31 #include "sim-signal.h"
32 #include "sim-syscall.h"
34 #include "opcode/riscv.h"
36 #include "sim/sim-riscv.h"
38 #include "riscv-sim.h"
40 #define TRACE_REG(cpu, reg) \
41 TRACE_REGISTER (cpu, "wrote %s = %#" PRIxTW, riscv_gpr_names_abi[reg], \
42 RISCV_SIM_CPU (cpu)->regs[reg])
44 static const struct riscv_opcode
*riscv_hash
[OP_MASK_OP
+ 1];
45 #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : 0x7f))
47 #define RISCV_ASSERT_RV32(cpu, fmt, args...) \
49 if (RISCV_XLEN (cpu) != 32) \
51 SIM_DESC sd = CPU_STATE (cpu); \
52 TRACE_INSN (cpu, "RV32I-only " fmt, ## args); \
53 sim_engine_halt (sd, cpu, NULL, sim_pc_get (cpu), sim_signalled, \
58 #define RISCV_ASSERT_RV64(cpu, fmt, args...) \
60 if (RISCV_XLEN (cpu) != 64) \
62 SIM_DESC sd = CPU_STATE (cpu); \
63 TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \
64 sim_engine_halt (sd, cpu, NULL, sim_pc_get (cpu), sim_signalled, \
70 store_rd (SIM_CPU
*cpu
, int rd
, unsigned_word val
)
72 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
76 riscv_cpu
->regs
[rd
] = val
;
81 static INLINE unsigned_word
82 fetch_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
)
84 /* Handle pseudo registers. */
87 /* Allow certain registers only in respective modes. */
91 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
99 store_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
,
102 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
106 /* These are pseudo registers that modify sub-fields of fcsr. */
110 riscv_cpu
->csr
.fcsr
= (riscv_cpu
->csr
.fcsr
& ~0xe0) | (val
<< 5);
115 riscv_cpu
->csr
.fcsr
= (riscv_cpu
->csr
.fcsr
& ~0x1f) | val
;
117 /* Keep the sub-fields in sync. */
120 riscv_cpu
->csr
.frm
= (val
>> 5) & 0x7;
121 riscv_cpu
->csr
.fflags
= val
& 0x1f;
124 /* Allow certain registers only in respective modes. */
128 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
130 /* All the rest are immutable. */
136 TRACE_REGISTER (cpu
, "wrote CSR %s = %#" PRIxTW
, name
, val
);
139 static inline unsigned_word
140 ashiftrt (unsigned_word val
, unsigned_word shift
)
142 uint32_t sign
= (val
& 0x80000000) ? ~(0xfffffffful
>> shift
) : 0;
143 return (val
>> shift
) | sign
;
146 static inline unsigned_word
147 ashiftrt64 (unsigned_word val
, unsigned_word shift
)
150 (val
& 0x8000000000000000ull
) ? ~(0xffffffffffffffffull
>> shift
) : 0;
151 return (val
>> shift
) | sign
;
155 execute_i (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
157 SIM_DESC sd
= CPU_STATE (cpu
);
158 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
159 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
160 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
161 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
162 const char *rd_name
= riscv_gpr_names_abi
[rd
];
163 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
164 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
165 unsigned int csr
= (iw
>> OP_SH_CSR
) & OP_MASK_CSR
;
166 unsigned_word i_imm
= EXTRACT_ITYPE_IMM (iw
);
167 unsigned_word u_imm
= EXTRACT_UTYPE_IMM ((uint64_t) iw
);
168 unsigned_word s_imm
= EXTRACT_STYPE_IMM (iw
);
169 unsigned_word sb_imm
= EXTRACT_BTYPE_IMM (iw
);
170 unsigned_word shamt_imm
= ((iw
>> OP_SH_SHAMT
) & OP_MASK_SHAMT
);
172 sim_cia pc
= riscv_cpu
->pc
+ 4;
176 "rs1:%-2i:%-4s %0*" PRIxTW
" "
177 "rs2:%-2i:%-4s %0*" PRIxTW
" "
178 "match:%#x mask:%#x",
180 rs1
, rs1_name
, (int) sizeof (unsigned_word
) * 2,
181 riscv_cpu
->regs
[rs1
],
182 rs2
, rs2_name
, (int) sizeof (unsigned_word
) * 2,
183 riscv_cpu
->regs
[rs2
],
184 (unsigned) op
->match
, (unsigned) op
->mask
);
189 TRACE_INSN (cpu
, "add %s, %s, %s; // %s = %s + %s",
190 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
191 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] + riscv_cpu
->regs
[rs2
]);
194 TRACE_INSN (cpu
, "addw %s, %s, %s; // %s = %s + %s",
195 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
196 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
198 EXTEND32 (riscv_cpu
->regs
[rs1
] + riscv_cpu
->regs
[rs2
]));
201 TRACE_INSN (cpu
, "addi %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
202 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
203 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] + i_imm
);
206 TRACE_INSN (cpu
, "addiw %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
207 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
208 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
209 store_rd (cpu
, rd
, EXTEND32 (riscv_cpu
->regs
[rs1
] + i_imm
));
212 TRACE_INSN (cpu
, "and %s, %s, %s; // %s = %s & %s",
213 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
214 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] & riscv_cpu
->regs
[rs2
]);
217 TRACE_INSN (cpu
, "andi %s, %s, %" PRIiTW
"; // %s = %s & %#" PRIxTW
,
218 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
219 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] & i_imm
);
222 TRACE_INSN (cpu
, "or %s, %s, %s; // %s = %s | %s",
223 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
224 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] | riscv_cpu
->regs
[rs2
]);
227 TRACE_INSN (cpu
, "ori %s, %s, %" PRIiTW
"; // %s = %s | %#" PRIxTW
,
228 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
229 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] | i_imm
);
232 TRACE_INSN (cpu
, "xor %s, %s, %s; // %s = %s ^ %s",
233 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
234 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] ^ riscv_cpu
->regs
[rs2
]);
237 TRACE_INSN (cpu
, "xori %s, %s, %" PRIiTW
"; // %s = %s ^ %#" PRIxTW
,
238 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
239 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] ^ i_imm
);
242 TRACE_INSN (cpu
, "sub %s, %s, %s; // %s = %s - %s",
243 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
244 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] - riscv_cpu
->regs
[rs2
]);
247 TRACE_INSN (cpu
, "subw %s, %s, %s; // %s = %s - %s",
248 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
249 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
251 EXTEND32 (riscv_cpu
->regs
[rs1
] - riscv_cpu
->regs
[rs2
]));
254 TRACE_INSN (cpu
, "lui %s, %#" PRIxTW
";", rd_name
, u_imm
);
255 store_rd (cpu
, rd
, u_imm
);
258 TRACE_INSN (cpu
, "sll %s, %s, %s; // %s = %s << %s",
259 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
260 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
262 riscv_cpu
->regs
[rs1
] << (riscv_cpu
->regs
[rs2
] & u_imm
));
265 TRACE_INSN (cpu
, "sllw %s, %s, %s; // %s = %s << %s",
266 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
267 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
268 store_rd (cpu
, rd
, EXTEND32 (
269 (uint32_t) riscv_cpu
->regs
[rs1
] << (riscv_cpu
->regs
[rs2
] & 0x1f)));
272 TRACE_INSN (cpu
, "slli %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
273 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
274 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
275 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
277 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] << shamt_imm
);
280 TRACE_INSN (cpu
, "slliw %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
281 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
282 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
284 EXTEND32 ((uint32_t) riscv_cpu
->regs
[rs1
] << shamt_imm
));
287 TRACE_INSN (cpu
, "srl %s, %s, %s; // %s = %s >> %s",
288 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
289 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
291 riscv_cpu
->regs
[rs1
] >> (riscv_cpu
->regs
[rs2
] & u_imm
));
294 TRACE_INSN (cpu
, "srlw %s, %s, %s; // %s = %s >> %s",
295 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
296 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
297 store_rd (cpu
, rd
, EXTEND32 (
298 (uint32_t) riscv_cpu
->regs
[rs1
] >> (riscv_cpu
->regs
[rs2
] & 0x1f)));
301 TRACE_INSN (cpu
, "srli %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
302 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
303 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
304 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
306 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] >> shamt_imm
);
309 TRACE_INSN (cpu
, "srliw %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
310 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
311 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
313 EXTEND32 ((uint32_t) riscv_cpu
->regs
[rs1
] >> shamt_imm
));
316 TRACE_INSN (cpu
, "sra %s, %s, %s; // %s = %s >>> %s",
317 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
318 if (RISCV_XLEN (cpu
) == 32)
319 tmp
= ashiftrt (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
] & 0x1f);
321 tmp
= ashiftrt64 (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
] & 0x3f);
322 store_rd (cpu
, rd
, tmp
);
325 TRACE_INSN (cpu
, "sraw %s, %s, %s; // %s = %s >>> %s",
326 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
327 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
328 store_rd (cpu
, rd
, EXTEND32 (
329 ashiftrt ((int32_t) riscv_cpu
->regs
[rs1
],
330 riscv_cpu
->regs
[rs2
] & 0x1f)));
333 TRACE_INSN (cpu
, "srai %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
334 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
335 if (RISCV_XLEN (cpu
) == 32)
337 if (shamt_imm
> 0x1f)
338 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
340 tmp
= ashiftrt (riscv_cpu
->regs
[rs1
], shamt_imm
);
343 tmp
= ashiftrt64 (riscv_cpu
->regs
[rs1
], shamt_imm
);
344 store_rd (cpu
, rd
, tmp
);
347 TRACE_INSN (cpu
, "sraiw %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
348 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
349 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
350 store_rd (cpu
, rd
, EXTEND32 (
351 ashiftrt ((int32_t) riscv_cpu
->regs
[rs1
], shamt_imm
)));
354 TRACE_INSN (cpu
, "slt");
356 !!((signed_word
) riscv_cpu
->regs
[rs1
] <
357 (signed_word
) riscv_cpu
->regs
[rs2
]));
360 TRACE_INSN (cpu
, "sltu");
361 store_rd (cpu
, rd
, !!((unsigned_word
) riscv_cpu
->regs
[rs1
] <
362 (unsigned_word
) riscv_cpu
->regs
[rs2
]));
365 TRACE_INSN (cpu
, "slti");
366 store_rd (cpu
, rd
, !!((signed_word
) riscv_cpu
->regs
[rs1
] <
367 (signed_word
) i_imm
));
370 TRACE_INSN (cpu
, "sltiu");
371 store_rd (cpu
, rd
, !!((unsigned_word
) riscv_cpu
->regs
[rs1
] <
372 (unsigned_word
) i_imm
));
375 TRACE_INSN (cpu
, "auipc %s, %" PRIiTW
"; // %s = pc + %" PRIiTW
,
376 rd_name
, u_imm
, rd_name
, u_imm
);
377 store_rd (cpu
, rd
, riscv_cpu
->pc
+ u_imm
);
380 TRACE_INSN (cpu
, "beq %s, %s, %#" PRIxTW
"; "
381 "// if (%s == %s) goto %#" PRIxTW
,
382 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
383 if (riscv_cpu
->regs
[rs1
] == riscv_cpu
->regs
[rs2
])
385 pc
= riscv_cpu
->pc
+ sb_imm
;
386 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
390 TRACE_INSN (cpu
, "blt %s, %s, %#" PRIxTW
"; "
391 "// if (%s < %s) goto %#" PRIxTW
,
392 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
393 if ((signed_word
) riscv_cpu
->regs
[rs1
] <
394 (signed_word
) riscv_cpu
->regs
[rs2
])
396 pc
= riscv_cpu
->pc
+ sb_imm
;
397 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
401 TRACE_INSN (cpu
, "bltu %s, %s, %#" PRIxTW
"; "
402 "// if (%s < %s) goto %#" PRIxTW
,
403 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
404 if ((unsigned_word
) riscv_cpu
->regs
[rs1
] <
405 (unsigned_word
) riscv_cpu
->regs
[rs2
])
407 pc
= riscv_cpu
->pc
+ sb_imm
;
408 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
412 TRACE_INSN (cpu
, "bge %s, %s, %#" PRIxTW
"; "
413 "// if (%s >= %s) goto %#" PRIxTW
,
414 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
415 if ((signed_word
) riscv_cpu
->regs
[rs1
] >=
416 (signed_word
) riscv_cpu
->regs
[rs2
])
418 pc
= riscv_cpu
->pc
+ sb_imm
;
419 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
423 TRACE_INSN (cpu
, "bgeu %s, %s, %#" PRIxTW
"; "
424 "// if (%s >= %s) goto %#" PRIxTW
,
425 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
426 if ((unsigned_word
) riscv_cpu
->regs
[rs1
] >=
427 (unsigned_word
) riscv_cpu
->regs
[rs2
])
429 pc
= riscv_cpu
->pc
+ sb_imm
;
430 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
434 TRACE_INSN (cpu
, "bne %s, %s, %#" PRIxTW
"; "
435 "// if (%s != %s) goto %#" PRIxTW
,
436 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
437 if (riscv_cpu
->regs
[rs1
] != riscv_cpu
->regs
[rs2
])
439 pc
= riscv_cpu
->pc
+ sb_imm
;
440 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
444 TRACE_INSN (cpu
, "jal %s, %" PRIiTW
";", rd_name
,
445 EXTRACT_JTYPE_IMM (iw
));
446 store_rd (cpu
, rd
, riscv_cpu
->pc
+ 4);
447 pc
= riscv_cpu
->pc
+ EXTRACT_JTYPE_IMM (iw
);
448 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
451 TRACE_INSN (cpu
, "jalr %s, %s, %" PRIiTW
";", rd_name
, rs1_name
, i_imm
);
452 store_rd (cpu
, rd
, riscv_cpu
->pc
+ 4);
453 pc
= riscv_cpu
->regs
[rs1
] + i_imm
;
454 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
458 TRACE_INSN (cpu
, "ld %s, %" PRIiTW
"(%s);",
459 rd_name
, i_imm
, rs1_name
);
460 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
462 sim_core_read_unaligned_8 (cpu
, riscv_cpu
->pc
, read_map
,
463 riscv_cpu
->regs
[rs1
] + i_imm
));
466 TRACE_INSN (cpu
, "lw %s, %" PRIiTW
"(%s);",
467 rd_name
, i_imm
, rs1_name
);
468 store_rd (cpu
, rd
, EXTEND32 (
469 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
470 riscv_cpu
->regs
[rs1
] + i_imm
)));
473 TRACE_INSN (cpu
, "lwu %s, %" PRIiTW
"(%s);",
474 rd_name
, i_imm
, rs1_name
);
476 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
477 riscv_cpu
->regs
[rs1
] + i_imm
));
480 TRACE_INSN (cpu
, "lh %s, %" PRIiTW
"(%s);",
481 rd_name
, i_imm
, rs1_name
);
482 store_rd (cpu
, rd
, EXTEND16 (
483 sim_core_read_unaligned_2 (cpu
, riscv_cpu
->pc
, read_map
,
484 riscv_cpu
->regs
[rs1
] + i_imm
)));
487 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
488 rd_name
, i_imm
, rs1_name
);
490 sim_core_read_unaligned_2 (cpu
, riscv_cpu
->pc
, read_map
,
491 riscv_cpu
->regs
[rs1
] + i_imm
));
494 TRACE_INSN (cpu
, "lb %s, %" PRIiTW
"(%s);",
495 rd_name
, i_imm
, rs1_name
);
496 store_rd (cpu
, rd
, EXTEND8 (
497 sim_core_read_unaligned_1 (cpu
, riscv_cpu
->pc
, read_map
,
498 riscv_cpu
->regs
[rs1
] + i_imm
)));
501 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
502 rd_name
, i_imm
, rs1_name
);
504 sim_core_read_unaligned_1 (cpu
, riscv_cpu
->pc
, read_map
,
505 riscv_cpu
->regs
[rs1
] + i_imm
));
508 TRACE_INSN (cpu
, "sd %s, %" PRIiTW
"(%s);",
509 rs2_name
, s_imm
, rs1_name
);
510 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
511 sim_core_write_unaligned_8 (cpu
, riscv_cpu
->pc
, write_map
,
512 riscv_cpu
->regs
[rs1
] + s_imm
,
513 riscv_cpu
->regs
[rs2
]);
516 TRACE_INSN (cpu
, "sw %s, %" PRIiTW
"(%s);",
517 rs2_name
, s_imm
, rs1_name
);
518 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
519 riscv_cpu
->regs
[rs1
] + s_imm
,
520 riscv_cpu
->regs
[rs2
]);
523 TRACE_INSN (cpu
, "sh %s, %" PRIiTW
"(%s);",
524 rs2_name
, s_imm
, rs1_name
);
525 sim_core_write_unaligned_2 (cpu
, riscv_cpu
->pc
, write_map
,
526 riscv_cpu
->regs
[rs1
] + s_imm
,
527 riscv_cpu
->regs
[rs2
]);
530 TRACE_INSN (cpu
, "sb %s, %" PRIiTW
"(%s);",
531 rs2_name
, s_imm
, rs1_name
);
532 sim_core_write_unaligned_1 (cpu
, riscv_cpu
->pc
, write_map
,
533 riscv_cpu
->regs
[rs1
] + s_imm
,
534 riscv_cpu
->regs
[rs2
]);
538 TRACE_INSN (cpu
, "csrrc");
541 #define DECLARE_CSR(name, num, ...) \
544 fetch_csr (cpu, #name, num, &riscv_cpu->csr.name)); \
545 store_csr (cpu, #name, num, &riscv_cpu->csr.name, \
546 riscv_cpu->csr.name & !riscv_cpu->regs[rs1]); \
548 #include "opcode/riscv-opc.h"
553 TRACE_INSN (cpu
, "csrrs");
556 #define DECLARE_CSR(name, num, ...) \
559 fetch_csr (cpu, #name, num, &riscv_cpu->csr.name)); \
560 store_csr (cpu, #name, num, &riscv_cpu->csr.name, \
561 riscv_cpu->csr.name | riscv_cpu->regs[rs1]); \
563 #include "opcode/riscv-opc.h"
568 TRACE_INSN (cpu
, "csrrw");
571 #define DECLARE_CSR(name, num, ...) \
574 fetch_csr (cpu, #name, num, &riscv_cpu->csr.name)); \
575 store_csr (cpu, #name, num, &riscv_cpu->csr.name, \
576 riscv_cpu->regs[rs1]); \
578 #include "opcode/riscv-opc.h"
584 TRACE_INSN (cpu
, "rdcycle %s;", rd_name
);
586 fetch_csr (cpu
, "cycle", CSR_CYCLE
, &riscv_cpu
->csr
.cycle
));
589 TRACE_INSN (cpu
, "rdcycleh %s;", rd_name
);
590 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
592 fetch_csr (cpu
, "cycleh", CSR_CYCLEH
, &riscv_cpu
->csr
.cycleh
));
594 case MATCH_RDINSTRET
:
595 TRACE_INSN (cpu
, "rdinstret %s;", rd_name
);
597 fetch_csr (cpu
, "instret", CSR_INSTRET
,
598 &riscv_cpu
->csr
.instret
));
600 case MATCH_RDINSTRETH
:
601 TRACE_INSN (cpu
, "rdinstreth %s;", rd_name
);
602 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
604 fetch_csr (cpu
, "instreth", CSR_INSTRETH
,
605 &riscv_cpu
->csr
.instreth
));
608 TRACE_INSN (cpu
, "rdtime %s;", rd_name
);
610 fetch_csr (cpu
, "time", CSR_TIME
, &riscv_cpu
->csr
.time
));
613 TRACE_INSN (cpu
, "rdtimeh %s;", rd_name
);
614 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
616 fetch_csr (cpu
, "timeh", CSR_TIMEH
, &riscv_cpu
->csr
.timeh
));
620 TRACE_INSN (cpu
, "fence;");
623 TRACE_INSN (cpu
, "fence.i;");
626 TRACE_INSN (cpu
, "ebreak;");
627 /* GDB expects us to step over EBREAK. */
628 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
+ 4, sim_stopped
,
632 TRACE_INSN (cpu
, "ecall;");
633 riscv_cpu
->a0
= sim_syscall (cpu
, riscv_cpu
->a7
, riscv_cpu
->a0
,
634 riscv_cpu
->a1
, riscv_cpu
->a2
, riscv_cpu
->a3
);
637 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
638 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
645 mulhu (uint64_t a
, uint64_t b
)
648 return ((__int128
)a
* b
) >> 64;
652 uint64_t a0
= (uint32_t)a
, a1
= a
>> 32;
653 uint64_t b0
= (uint32_t)b
, b1
= b
>> 32;
655 t
= a1
*b0
+ ((a0
*b0
) >> 32);
662 t
= a1
*b1
+ y2
+ (t
>> 32);
666 return ((uint64_t)y3
<< 32) | y2
;
671 mulh (int64_t a
, int64_t b
)
673 int negate
= (a
< 0) != (b
< 0);
674 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
< 0 ? -b
: b
);
675 return negate
? ~res
+ (a
* b
== 0) : res
;
679 mulhsu (int64_t a
, uint64_t b
)
682 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
);
683 return negate
? ~res
+ (a
* b
== 0) : res
;
687 execute_m (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
689 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
690 SIM_DESC sd
= CPU_STATE (cpu
);
691 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
692 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
693 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
694 const char *rd_name
= riscv_gpr_names_abi
[rd
];
695 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
696 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
697 unsigned_word tmp
, dividend_max
;
698 sim_cia pc
= riscv_cpu
->pc
+ 4;
700 dividend_max
= -((unsigned_word
) 1 << (WITH_TARGET_WORD_BITSIZE
- 1));
705 TRACE_INSN (cpu
, "div %s, %s, %s; // %s = %s / %s",
706 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
707 if (riscv_cpu
->regs
[rs1
] == dividend_max
&& riscv_cpu
->regs
[rs2
] == -1)
709 else if (riscv_cpu
->regs
[rs2
])
710 tmp
= (signed_word
) riscv_cpu
->regs
[rs1
] /
711 (signed_word
) riscv_cpu
->regs
[rs2
];
714 store_rd (cpu
, rd
, tmp
);
717 TRACE_INSN (cpu
, "divw %s, %s, %s; // %s = %s / %s",
718 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
719 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
720 if (EXTEND32 (riscv_cpu
->regs
[rs2
]) == -1)
722 else if (EXTEND32 (riscv_cpu
->regs
[rs2
]))
723 tmp
= EXTEND32 (riscv_cpu
->regs
[rs1
]) / EXTEND32 (riscv_cpu
->regs
[rs2
]);
726 store_rd (cpu
, rd
, EXTEND32 (tmp
));
729 TRACE_INSN (cpu
, "divu %s, %s, %s; // %s = %s / %s",
730 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
731 if (riscv_cpu
->regs
[rs2
])
732 store_rd (cpu
, rd
, (unsigned_word
) riscv_cpu
->regs
[rs1
]
733 / (unsigned_word
) riscv_cpu
->regs
[rs2
]);
735 store_rd (cpu
, rd
, -1);
738 TRACE_INSN (cpu
, "divuw %s, %s, %s; // %s = %s / %s",
739 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
740 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
741 if ((uint32_t) riscv_cpu
->regs
[rs2
])
742 tmp
= (uint32_t) riscv_cpu
->regs
[rs1
] / (uint32_t) riscv_cpu
->regs
[rs2
];
745 store_rd (cpu
, rd
, EXTEND32 (tmp
));
748 TRACE_INSN (cpu
, "mul %s, %s, %s; // %s = %s * %s",
749 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
750 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] * riscv_cpu
->regs
[rs2
]);
753 TRACE_INSN (cpu
, "mulw %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 store_rd (cpu
, rd
, EXTEND32 ((int32_t) riscv_cpu
->regs
[rs1
]
757 * (int32_t) riscv_cpu
->regs
[rs2
]));
760 TRACE_INSN (cpu
, "mulh %s, %s, %s; // %s = %s * %s",
761 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
762 if (RISCV_XLEN (cpu
) == 32)
764 ((int64_t)(signed_word
) riscv_cpu
->regs
[rs1
]
765 * (int64_t)(signed_word
) riscv_cpu
->regs
[rs2
]) >> 32);
767 store_rd (cpu
, rd
, mulh (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
]));
770 TRACE_INSN (cpu
, "mulhu %s, %s, %s; // %s = %s * %s",
771 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
772 if (RISCV_XLEN (cpu
) == 32)
773 store_rd (cpu
, rd
, ((uint64_t)riscv_cpu
->regs
[rs1
]
774 * (uint64_t)riscv_cpu
->regs
[rs2
]) >> 32);
776 store_rd (cpu
, rd
, mulhu (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
]));
779 TRACE_INSN (cpu
, "mulhsu %s, %s, %s; // %s = %s * %s",
780 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
781 if (RISCV_XLEN (cpu
) == 32)
782 store_rd (cpu
, rd
, ((int64_t)(signed_word
) riscv_cpu
->regs
[rs1
]
783 * (uint64_t)riscv_cpu
->regs
[rs2
]) >> 32);
785 store_rd (cpu
, rd
, mulhsu (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
]));
788 TRACE_INSN (cpu
, "rem %s, %s, %s; // %s = %s %% %s",
789 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
790 if (riscv_cpu
->regs
[rs1
] == dividend_max
&& riscv_cpu
->regs
[rs2
] == -1)
792 else if (riscv_cpu
->regs
[rs2
])
793 tmp
= (signed_word
) riscv_cpu
->regs
[rs1
]
794 % (signed_word
) riscv_cpu
->regs
[rs2
];
796 tmp
= riscv_cpu
->regs
[rs1
];
797 store_rd (cpu
, rd
, tmp
);
800 TRACE_INSN (cpu
, "remw %s, %s, %s; // %s = %s %% %s",
801 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
802 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
803 if (EXTEND32 (riscv_cpu
->regs
[rs2
]) == -1)
805 else if (EXTEND32 (riscv_cpu
->regs
[rs2
]))
806 tmp
= EXTEND32 (riscv_cpu
->regs
[rs1
]) % EXTEND32 (riscv_cpu
->regs
[rs2
]);
808 tmp
= riscv_cpu
->regs
[rs1
];
809 store_rd (cpu
, rd
, EXTEND32 (tmp
));
812 TRACE_INSN (cpu
, "remu %s, %s, %s; // %s = %s %% %s",
813 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
814 if (riscv_cpu
->regs
[rs2
])
815 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] % riscv_cpu
->regs
[rs2
]);
817 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
]);
820 TRACE_INSN (cpu
, "remuw %s, %s, %s; // %s = %s %% %s",
821 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
822 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
823 if ((uint32_t) riscv_cpu
->regs
[rs2
])
824 tmp
= (uint32_t) riscv_cpu
->regs
[rs1
] % (uint32_t) riscv_cpu
->regs
[rs2
];
826 tmp
= riscv_cpu
->regs
[rs1
];
827 store_rd (cpu
, rd
, EXTEND32 (tmp
));
830 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
831 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
838 execute_a (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
840 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
841 SIM_DESC sd
= CPU_STATE (cpu
);
842 struct riscv_sim_state
*state
= RISCV_SIM_STATE (sd
);
843 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
844 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
845 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
846 const char *rd_name
= riscv_gpr_names_abi
[rd
];
847 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
848 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
849 struct atomic_mem_reserved_list
*amo_prev
, *amo_curr
;
851 sim_cia pc
= riscv_cpu
->pc
+ 4;
853 /* Handle these two load/store operations specifically. */
857 TRACE_INSN (cpu
, "%s %s, (%s);", op
->name
, rd_name
, rs1_name
);
859 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
860 riscv_cpu
->regs
[rs1
]));
862 /* Walk the reservation list to find an existing match. */
863 amo_curr
= state
->amo_reserved_list
;
866 if (amo_curr
->addr
== riscv_cpu
->regs
[rs1
])
868 amo_curr
= amo_curr
->next
;
871 /* No reservation exists, so add one. */
872 amo_curr
= xmalloc (sizeof (*amo_curr
));
873 amo_curr
->addr
= riscv_cpu
->regs
[rs1
];
874 amo_curr
->next
= state
->amo_reserved_list
;
875 state
->amo_reserved_list
= amo_curr
;
878 TRACE_INSN (cpu
, "%s %s, %s, (%s);", op
->name
, rd_name
, rs2_name
,
881 /* Walk the reservation list to find a match. */
882 amo_curr
= amo_prev
= state
->amo_reserved_list
;
885 if (amo_curr
->addr
== riscv_cpu
->regs
[rs1
])
887 /* We found a reservation, so operate it. */
888 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
889 riscv_cpu
->regs
[rs1
],
890 riscv_cpu
->regs
[rs2
]);
891 store_rd (cpu
, rd
, 0);
892 if (amo_curr
== state
->amo_reserved_list
)
893 state
->amo_reserved_list
= amo_curr
->next
;
895 amo_prev
->next
= amo_curr
->next
;
900 amo_curr
= amo_curr
->next
;
903 /* If we're still here, then no reservation exists, so mark as failed. */
904 store_rd (cpu
, rd
, 1);
908 /* Handle the rest of the atomic insns with common code paths. */
909 TRACE_INSN (cpu
, "%s %s, %s, (%s);",
910 op
->name
, rd_name
, rs2_name
, rs1_name
);
911 if (op
->xlen_requirement
== 64)
912 tmp
= sim_core_read_unaligned_8 (cpu
, riscv_cpu
->pc
, read_map
,
913 riscv_cpu
->regs
[rs1
]);
915 tmp
= EXTEND32 (sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
916 riscv_cpu
->regs
[rs1
]));
917 store_rd (cpu
, rd
, tmp
);
923 tmp
= riscv_cpu
->regs
[rd
] + riscv_cpu
->regs
[rs2
];
927 tmp
= riscv_cpu
->regs
[rd
] & riscv_cpu
->regs
[rs2
];
931 tmp
= max ((signed_word
) riscv_cpu
->regs
[rd
],
932 (signed_word
) riscv_cpu
->regs
[rs2
]);
934 case MATCH_AMOMAXU_D
:
935 case MATCH_AMOMAXU_W
:
936 tmp
= max ((unsigned_word
) riscv_cpu
->regs
[rd
],
937 (unsigned_word
) riscv_cpu
->regs
[rs2
]);
941 tmp
= min ((signed_word
) riscv_cpu
->regs
[rd
],
942 (signed_word
) riscv_cpu
->regs
[rs2
]);
944 case MATCH_AMOMINU_D
:
945 case MATCH_AMOMINU_W
:
946 tmp
= min ((unsigned_word
) riscv_cpu
->regs
[rd
],
947 (unsigned_word
) riscv_cpu
->regs
[rs2
]);
951 tmp
= riscv_cpu
->regs
[rd
] | riscv_cpu
->regs
[rs2
];
953 case MATCH_AMOSWAP_D
:
954 case MATCH_AMOSWAP_W
:
955 tmp
= riscv_cpu
->regs
[rs2
];
959 tmp
= riscv_cpu
->regs
[rd
] ^ riscv_cpu
->regs
[rs2
];
962 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
963 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
966 if (op
->xlen_requirement
== 64)
967 sim_core_write_unaligned_8 (cpu
, riscv_cpu
->pc
, write_map
,
968 riscv_cpu
->regs
[rs1
], tmp
);
970 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
971 riscv_cpu
->regs
[rs1
], tmp
);
978 execute_one (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
980 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
981 SIM_DESC sd
= CPU_STATE (cpu
);
983 if (op
->xlen_requirement
== 32)
984 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
985 else if (op
->xlen_requirement
== 64)
986 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
988 switch (op
->insn_class
)
991 return execute_a (cpu
, iw
, op
);
993 return execute_i (cpu
, iw
, op
);
995 case INSN_CLASS_ZMMUL
:
996 return execute_m (cpu
, iw
, op
);
998 TRACE_INSN (cpu
, "UNHANDLED EXTENSION: %d", op
->insn_class
);
999 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
1002 return riscv_cpu
->pc
+ riscv_insn_length (iw
);
1005 /* Decode & execute a single instruction. */
1006 void step_once (SIM_CPU
*cpu
)
1008 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1009 SIM_DESC sd
= CPU_STATE (cpu
);
1012 sim_cia pc
= riscv_cpu
->pc
;
1013 const struct riscv_opcode
*op
;
1014 int xlen
= RISCV_XLEN (cpu
);
1016 if (TRACE_ANY_P (cpu
))
1017 trace_prefix (sd
, cpu
, NULL_CIA
, pc
, TRACE_LINENUM_P (cpu
),
1018 NULL
, 0, " "); /* Use a space for gcc warnings. */
1020 iw
= sim_core_read_aligned_2 (cpu
, pc
, exec_map
, pc
);
1022 /* Reject non-32-bit opcodes first. */
1023 len
= riscv_insn_length (iw
);
1026 sim_io_printf (sd
, "sim: bad insn len %#x @ %#" PRIxTA
": %#" PRIxTW
"\n",
1028 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
1031 iw
|= ((unsigned_word
) sim_core_read_aligned_2 (
1032 cpu
, pc
, exec_map
, pc
+ 2) << 16);
1034 TRACE_CORE (cpu
, "0x%08" PRIxTW
, iw
);
1036 op
= riscv_hash
[OP_HASH_IDX (iw
)];
1038 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
1040 /* NB: Same loop logic as riscv_disassemble_insn. */
1041 for (; op
->name
; op
++)
1043 /* Does the opcode match? */
1044 if (! op
->match_func (op
, iw
))
1046 /* Is this a pseudo-instruction and may we print it as such? */
1047 if (op
->pinfo
& INSN_ALIAS
)
1049 /* Is this instruction restricted to a certain value of XLEN? */
1050 if (op
->xlen_requirement
!= 0 && op
->xlen_requirement
!= xlen
)
1054 pc
= execute_one (cpu
, iw
, op
);
1058 /* TODO: Handle overflow into high 32 bits. */
1059 /* TODO: Try to use a common counter and only update on demand (reads). */
1060 ++riscv_cpu
->csr
.cycle
;
1061 ++riscv_cpu
->csr
.instret
;
1066 /* Return the program counter for this cpu. */
1068 pc_get (sim_cpu
*cpu
)
1070 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1072 return riscv_cpu
->pc
;
1075 /* Set the program counter for this cpu to the new pc value. */
1077 pc_set (sim_cpu
*cpu
, sim_cia pc
)
1079 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1085 reg_fetch (sim_cpu
*cpu
, int rn
, void *buf
, int len
)
1087 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1089 if (len
<= 0 || len
> sizeof (unsigned_word
))
1094 case SIM_RISCV_ZERO_REGNUM
:
1095 memset (buf
, 0, len
);
1097 case SIM_RISCV_RA_REGNUM
... SIM_RISCV_T6_REGNUM
:
1098 memcpy (buf
, &riscv_cpu
->regs
[rn
], len
);
1100 case SIM_RISCV_FIRST_FP_REGNUM
... SIM_RISCV_LAST_FP_REGNUM
:
1101 memcpy (buf
, &riscv_cpu
->fpregs
[rn
- SIM_RISCV_FIRST_FP_REGNUM
], len
);
1103 case SIM_RISCV_PC_REGNUM
:
1104 memcpy (buf
, &riscv_cpu
->pc
, len
);
1107 #define DECLARE_CSR(name, num, ...) \
1108 case SIM_RISCV_ ## num ## _REGNUM: \
1109 memcpy (buf, &riscv_cpu->csr.name, len); \
1111 #include "opcode/riscv-opc.h"
1120 reg_store (sim_cpu
*cpu
, int rn
, const void *buf
, int len
)
1122 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1124 if (len
<= 0 || len
> sizeof (unsigned_word
))
1129 case SIM_RISCV_ZERO_REGNUM
:
1130 /* Ignore writes. */
1132 case SIM_RISCV_RA_REGNUM
... SIM_RISCV_T6_REGNUM
:
1133 memcpy (&riscv_cpu
->regs
[rn
], buf
, len
);
1135 case SIM_RISCV_FIRST_FP_REGNUM
... SIM_RISCV_LAST_FP_REGNUM
:
1136 memcpy (&riscv_cpu
->fpregs
[rn
- SIM_RISCV_FIRST_FP_REGNUM
], buf
, len
);
1138 case SIM_RISCV_PC_REGNUM
:
1139 memcpy (&riscv_cpu
->pc
, buf
, len
);
1142 #define DECLARE_CSR(name, num, ...) \
1143 case SIM_RISCV_ ## num ## _REGNUM: \
1144 memcpy (&riscv_cpu->csr.name, buf, len); \
1146 #include "opcode/riscv-opc.h"
1154 /* Initialize the state for a single cpu. Usuaully this involves clearing all
1155 registers back to their reset state. Should also hook up the fetch/store
1156 helper functions too. */
1158 initialize_cpu (SIM_DESC sd
, SIM_CPU
*cpu
, int mhartid
)
1160 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1161 const char *extensions
;
1164 memset (riscv_cpu
->regs
, 0, sizeof (riscv_cpu
->regs
));
1166 CPU_PC_FETCH (cpu
) = pc_get
;
1167 CPU_PC_STORE (cpu
) = pc_set
;
1168 CPU_REG_FETCH (cpu
) = reg_fetch
;
1169 CPU_REG_STORE (cpu
) = reg_store
;
1173 const struct riscv_opcode
*op
;
1175 for (op
= riscv_opcodes
; op
->name
; op
++)
1176 if (!riscv_hash
[OP_HASH_IDX (op
->match
)])
1177 riscv_hash
[OP_HASH_IDX (op
->match
)] = op
;
1180 riscv_cpu
->csr
.misa
= 0;
1181 /* RV32 sets this field to 0, and we don't really support RV128 yet. */
1182 if (RISCV_XLEN (cpu
) == 64)
1183 riscv_cpu
->csr
.misa
|= (uint64_t)2 << 62;
1185 /* Skip the leading "rv" prefix and the two numbers. */
1186 extensions
= MODEL_NAME (CPU_MODEL (cpu
)) + 4;
1187 for (i
= 0; i
< 26; ++i
)
1193 else if (strchr (extensions
, ext
) != NULL
)
1196 riscv_cpu
->csr
.misa
|= 0x1129; /* G = IMAFD. */
1198 riscv_cpu
->csr
.misa
|= (1 << i
);
1202 riscv_cpu
->csr
.mimpid
= 0x8000;
1203 riscv_cpu
->csr
.mhartid
= mhartid
;
1206 /* Some utils don't like having a NULL environ. */
1207 static const char * const simple_env
[] = { "HOME=/", "PATH=/bin", NULL
};
1209 /* Count the number of arguments in an argv. */
1211 count_argv (const char * const *argv
)
1218 for (i
= 0; argv
[i
] != NULL
; ++i
)
1224 initialize_env (SIM_DESC sd
, const char * const *argv
, const char * const *env
)
1226 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
1227 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1229 int argc
, argv_flat
;
1231 address_word sp
, sp_flat
;
1232 unsigned char null
[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
1234 /* Figure out how many bytes the argv strings take up. */
1235 argc
= count_argv (argv
);
1238 argv_flat
= argc
; /* NUL bytes. */
1239 for (i
= 0; i
< argc
; ++i
)
1240 argv_flat
+= strlen (argv
[i
]);
1242 /* Figure out how many bytes the environ strings take up. */
1245 envc
= count_argv (env
);
1246 env_flat
= envc
; /* NUL bytes. */
1247 for (i
= 0; i
< envc
; ++i
)
1248 env_flat
+= strlen (env
[i
]);
1250 /* Make space for the strings themselves. */
1251 sp_flat
= (DEFAULT_MEM_SIZE
- argv_flat
- env_flat
) & -sizeof (address_word
);
1252 /* Then the pointers to the strings. */
1253 sp
= sp_flat
- ((argc
+ 1 + envc
+ 1) * sizeof (address_word
));
1254 /* Then the argc. */
1255 sp
-= sizeof (unsigned_word
);
1257 /* Set up the regs the libgloss crt0 expects. */
1258 riscv_cpu
->a0
= argc
;
1261 /* First push the argc value. */
1262 sim_write (sd
, sp
, &argc
, sizeof (unsigned_word
));
1263 sp
+= sizeof (unsigned_word
);
1265 /* Then the actual argv strings so we know where to point argv[]. */
1266 for (i
= 0; i
< argc
; ++i
)
1268 unsigned len
= strlen (argv
[i
]) + 1;
1269 sim_write (sd
, sp_flat
, argv
[i
], len
);
1270 sim_write (sd
, sp
, &sp_flat
, sizeof (address_word
));
1272 sp
+= sizeof (address_word
);
1274 sim_write (sd
, sp
, null
, sizeof (address_word
));
1275 sp
+= sizeof (address_word
);
1277 /* Then the actual env strings so we know where to point env[]. */
1278 for (i
= 0; i
< envc
; ++i
)
1280 unsigned len
= strlen (env
[i
]) + 1;
1281 sim_write (sd
, sp_flat
, env
[i
], len
);
1282 sim_write (sd
, sp
, &sp_flat
, sizeof (address_word
));
1284 sp
+= sizeof (address_word
);