3 Copyright (C) 2005-2024 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 TRACE_INSN (cpu, "RV32I-only " fmt, ## args); \
52 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, sim_pc_get (cpu), \
53 sim_signalled, SIM_SIGILL); \
57 #define RISCV_ASSERT_RV64(cpu, fmt, args...) \
59 if (RISCV_XLEN (cpu) != 64) \
61 TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \
62 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, sim_pc_get (cpu), \
63 sim_signalled, SIM_SIGILL); \
68 store_rd (SIM_CPU
*cpu
, int rd
, unsigned_word val
)
70 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
74 riscv_cpu
->regs
[rd
] = val
;
79 static INLINE unsigned_word
80 fetch_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
)
82 /* Handle pseudo registers. */
85 /* Allow certain registers only in respective modes. */
89 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
97 store_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
,
100 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
104 /* These are pseudo registers that modify sub-fields of fcsr. */
108 riscv_cpu
->csr
.fcsr
= (riscv_cpu
->csr
.fcsr
& ~0xe0) | (val
<< 5);
113 riscv_cpu
->csr
.fcsr
= (riscv_cpu
->csr
.fcsr
& ~0x1f) | val
;
115 /* Keep the sub-fields in sync. */
118 riscv_cpu
->csr
.frm
= (val
>> 5) & 0x7;
119 riscv_cpu
->csr
.fflags
= val
& 0x1f;
122 /* Allow certain registers only in respective modes. */
126 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
127 ATTRIBUTE_FALLTHROUGH
;
129 /* All the rest are immutable. */
135 TRACE_REGISTER (cpu
, "wrote CSR %s = %#" PRIxTW
, name
, val
);
138 static inline unsigned_word
139 ashiftrt (unsigned_word val
, unsigned_word shift
)
141 uint32_t sign
= (val
& 0x80000000) ? ~(0xfffffffful
>> shift
) : 0;
142 return (val
>> shift
) | sign
;
145 static inline unsigned_word
146 ashiftrt64 (unsigned_word val
, unsigned_word shift
)
149 (val
& 0x8000000000000000ull
) ? ~(0xffffffffffffffffull
>> shift
) : 0;
150 return (val
>> shift
) | sign
;
154 execute_i (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
156 SIM_DESC sd
= CPU_STATE (cpu
);
157 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
158 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
159 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
160 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
161 const char *rd_name
= riscv_gpr_names_abi
[rd
];
162 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
163 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
164 unsigned int csr
= (iw
>> OP_SH_CSR
) & OP_MASK_CSR
;
165 unsigned_word i_imm
= EXTRACT_ITYPE_IMM (iw
);
166 unsigned_word u_imm
= EXTRACT_UTYPE_IMM ((uint64_t) iw
);
167 unsigned_word s_imm
= EXTRACT_STYPE_IMM (iw
);
168 unsigned_word sb_imm
= EXTRACT_BTYPE_IMM (iw
);
169 unsigned_word shamt_imm
= ((iw
>> OP_SH_SHAMT
) & OP_MASK_SHAMT
);
171 sim_cia pc
= riscv_cpu
->pc
+ 4;
175 "rs1:%-2i:%-4s %0*" PRIxTW
" "
176 "rs2:%-2i:%-4s %0*" PRIxTW
" "
177 "match:%#x mask:%#x",
179 rs1
, rs1_name
, (int) sizeof (unsigned_word
) * 2,
180 riscv_cpu
->regs
[rs1
],
181 rs2
, rs2_name
, (int) sizeof (unsigned_word
) * 2,
182 riscv_cpu
->regs
[rs2
],
183 (unsigned) op
->match
, (unsigned) op
->mask
);
188 TRACE_INSN (cpu
, "add %s, %s, %s; // %s = %s + %s",
189 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
190 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] + riscv_cpu
->regs
[rs2
]);
193 TRACE_INSN (cpu
, "addw %s, %s, %s; // %s = %s + %s",
194 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
195 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
197 EXTEND32 (riscv_cpu
->regs
[rs1
] + riscv_cpu
->regs
[rs2
]));
200 TRACE_INSN (cpu
, "addi %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
201 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
202 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] + i_imm
);
205 TRACE_INSN (cpu
, "addiw %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
206 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
207 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
208 store_rd (cpu
, rd
, EXTEND32 (riscv_cpu
->regs
[rs1
] + i_imm
));
211 TRACE_INSN (cpu
, "and %s, %s, %s; // %s = %s & %s",
212 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
213 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] & riscv_cpu
->regs
[rs2
]);
216 TRACE_INSN (cpu
, "andi %s, %s, %" PRIiTW
"; // %s = %s & %#" PRIxTW
,
217 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
218 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] & i_imm
);
221 TRACE_INSN (cpu
, "or %s, %s, %s; // %s = %s | %s",
222 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
223 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] | riscv_cpu
->regs
[rs2
]);
226 TRACE_INSN (cpu
, "ori %s, %s, %" PRIiTW
"; // %s = %s | %#" PRIxTW
,
227 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
228 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] | i_imm
);
231 TRACE_INSN (cpu
, "xor %s, %s, %s; // %s = %s ^ %s",
232 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
233 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] ^ riscv_cpu
->regs
[rs2
]);
236 TRACE_INSN (cpu
, "xori %s, %s, %" PRIiTW
"; // %s = %s ^ %#" PRIxTW
,
237 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
238 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] ^ i_imm
);
241 TRACE_INSN (cpu
, "sub %s, %s, %s; // %s = %s - %s",
242 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
243 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] - riscv_cpu
->regs
[rs2
]);
246 TRACE_INSN (cpu
, "subw %s, %s, %s; // %s = %s - %s",
247 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
248 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
250 EXTEND32 (riscv_cpu
->regs
[rs1
] - riscv_cpu
->regs
[rs2
]));
253 TRACE_INSN (cpu
, "lui %s, %#" PRIxTW
";", rd_name
, u_imm
);
254 store_rd (cpu
, rd
, u_imm
);
257 TRACE_INSN (cpu
, "sll %s, %s, %s; // %s = %s << %s",
258 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
259 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
261 riscv_cpu
->regs
[rs1
] << (riscv_cpu
->regs
[rs2
] & u_imm
));
264 TRACE_INSN (cpu
, "sllw %s, %s, %s; // %s = %s << %s",
265 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
266 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
267 store_rd (cpu
, rd
, EXTEND32 (
268 (uint32_t) riscv_cpu
->regs
[rs1
] << (riscv_cpu
->regs
[rs2
] & 0x1f)));
271 TRACE_INSN (cpu
, "slli %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
272 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
273 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
274 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
276 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] << shamt_imm
);
279 TRACE_INSN (cpu
, "slliw %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
280 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
281 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
283 EXTEND32 ((uint32_t) riscv_cpu
->regs
[rs1
] << shamt_imm
));
286 TRACE_INSN (cpu
, "srl %s, %s, %s; // %s = %s >> %s",
287 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
288 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
290 riscv_cpu
->regs
[rs1
] >> (riscv_cpu
->regs
[rs2
] & u_imm
));
293 TRACE_INSN (cpu
, "srlw %s, %s, %s; // %s = %s >> %s",
294 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
295 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
296 store_rd (cpu
, rd
, EXTEND32 (
297 (uint32_t) riscv_cpu
->regs
[rs1
] >> (riscv_cpu
->regs
[rs2
] & 0x1f)));
300 TRACE_INSN (cpu
, "srli %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
301 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
302 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
303 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
305 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] >> shamt_imm
);
308 TRACE_INSN (cpu
, "srliw %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
309 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
310 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
312 EXTEND32 ((uint32_t) riscv_cpu
->regs
[rs1
] >> shamt_imm
));
315 TRACE_INSN (cpu
, "sra %s, %s, %s; // %s = %s >>> %s",
316 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
317 if (RISCV_XLEN (cpu
) == 32)
318 tmp
= ashiftrt (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
] & 0x1f);
320 tmp
= ashiftrt64 (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
] & 0x3f);
321 store_rd (cpu
, rd
, tmp
);
324 TRACE_INSN (cpu
, "sraw %s, %s, %s; // %s = %s >>> %s",
325 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
326 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
327 store_rd (cpu
, rd
, EXTEND32 (
328 ashiftrt ((int32_t) riscv_cpu
->regs
[rs1
],
329 riscv_cpu
->regs
[rs2
] & 0x1f)));
332 TRACE_INSN (cpu
, "srai %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
333 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
334 if (RISCV_XLEN (cpu
) == 32)
336 if (shamt_imm
> 0x1f)
337 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
339 tmp
= ashiftrt (riscv_cpu
->regs
[rs1
], shamt_imm
);
342 tmp
= ashiftrt64 (riscv_cpu
->regs
[rs1
], shamt_imm
);
343 store_rd (cpu
, rd
, tmp
);
346 TRACE_INSN (cpu
, "sraiw %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
347 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
348 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
349 store_rd (cpu
, rd
, EXTEND32 (
350 ashiftrt ((int32_t) riscv_cpu
->regs
[rs1
], shamt_imm
)));
353 TRACE_INSN (cpu
, "slt");
355 !!((signed_word
) riscv_cpu
->regs
[rs1
] <
356 (signed_word
) riscv_cpu
->regs
[rs2
]));
359 TRACE_INSN (cpu
, "sltu");
360 store_rd (cpu
, rd
, !!((unsigned_word
) riscv_cpu
->regs
[rs1
] <
361 (unsigned_word
) riscv_cpu
->regs
[rs2
]));
364 TRACE_INSN (cpu
, "slti");
365 store_rd (cpu
, rd
, !!((signed_word
) riscv_cpu
->regs
[rs1
] <
366 (signed_word
) i_imm
));
369 TRACE_INSN (cpu
, "sltiu");
370 store_rd (cpu
, rd
, !!((unsigned_word
) riscv_cpu
->regs
[rs1
] <
371 (unsigned_word
) i_imm
));
374 TRACE_INSN (cpu
, "auipc %s, %" PRIiTW
"; // %s = pc + %" PRIiTW
,
375 rd_name
, u_imm
, rd_name
, u_imm
);
376 store_rd (cpu
, rd
, riscv_cpu
->pc
+ u_imm
);
379 TRACE_INSN (cpu
, "beq %s, %s, %#" PRIxTW
"; "
380 "// if (%s == %s) goto %#" PRIxTW
,
381 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
382 if (riscv_cpu
->regs
[rs1
] == riscv_cpu
->regs
[rs2
])
384 pc
= riscv_cpu
->pc
+ sb_imm
;
385 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
389 TRACE_INSN (cpu
, "blt %s, %s, %#" PRIxTW
"; "
390 "// if (%s < %s) goto %#" PRIxTW
,
391 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
392 if ((signed_word
) riscv_cpu
->regs
[rs1
] <
393 (signed_word
) riscv_cpu
->regs
[rs2
])
395 pc
= riscv_cpu
->pc
+ sb_imm
;
396 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
400 TRACE_INSN (cpu
, "bltu %s, %s, %#" PRIxTW
"; "
401 "// if (%s < %s) goto %#" PRIxTW
,
402 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
403 if ((unsigned_word
) riscv_cpu
->regs
[rs1
] <
404 (unsigned_word
) riscv_cpu
->regs
[rs2
])
406 pc
= riscv_cpu
->pc
+ sb_imm
;
407 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
411 TRACE_INSN (cpu
, "bge %s, %s, %#" PRIxTW
"; "
412 "// if (%s >= %s) goto %#" PRIxTW
,
413 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
414 if ((signed_word
) riscv_cpu
->regs
[rs1
] >=
415 (signed_word
) riscv_cpu
->regs
[rs2
])
417 pc
= riscv_cpu
->pc
+ sb_imm
;
418 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
422 TRACE_INSN (cpu
, "bgeu %s, %s, %#" PRIxTW
"; "
423 "// if (%s >= %s) goto %#" PRIxTW
,
424 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
425 if ((unsigned_word
) riscv_cpu
->regs
[rs1
] >=
426 (unsigned_word
) riscv_cpu
->regs
[rs2
])
428 pc
= riscv_cpu
->pc
+ sb_imm
;
429 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
433 TRACE_INSN (cpu
, "bne %s, %s, %#" PRIxTW
"; "
434 "// if (%s != %s) goto %#" PRIxTW
,
435 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
436 if (riscv_cpu
->regs
[rs1
] != riscv_cpu
->regs
[rs2
])
438 pc
= riscv_cpu
->pc
+ sb_imm
;
439 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
443 TRACE_INSN (cpu
, "jal %s, %" PRIiTW
";", rd_name
,
444 EXTRACT_JTYPE_IMM (iw
));
445 store_rd (cpu
, rd
, riscv_cpu
->pc
+ 4);
446 pc
= riscv_cpu
->pc
+ EXTRACT_JTYPE_IMM (iw
);
447 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
450 TRACE_INSN (cpu
, "jalr %s, %s, %" PRIiTW
";", rd_name
, rs1_name
, i_imm
);
451 pc
= riscv_cpu
->regs
[rs1
] + i_imm
;
452 store_rd (cpu
, rd
, riscv_cpu
->pc
+ 4);
453 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
457 TRACE_INSN (cpu
, "ld %s, %" PRIiTW
"(%s);",
458 rd_name
, i_imm
, rs1_name
);
459 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
461 sim_core_read_unaligned_8 (cpu
, riscv_cpu
->pc
, read_map
,
462 riscv_cpu
->regs
[rs1
] + i_imm
));
465 TRACE_INSN (cpu
, "lw %s, %" PRIiTW
"(%s);",
466 rd_name
, i_imm
, rs1_name
);
467 store_rd (cpu
, rd
, EXTEND32 (
468 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
469 riscv_cpu
->regs
[rs1
] + i_imm
)));
472 TRACE_INSN (cpu
, "lwu %s, %" PRIiTW
"(%s);",
473 rd_name
, i_imm
, rs1_name
);
475 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
476 riscv_cpu
->regs
[rs1
] + i_imm
));
479 TRACE_INSN (cpu
, "lh %s, %" PRIiTW
"(%s);",
480 rd_name
, i_imm
, rs1_name
);
481 store_rd (cpu
, rd
, EXTEND16 (
482 sim_core_read_unaligned_2 (cpu
, riscv_cpu
->pc
, read_map
,
483 riscv_cpu
->regs
[rs1
] + i_imm
)));
486 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
487 rd_name
, i_imm
, rs1_name
);
489 sim_core_read_unaligned_2 (cpu
, riscv_cpu
->pc
, read_map
,
490 riscv_cpu
->regs
[rs1
] + i_imm
));
493 TRACE_INSN (cpu
, "lb %s, %" PRIiTW
"(%s);",
494 rd_name
, i_imm
, rs1_name
);
495 store_rd (cpu
, rd
, EXTEND8 (
496 sim_core_read_unaligned_1 (cpu
, riscv_cpu
->pc
, read_map
,
497 riscv_cpu
->regs
[rs1
] + i_imm
)));
500 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
501 rd_name
, i_imm
, rs1_name
);
503 sim_core_read_unaligned_1 (cpu
, riscv_cpu
->pc
, read_map
,
504 riscv_cpu
->regs
[rs1
] + i_imm
));
507 TRACE_INSN (cpu
, "sd %s, %" PRIiTW
"(%s);",
508 rs2_name
, s_imm
, rs1_name
);
509 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
510 sim_core_write_unaligned_8 (cpu
, riscv_cpu
->pc
, write_map
,
511 riscv_cpu
->regs
[rs1
] + s_imm
,
512 riscv_cpu
->regs
[rs2
]);
515 TRACE_INSN (cpu
, "sw %s, %" PRIiTW
"(%s);",
516 rs2_name
, s_imm
, rs1_name
);
517 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
518 riscv_cpu
->regs
[rs1
] + s_imm
,
519 riscv_cpu
->regs
[rs2
]);
522 TRACE_INSN (cpu
, "sh %s, %" PRIiTW
"(%s);",
523 rs2_name
, s_imm
, rs1_name
);
524 sim_core_write_unaligned_2 (cpu
, riscv_cpu
->pc
, write_map
,
525 riscv_cpu
->regs
[rs1
] + s_imm
,
526 riscv_cpu
->regs
[rs2
]);
529 TRACE_INSN (cpu
, "sb %s, %" PRIiTW
"(%s);",
530 rs2_name
, s_imm
, rs1_name
);
531 sim_core_write_unaligned_1 (cpu
, riscv_cpu
->pc
, write_map
,
532 riscv_cpu
->regs
[rs1
] + s_imm
,
533 riscv_cpu
->regs
[rs2
]);
537 TRACE_INSN (cpu
, "csrrc");
540 #define DECLARE_CSR(name, num, ...) \
543 fetch_csr (cpu, #name, num, &riscv_cpu->csr.name)); \
544 store_csr (cpu, #name, num, &riscv_cpu->csr.name, \
545 riscv_cpu->csr.name & !riscv_cpu->regs[rs1]); \
547 #include "opcode/riscv-opc.h"
552 TRACE_INSN (cpu
, "csrrs");
555 #define DECLARE_CSR(name, num, ...) \
558 fetch_csr (cpu, #name, num, &riscv_cpu->csr.name)); \
559 store_csr (cpu, #name, num, &riscv_cpu->csr.name, \
560 riscv_cpu->csr.name | riscv_cpu->regs[rs1]); \
562 #include "opcode/riscv-opc.h"
567 TRACE_INSN (cpu
, "csrrw");
570 #define DECLARE_CSR(name, num, ...) \
573 fetch_csr (cpu, #name, num, &riscv_cpu->csr.name)); \
574 store_csr (cpu, #name, num, &riscv_cpu->csr.name, \
575 riscv_cpu->regs[rs1]); \
577 #include "opcode/riscv-opc.h"
583 TRACE_INSN (cpu
, "rdcycle %s;", rd_name
);
585 fetch_csr (cpu
, "cycle", CSR_CYCLE
, &riscv_cpu
->csr
.cycle
));
588 TRACE_INSN (cpu
, "rdcycleh %s;", rd_name
);
589 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
591 fetch_csr (cpu
, "cycleh", CSR_CYCLEH
, &riscv_cpu
->csr
.cycleh
));
593 case MATCH_RDINSTRET
:
594 TRACE_INSN (cpu
, "rdinstret %s;", rd_name
);
596 fetch_csr (cpu
, "instret", CSR_INSTRET
,
597 &riscv_cpu
->csr
.instret
));
599 case MATCH_RDINSTRETH
:
600 TRACE_INSN (cpu
, "rdinstreth %s;", rd_name
);
601 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
603 fetch_csr (cpu
, "instreth", CSR_INSTRETH
,
604 &riscv_cpu
->csr
.instreth
));
607 TRACE_INSN (cpu
, "rdtime %s;", rd_name
);
609 fetch_csr (cpu
, "time", CSR_TIME
, &riscv_cpu
->csr
.time
));
612 TRACE_INSN (cpu
, "rdtimeh %s;", rd_name
);
613 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
615 fetch_csr (cpu
, "timeh", CSR_TIMEH
, &riscv_cpu
->csr
.timeh
));
619 TRACE_INSN (cpu
, "fence;");
622 TRACE_INSN (cpu
, "fence.i;");
625 TRACE_INSN (cpu
, "ebreak;");
626 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_stopped
, SIM_SIGTRAP
);
629 TRACE_INSN (cpu
, "ecall;");
630 riscv_cpu
->a0
= sim_syscall (cpu
, riscv_cpu
->a7
, riscv_cpu
->a0
,
631 riscv_cpu
->a1
, riscv_cpu
->a2
, riscv_cpu
->a3
);
634 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
635 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
642 mulhu (uint64_t a
, uint64_t b
)
645 return ((__int128
)a
* b
) >> 64;
649 uint64_t a0
= (uint32_t)a
, a1
= a
>> 32;
650 uint64_t b0
= (uint32_t)b
, b1
= b
>> 32;
652 t
= a1
*b0
+ ((a0
*b0
) >> 32);
659 t
= a1
*b1
+ y2
+ (t
>> 32);
663 return ((uint64_t)y3
<< 32) | y2
;
668 mulh (int64_t a
, int64_t b
)
670 int negate
= (a
< 0) != (b
< 0);
671 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
< 0 ? -b
: b
);
672 return negate
? ~res
+ (a
* b
== 0) : res
;
676 mulhsu (int64_t a
, uint64_t b
)
679 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
);
680 return negate
? ~res
+ (a
* b
== 0) : res
;
684 execute_m (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
686 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
687 SIM_DESC sd
= CPU_STATE (cpu
);
688 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
689 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
690 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
691 const char *rd_name
= riscv_gpr_names_abi
[rd
];
692 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
693 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
694 unsigned_word tmp
, dividend_max
;
695 sim_cia pc
= riscv_cpu
->pc
+ 4;
697 dividend_max
= -((unsigned_word
) 1 << (WITH_TARGET_WORD_BITSIZE
- 1));
702 TRACE_INSN (cpu
, "div %s, %s, %s; // %s = %s / %s",
703 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
704 if (riscv_cpu
->regs
[rs1
] == dividend_max
&& riscv_cpu
->regs
[rs2
] == -1)
706 else if (riscv_cpu
->regs
[rs2
])
707 tmp
= (signed_word
) riscv_cpu
->regs
[rs1
] /
708 (signed_word
) riscv_cpu
->regs
[rs2
];
711 store_rd (cpu
, rd
, tmp
);
714 TRACE_INSN (cpu
, "divw %s, %s, %s; // %s = %s / %s",
715 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
716 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
717 if (EXTEND32 (riscv_cpu
->regs
[rs2
]) == -1)
719 else if (EXTEND32 (riscv_cpu
->regs
[rs2
]))
720 tmp
= EXTEND32 (riscv_cpu
->regs
[rs1
]) / EXTEND32 (riscv_cpu
->regs
[rs2
]);
723 store_rd (cpu
, rd
, EXTEND32 (tmp
));
726 TRACE_INSN (cpu
, "divu %s, %s, %s; // %s = %s / %s",
727 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
728 if (riscv_cpu
->regs
[rs2
])
729 store_rd (cpu
, rd
, (unsigned_word
) riscv_cpu
->regs
[rs1
]
730 / (unsigned_word
) riscv_cpu
->regs
[rs2
]);
732 store_rd (cpu
, rd
, -1);
735 TRACE_INSN (cpu
, "divuw %s, %s, %s; // %s = %s / %s",
736 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
737 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
738 if ((uint32_t) riscv_cpu
->regs
[rs2
])
739 tmp
= (uint32_t) riscv_cpu
->regs
[rs1
] / (uint32_t) riscv_cpu
->regs
[rs2
];
742 store_rd (cpu
, rd
, EXTEND32 (tmp
));
745 TRACE_INSN (cpu
, "mul %s, %s, %s; // %s = %s * %s",
746 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
747 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] * riscv_cpu
->regs
[rs2
]);
750 TRACE_INSN (cpu
, "mulw %s, %s, %s; // %s = %s * %s",
751 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
752 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
753 store_rd (cpu
, rd
, EXTEND32 ((int32_t) riscv_cpu
->regs
[rs1
]
754 * (int32_t) riscv_cpu
->regs
[rs2
]));
757 TRACE_INSN (cpu
, "mulh %s, %s, %s; // %s = %s * %s",
758 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
759 if (RISCV_XLEN (cpu
) == 32)
761 ((int64_t)(signed_word
) riscv_cpu
->regs
[rs1
]
762 * (int64_t)(signed_word
) riscv_cpu
->regs
[rs2
]) >> 32);
764 store_rd (cpu
, rd
, mulh (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
]));
767 TRACE_INSN (cpu
, "mulhu %s, %s, %s; // %s = %s * %s",
768 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
769 if (RISCV_XLEN (cpu
) == 32)
770 store_rd (cpu
, rd
, ((uint64_t)riscv_cpu
->regs
[rs1
]
771 * (uint64_t)riscv_cpu
->regs
[rs2
]) >> 32);
773 store_rd (cpu
, rd
, mulhu (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
]));
776 TRACE_INSN (cpu
, "mulhsu %s, %s, %s; // %s = %s * %s",
777 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
778 if (RISCV_XLEN (cpu
) == 32)
779 store_rd (cpu
, rd
, ((int64_t)(signed_word
) riscv_cpu
->regs
[rs1
]
780 * (uint64_t)riscv_cpu
->regs
[rs2
]) >> 32);
782 store_rd (cpu
, rd
, mulhsu (riscv_cpu
->regs
[rs1
], riscv_cpu
->regs
[rs2
]));
785 TRACE_INSN (cpu
, "rem %s, %s, %s; // %s = %s %% %s",
786 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
787 if (riscv_cpu
->regs
[rs1
] == dividend_max
&& riscv_cpu
->regs
[rs2
] == -1)
789 else if (riscv_cpu
->regs
[rs2
])
790 tmp
= (signed_word
) riscv_cpu
->regs
[rs1
]
791 % (signed_word
) riscv_cpu
->regs
[rs2
];
793 tmp
= riscv_cpu
->regs
[rs1
];
794 store_rd (cpu
, rd
, tmp
);
797 TRACE_INSN (cpu
, "remw %s, %s, %s; // %s = %s %% %s",
798 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
799 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
800 if (EXTEND32 (riscv_cpu
->regs
[rs2
]) == -1)
802 else if (EXTEND32 (riscv_cpu
->regs
[rs2
]))
803 tmp
= EXTEND32 (riscv_cpu
->regs
[rs1
]) % EXTEND32 (riscv_cpu
->regs
[rs2
]);
805 tmp
= riscv_cpu
->regs
[rs1
];
806 store_rd (cpu
, rd
, EXTEND32 (tmp
));
809 TRACE_INSN (cpu
, "remu %s, %s, %s; // %s = %s %% %s",
810 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
811 if (riscv_cpu
->regs
[rs2
])
812 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
] % riscv_cpu
->regs
[rs2
]);
814 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs1
]);
817 TRACE_INSN (cpu
, "remuw %s, %s, %s; // %s = %s %% %s",
818 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
819 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
820 if ((uint32_t) riscv_cpu
->regs
[rs2
])
821 tmp
= (uint32_t) riscv_cpu
->regs
[rs1
] % (uint32_t) riscv_cpu
->regs
[rs2
];
823 tmp
= riscv_cpu
->regs
[rs1
];
824 store_rd (cpu
, rd
, EXTEND32 (tmp
));
827 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
828 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
835 execute_a (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
837 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
838 SIM_DESC sd
= CPU_STATE (cpu
);
839 struct riscv_sim_state
*state
= RISCV_SIM_STATE (sd
);
840 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
841 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
842 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
843 const char *rd_name
= riscv_gpr_names_abi
[rd
];
844 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
845 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
846 struct atomic_mem_reserved_list
*amo_prev
, *amo_curr
;
848 sim_cia pc
= riscv_cpu
->pc
+ 4;
850 /* Handle these two load/store operations specifically. */
854 TRACE_INSN (cpu
, "%s %s, (%s);", op
->name
, rd_name
, rs1_name
);
856 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
857 riscv_cpu
->regs
[rs1
]));
859 /* Walk the reservation list to find an existing match. */
860 amo_curr
= state
->amo_reserved_list
;
863 if (amo_curr
->addr
== riscv_cpu
->regs
[rs1
])
865 amo_curr
= amo_curr
->next
;
868 /* No reservation exists, so add one. */
869 amo_curr
= xmalloc (sizeof (*amo_curr
));
870 amo_curr
->addr
= riscv_cpu
->regs
[rs1
];
871 amo_curr
->next
= state
->amo_reserved_list
;
872 state
->amo_reserved_list
= amo_curr
;
875 TRACE_INSN (cpu
, "%s %s, %s, (%s);", op
->name
, rd_name
, rs2_name
,
878 /* Walk the reservation list to find a match. */
879 amo_curr
= amo_prev
= state
->amo_reserved_list
;
882 if (amo_curr
->addr
== riscv_cpu
->regs
[rs1
])
884 /* We found a reservation, so operate it. */
885 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
886 riscv_cpu
->regs
[rs1
],
887 riscv_cpu
->regs
[rs2
]);
888 store_rd (cpu
, rd
, 0);
889 if (amo_curr
== state
->amo_reserved_list
)
890 state
->amo_reserved_list
= amo_curr
->next
;
892 amo_prev
->next
= amo_curr
->next
;
897 amo_curr
= amo_curr
->next
;
900 /* If we're still here, then no reservation exists, so mark as failed. */
901 store_rd (cpu
, rd
, 1);
905 /* Handle the rest of the atomic insns with common code paths. */
906 TRACE_INSN (cpu
, "%s %s, %s, (%s);",
907 op
->name
, rd_name
, rs2_name
, rs1_name
);
908 if (op
->xlen_requirement
== 64)
909 tmp
= sim_core_read_unaligned_8 (cpu
, riscv_cpu
->pc
, read_map
,
910 riscv_cpu
->regs
[rs1
]);
912 tmp
= EXTEND32 (sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
913 riscv_cpu
->regs
[rs1
]));
914 store_rd (cpu
, rd
, tmp
);
920 tmp
= riscv_cpu
->regs
[rd
] + riscv_cpu
->regs
[rs2
];
924 tmp
= riscv_cpu
->regs
[rd
] & riscv_cpu
->regs
[rs2
];
928 tmp
= max ((signed_word
) riscv_cpu
->regs
[rd
],
929 (signed_word
) riscv_cpu
->regs
[rs2
]);
931 case MATCH_AMOMAXU_D
:
932 case MATCH_AMOMAXU_W
:
933 tmp
= max ((unsigned_word
) riscv_cpu
->regs
[rd
],
934 (unsigned_word
) riscv_cpu
->regs
[rs2
]);
938 tmp
= min ((signed_word
) riscv_cpu
->regs
[rd
],
939 (signed_word
) riscv_cpu
->regs
[rs2
]);
941 case MATCH_AMOMINU_D
:
942 case MATCH_AMOMINU_W
:
943 tmp
= min ((unsigned_word
) riscv_cpu
->regs
[rd
],
944 (unsigned_word
) riscv_cpu
->regs
[rs2
]);
948 tmp
= riscv_cpu
->regs
[rd
] | riscv_cpu
->regs
[rs2
];
950 case MATCH_AMOSWAP_D
:
951 case MATCH_AMOSWAP_W
:
952 tmp
= riscv_cpu
->regs
[rs2
];
956 tmp
= riscv_cpu
->regs
[rd
] ^ riscv_cpu
->regs
[rs2
];
959 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
960 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
963 if (op
->xlen_requirement
== 64)
964 sim_core_write_unaligned_8 (cpu
, riscv_cpu
->pc
, write_map
,
965 riscv_cpu
->regs
[rs1
], tmp
);
967 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
968 riscv_cpu
->regs
[rs1
], tmp
);
975 execute_c (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
977 SIM_DESC sd
= CPU_STATE (cpu
);
978 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
979 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
980 int rs1_c
= ((iw
>> OP_SH_CRS1S
) & OP_MASK_CRS1S
) + 8;
981 int rs2
= (iw
>> OP_SH_CRS2
) & OP_MASK_CRS2
;
982 int rs2_c
= ((iw
>> OP_SH_CRS2S
) & OP_MASK_CRS2S
) + 8;
983 const char *rd_name
= riscv_gpr_names_abi
[rd
];
984 const char *rs1_c_name
= riscv_gpr_names_abi
[rs1_c
];
985 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
986 const char *rs2_c_name
= riscv_gpr_names_abi
[rs2_c
];
989 sim_cia pc
= riscv_cpu
->pc
+ 2;
993 case MATCH_C_JR
| MATCH_C_MV
:
997 TRACE_INSN (cpu
, "c.mv %s, %s; // %s = %s",
998 rd_name
, rs2_name
, rd_name
, rs2_name
);
999 store_rd (cpu
, rd
, riscv_cpu
->regs
[rs2
]);
1002 TRACE_INSN (cpu
, "c.jr %s;",
1004 pc
= riscv_cpu
->regs
[rd
];
1005 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
1010 imm
= EXTRACT_CJTYPE_IMM (iw
);
1011 TRACE_INSN (cpu
, "c.j %" PRIxTW
,
1013 pc
= riscv_cpu
->pc
+ imm
;
1014 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
1016 case MATCH_C_JAL
| MATCH_C_ADDIW
:
1017 /* JAL and ADDIW have the same mask but are only available on RV32 or
1018 RV64 respectively. */
1019 if (RISCV_XLEN (cpu
) == 32)
1021 imm
= EXTRACT_CJTYPE_IMM (iw
);
1022 TRACE_INSN (cpu
, "c.jal %" PRIxTW
,
1024 store_rd (cpu
, SIM_RISCV_RA_REGNUM
, riscv_cpu
->pc
+ 2);
1025 pc
= riscv_cpu
->pc
+ imm
;
1026 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
1028 else if (RISCV_XLEN (cpu
) == 64)
1030 imm
= EXTRACT_CITYPE_IMM (iw
);
1031 TRACE_INSN (cpu
, "c.addiw %s, %s, %#" PRIxTW
"; // %s += %#" PRIxTW
,
1032 rd_name
, rd_name
, imm
, rd_name
, imm
);
1033 store_rd (cpu
, rd
, EXTEND32 (riscv_cpu
->regs
[rd
] + imm
));
1037 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
1038 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
1042 case MATCH_C_JALR
| MATCH_C_ADD
| MATCH_C_EBREAK
:
1046 TRACE_INSN (cpu
, "c.add %s, %s; // %s += %s",
1047 rd_name
, rs2_name
, rd_name
, rs2_name
);
1048 store_rd (cpu
, rd
, riscv_cpu
->regs
[rd
] + riscv_cpu
->regs
[rs2
]);
1051 TRACE_INSN (cpu
, "c.jalr %s, %s;",
1052 riscv_gpr_names_abi
[SIM_RISCV_RA_REGNUM
], rd_name
);
1053 store_rd (cpu
, SIM_RISCV_RA_REGNUM
, riscv_cpu
->pc
+ 2);
1054 pc
= riscv_cpu
->regs
[rd
];
1055 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
1058 TRACE_INSN (cpu
, "ebreak");
1059 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_stopped
,
1064 imm
= EXTRACT_CBTYPE_IMM (iw
);
1065 TRACE_INSN (cpu
, "c.beqz %s, %#" PRIxTW
"; "
1066 "// if (%s == 0) goto %#" PRIxTW
,
1067 rs1_c_name
, imm
, rs1_c_name
, riscv_cpu
->pc
+ imm
);
1068 if (riscv_cpu
->regs
[rs1_c
] == riscv_cpu
->regs
[0])
1070 pc
= riscv_cpu
->pc
+ imm
;
1071 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
1075 imm
= EXTRACT_CBTYPE_IMM (iw
);
1076 TRACE_INSN (cpu
, "c.bnez %s, %#" PRIxTW
"; "
1077 "// if (%s != 0) goto %#" PRIxTW
,
1078 rs1_c_name
, imm
, rs1_c_name
, riscv_cpu
->pc
+ imm
);
1079 if (riscv_cpu
->regs
[rs1_c
] != riscv_cpu
->regs
[0])
1081 pc
= riscv_cpu
->pc
+ imm
;
1082 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
1086 imm
= EXTRACT_CITYPE_LWSP_IMM (iw
);
1087 TRACE_INSN (cpu
, "c.lwsp %s, %" PRIiTW
"(sp);",
1089 store_rd (cpu
, rd
, EXTEND32 (
1090 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
1091 riscv_cpu
->regs
[SIM_RISCV_SP_REGNUM
]
1095 imm
= EXTRACT_CLTYPE_LW_IMM (iw
);
1096 TRACE_INSN (cpu
, "c.lw %s, %" PRIiTW
"(%s);",
1097 rs2_c_name
, imm
, rs1_c_name
);
1098 store_rd (cpu
, rs2_c
, EXTEND32 (
1099 sim_core_read_unaligned_4 (cpu
, riscv_cpu
->pc
, read_map
,
1100 riscv_cpu
->regs
[rs1_c
] + imm
)));
1103 imm
= EXTRACT_CSSTYPE_SWSP_IMM (iw
);
1104 TRACE_INSN (cpu
, "c.swsp %s, %" PRIiTW
"(sp);",
1106 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
1107 riscv_cpu
->regs
[SIM_RISCV_SP_REGNUM
] + imm
,
1108 riscv_cpu
->regs
[rs2
]);
1111 imm
= EXTRACT_CLTYPE_LW_IMM (iw
);
1112 TRACE_INSN (cpu
, "c.sw %s, %" PRIiTW
"(%s);",
1113 rs2_c_name
, imm
, rs1_c_name
);
1114 sim_core_write_unaligned_4 (cpu
, riscv_cpu
->pc
, write_map
,
1115 riscv_cpu
->regs
[rs1_c
] + (imm
),
1116 riscv_cpu
->regs
[rs2_c
]);
1119 imm
= EXTRACT_CITYPE_IMM (iw
);
1120 TRACE_INSN (cpu
, "c.addi %s, %s, %#" PRIxTW
"; // %s += %#" PRIxTW
,
1121 rd_name
, rd_name
, imm
, rd_name
, imm
);
1122 store_rd (cpu
, rd
, riscv_cpu
->regs
[rd
] + imm
);
1125 imm
= EXTRACT_CITYPE_LUI_IMM (iw
);
1126 TRACE_INSN (cpu
, "c.lui %s, %#" PRIxTW
";",
1128 store_rd (cpu
, rd
, imm
);
1131 imm
= EXTRACT_CITYPE_IMM (iw
);
1132 TRACE_INSN (cpu
, "c.li %s, %#" PRIxTW
"; // %s = %#" PRIxTW
,
1133 rd_name
, imm
, rd_name
, imm
);
1134 store_rd (cpu
, rd
, imm
);
1136 case MATCH_C_ADDI4SPN
:
1137 imm
= EXTRACT_CIWTYPE_ADDI4SPN_IMM (iw
);
1138 TRACE_INSN (cpu
, "c.addi4spn %s, %" PRIiTW
"; // %s = sp + %" PRIiTW
,
1139 rs2_c_name
, imm
, rs2_c_name
, imm
);
1140 store_rd (cpu
, rs2_c
, riscv_cpu
->regs
[SIM_RISCV_SP_REGNUM
] + (imm
));
1142 case MATCH_C_ADDI16SP
:
1143 imm
= EXTRACT_CITYPE_ADDI16SP_IMM (iw
);
1144 TRACE_INSN (cpu
, "c.addi16sp %s, %" PRIiTW
"; // %s = sp + %" PRIiTW
,
1145 rd_name
, imm
, rd_name
, imm
);
1146 store_rd (cpu
, rd
, riscv_cpu
->regs
[SIM_RISCV_SP_REGNUM
] + imm
);
1149 TRACE_INSN (cpu
, "c.sub %s, %s; // %s = %s - %s",
1150 rs1_c_name
, rs2_c_name
, rs1_c_name
, rs1_c_name
, rs2_c_name
);
1151 store_rd (cpu
, rs1_c
, riscv_cpu
->regs
[rs1_c
] - riscv_cpu
->regs
[rs2_c
]);
1154 TRACE_INSN (cpu
, "c.and %s, %s; // %s = %s & %s",
1155 rs1_c_name
, rs2_c_name
, rs1_c_name
, rs1_c_name
, rs2_c_name
);
1156 store_rd (cpu
, rs1_c
, riscv_cpu
->regs
[rs1_c
] & riscv_cpu
->regs
[rs2_c
]);
1159 TRACE_INSN (cpu
, "c.or %s, %s; // %s = %s | %s",
1160 rs1_c_name
, rs2_c_name
, rs1_c_name
, rs1_c_name
, rs2_c_name
);
1161 store_rd (cpu
, rs1_c
, riscv_cpu
->regs
[rs1_c
] | riscv_cpu
->regs
[rs2_c
]);
1164 TRACE_INSN (cpu
, "c.xor %s, %s; // %s = %s ^ %s",
1165 rs1_c_name
, rs2_c_name
, rs1_c_name
, rs1_c_name
, rs2_c_name
);
1166 store_rd (cpu
, rs1_c
, riscv_cpu
->regs
[rs1_c
] ^ riscv_cpu
->regs
[rs2_c
]);
1168 case MATCH_C_SLLI
| MATCH_C_SLLI64
:
1169 if (op
->mask
== MASK_C_SLLI64
)
1171 /* Reserved for custom use. */
1172 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
1173 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
1177 imm
= EXTRACT_CITYPE_IMM (iw
);
1178 TRACE_INSN (cpu
, "c.slli %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
1179 rd_name
, imm
, rd_name
, rd_name
, imm
);
1180 store_rd (cpu
, rd
, riscv_cpu
->regs
[rd
] << imm
);
1182 case MATCH_C_SRLI
| MATCH_C_SRLI64
:
1183 if (op
->mask
== MASK_C_SRLI64
)
1185 /* Reserved for custom use. */
1186 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
1187 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
1191 imm
= EXTRACT_CITYPE_IMM (iw
);
1192 TRACE_INSN (cpu
, "c.srli %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
1193 rs1_c_name
, imm
, rs1_c_name
, rs1_c_name
, imm
);
1194 if (RISCV_XLEN (cpu
) == 32)
1195 store_rd (cpu
, rs1_c
,
1196 EXTEND32 ((uint32_t) riscv_cpu
->regs
[rs1_c
] >> imm
));
1198 store_rd (cpu
, rs1_c
, riscv_cpu
->regs
[rs1_c
] >> imm
);
1200 case MATCH_C_SRAI
| MATCH_C_SRAI64
:
1201 if (op
->mask
== MASK_C_SRAI64
)
1203 /* Reserved for custom use. */
1204 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
1205 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
1209 imm
= EXTRACT_CITYPE_IMM (iw
);
1210 TRACE_INSN (cpu
, "c.srai %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
1211 rs1_c_name
, imm
, rs1_c_name
, rs1_c_name
, imm
);
1212 if (RISCV_XLEN (cpu
) == 32)
1215 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
1217 tmp
= ashiftrt (riscv_cpu
->regs
[rs1_c
], imm
);
1220 tmp
= ashiftrt64 (riscv_cpu
->regs
[rs1_c
], imm
);
1221 store_rd (cpu
, rd
, tmp
);
1224 imm
= EXTRACT_CITYPE_IMM (iw
);
1225 TRACE_INSN (cpu
, "c.andi %s, %" PRIiTW
"; // %s = %s & %#" PRIxTW
,
1226 rs1_c_name
, imm
, rs1_c_name
, rs1_c_name
, imm
);
1227 store_rd (cpu
, rs1_c
, riscv_cpu
->regs
[rs1_c
] & imm
);
1230 TRACE_INSN (cpu
, "c.addw %s, %s; // %s = %s + %s",
1231 rs1_c_name
, rs2_c_name
, rs1_c_name
, rs1_c_name
, rs2_c_name
);
1232 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
1233 store_rd (cpu
, rs1_c
,
1234 EXTEND32 (riscv_cpu
->regs
[rs1_c
] + riscv_cpu
->regs
[rs2_c
]));
1237 TRACE_INSN (cpu
, "c.subw %s, %s; // %s = %s - %s",
1238 rs1_c_name
, rs2_c_name
, rs1_c_name
, rs1_c_name
, rs2_c_name
);
1239 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
1240 store_rd (cpu
, rs1_c
,
1241 EXTEND32 (riscv_cpu
->regs
[rs1_c
] - riscv_cpu
->regs
[rs2_c
]));
1244 imm
= EXTRACT_CITYPE_LDSP_IMM (iw
);
1245 TRACE_INSN (cpu
, "c.ldsp %s, %" PRIiTW
"(sp);",
1247 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
1249 sim_core_read_unaligned_8 (cpu
, riscv_cpu
->pc
, read_map
,
1250 riscv_cpu
->regs
[SIM_RISCV_SP_REGNUM
]
1254 imm
= EXTRACT_CLTYPE_LD_IMM (iw
);
1255 TRACE_INSN (cpu
, "c.ld %s, %" PRIiTW
"(%s);",
1256 rs1_c_name
, imm
, rs2_c_name
);
1257 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
1258 store_rd (cpu
, rs2_c
,
1259 sim_core_read_unaligned_8 (cpu
, riscv_cpu
->pc
, read_map
,
1260 riscv_cpu
->regs
[rs1_c
] + imm
));
1263 imm
= EXTRACT_CSSTYPE_SDSP_IMM (iw
);
1264 TRACE_INSN (cpu
, "c.sdsp %s, %" PRIiTW
"(sp);",
1266 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
1267 sim_core_write_unaligned_8 (cpu
, riscv_cpu
->pc
, write_map
,
1268 riscv_cpu
->regs
[SIM_RISCV_SP_REGNUM
] + imm
,
1269 riscv_cpu
->regs
[rs2
]);
1272 imm
= EXTRACT_CLTYPE_LD_IMM (iw
);
1273 TRACE_INSN (cpu
, "c.sd %s, %" PRIiTW
"(%s);",
1274 rs2_c_name
, imm
, rs1_c_name
);
1275 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
1276 sim_core_write_unaligned_8 (cpu
, riscv_cpu
->pc
, write_map
,
1277 riscv_cpu
->regs
[rs1_c
] + imm
,
1278 riscv_cpu
->regs
[rs2_c
]);
1281 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
1282 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
1290 execute_one (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
1292 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1293 SIM_DESC sd
= CPU_STATE (cpu
);
1295 if (op
->xlen_requirement
== 32)
1296 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
1297 else if (op
->xlen_requirement
== 64)
1298 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
1300 switch (op
->insn_class
)
1302 case INSN_CLASS_ZAAMO
:
1303 case INSN_CLASS_ZALRSC
:
1304 return execute_a (cpu
, iw
, op
);
1306 /* Check whether model with C extension is selected. */
1307 if (riscv_cpu
->csr
.misa
& 4)
1308 return execute_c (cpu
, iw
, op
);
1311 TRACE_INSN (cpu
, "UNHANDLED EXTENSION: %d", op
->insn_class
);
1312 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
,
1316 return execute_i (cpu
, iw
, op
);
1318 case INSN_CLASS_ZMMUL
:
1319 return execute_m (cpu
, iw
, op
);
1321 TRACE_INSN (cpu
, "UNHANDLED EXTENSION: %d", op
->insn_class
);
1322 sim_engine_halt (sd
, cpu
, NULL
, riscv_cpu
->pc
, sim_signalled
, SIM_SIGILL
);
1325 return riscv_cpu
->pc
+ riscv_insn_length (iw
);
1328 /* Decode & execute a single instruction. */
1329 void step_once (SIM_CPU
*cpu
)
1331 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1332 SIM_DESC sd
= CPU_STATE (cpu
);
1335 sim_cia pc
= riscv_cpu
->pc
;
1336 const struct riscv_opcode
*op
;
1337 int xlen
= RISCV_XLEN (cpu
);
1339 if (TRACE_ANY_P (cpu
))
1340 trace_prefix (sd
, cpu
, NULL_CIA
, pc
, TRACE_LINENUM_P (cpu
),
1341 NULL
, 0, " "); /* Use a space for gcc warnings. */
1343 iw
= sim_core_read_aligned_2 (cpu
, pc
, exec_map
, pc
);
1345 len
= riscv_insn_length (iw
);
1346 if (len
!= 4 && len
!= 2)
1348 sim_io_printf (sd
, "sim: bad insn len %#x @ %#" PRIxTA
": %#" PRIxTW
"\n",
1350 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
1354 iw
|= ((unsigned_word
) sim_core_read_aligned_2
1355 (cpu
, pc
, exec_map
, pc
+ 2) << 16);
1357 TRACE_CORE (cpu
, "0x%08" PRIxTW
, iw
);
1359 op
= riscv_hash
[OP_HASH_IDX (iw
)];
1361 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
1363 /* NB: Same loop logic as riscv_disassemble_insn. */
1364 for (; op
->name
; op
++)
1366 /* Does the opcode match? */
1367 if (! op
->match_func
|| ! op
->match_func (op
, iw
))
1369 /* Is this a pseudo-instruction and may we print it as such? */
1370 if (op
->pinfo
& INSN_ALIAS
)
1372 /* Is this instruction restricted to a certain value of XLEN? */
1373 if (op
->xlen_requirement
!= 0 && op
->xlen_requirement
!= xlen
)
1377 pc
= execute_one (cpu
, iw
, op
);
1381 /* TODO: Handle overflow into high 32 bits. */
1382 /* TODO: Try to use a common counter and only update on demand (reads). */
1383 ++riscv_cpu
->csr
.cycle
;
1384 ++riscv_cpu
->csr
.instret
;
1389 /* Return the program counter for this cpu. */
1391 pc_get (sim_cpu
*cpu
)
1393 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1395 return riscv_cpu
->pc
;
1398 /* Set the program counter for this cpu to the new pc value. */
1400 pc_set (sim_cpu
*cpu
, sim_cia pc
)
1402 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1408 reg_fetch (sim_cpu
*cpu
, int rn
, void *buf
, int len
)
1410 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1412 if (len
<= 0 || len
> sizeof (unsigned_word
))
1417 case SIM_RISCV_ZERO_REGNUM
:
1418 memset (buf
, 0, len
);
1420 case SIM_RISCV_RA_REGNUM
... SIM_RISCV_T6_REGNUM
:
1421 memcpy (buf
, &riscv_cpu
->regs
[rn
], len
);
1423 case SIM_RISCV_FIRST_FP_REGNUM
... SIM_RISCV_LAST_FP_REGNUM
:
1424 memcpy (buf
, &riscv_cpu
->fpregs
[rn
- SIM_RISCV_FIRST_FP_REGNUM
], len
);
1426 case SIM_RISCV_PC_REGNUM
:
1427 memcpy (buf
, &riscv_cpu
->pc
, len
);
1430 #define DECLARE_CSR(name, num, ...) \
1431 case SIM_RISCV_ ## num ## _REGNUM: \
1432 memcpy (buf, &riscv_cpu->csr.name, len); \
1434 #include "opcode/riscv-opc.h"
1443 reg_store (sim_cpu
*cpu
, int rn
, const void *buf
, int len
)
1445 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1447 if (len
<= 0 || len
> sizeof (unsigned_word
))
1452 case SIM_RISCV_ZERO_REGNUM
:
1453 /* Ignore writes. */
1455 case SIM_RISCV_RA_REGNUM
... SIM_RISCV_T6_REGNUM
:
1456 memcpy (&riscv_cpu
->regs
[rn
], buf
, len
);
1458 case SIM_RISCV_FIRST_FP_REGNUM
... SIM_RISCV_LAST_FP_REGNUM
:
1459 memcpy (&riscv_cpu
->fpregs
[rn
- SIM_RISCV_FIRST_FP_REGNUM
], buf
, len
);
1461 case SIM_RISCV_PC_REGNUM
:
1462 memcpy (&riscv_cpu
->pc
, buf
, len
);
1465 #define DECLARE_CSR(name, num, ...) \
1466 case SIM_RISCV_ ## num ## _REGNUM: \
1467 memcpy (&riscv_cpu->csr.name, buf, len); \
1469 #include "opcode/riscv-opc.h"
1477 /* Initialize the state for a single cpu. Usuaully this involves clearing all
1478 registers back to their reset state. Should also hook up the fetch/store
1479 helper functions too. */
1481 initialize_cpu (SIM_DESC sd
, SIM_CPU
*cpu
, int mhartid
)
1483 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1484 const char *extensions
;
1487 memset (riscv_cpu
->regs
, 0, sizeof (riscv_cpu
->regs
));
1489 CPU_PC_FETCH (cpu
) = pc_get
;
1490 CPU_PC_STORE (cpu
) = pc_set
;
1491 CPU_REG_FETCH (cpu
) = reg_fetch
;
1492 CPU_REG_STORE (cpu
) = reg_store
;
1496 const struct riscv_opcode
*op
;
1498 for (op
= riscv_opcodes
; op
->name
; op
++)
1499 if (!riscv_hash
[OP_HASH_IDX (op
->match
)])
1500 riscv_hash
[OP_HASH_IDX (op
->match
)] = op
;
1503 riscv_cpu
->csr
.misa
= 0;
1504 /* RV32 sets this field to 0, and we don't really support RV128 yet. */
1505 if (RISCV_XLEN (cpu
) == 64)
1506 riscv_cpu
->csr
.misa
|= (uint64_t)2 << 62;
1508 /* Skip the leading "rv" prefix and the two numbers. */
1509 extensions
= MODEL_NAME (CPU_MODEL (cpu
)) + 4;
1510 for (i
= 0; i
< 26; ++i
)
1516 else if (strchr (extensions
, ext
) != NULL
)
1519 riscv_cpu
->csr
.misa
|= 0x1129; /* G = IMAFD. */
1521 riscv_cpu
->csr
.misa
|= (1 << i
);
1525 riscv_cpu
->csr
.mimpid
= 0x8000;
1526 riscv_cpu
->csr
.mhartid
= mhartid
;
1529 /* Some utils don't like having a NULL environ. */
1530 static const char * const simple_env
[] = { "HOME=/", "PATH=/bin", NULL
};
1532 /* Count the number of arguments in an argv. */
1534 count_argv (const char * const *argv
)
1541 for (i
= 0; argv
[i
] != NULL
; ++i
)
1547 initialize_env (SIM_DESC sd
, const char * const *argv
, const char * const *env
)
1549 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
1550 struct riscv_sim_cpu
*riscv_cpu
= RISCV_SIM_CPU (cpu
);
1552 int argc
, argv_flat
;
1554 address_word sp
, sp_flat
;
1555 unsigned char null
[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
1557 /* Figure out how many bytes the argv strings take up. */
1558 argc
= count_argv (argv
);
1561 argv_flat
= argc
; /* NUL bytes. */
1562 for (i
= 0; i
< argc
; ++i
)
1563 argv_flat
+= strlen (argv
[i
]);
1565 /* Figure out how many bytes the environ strings take up. */
1568 envc
= count_argv (env
);
1569 env_flat
= envc
; /* NUL bytes. */
1570 for (i
= 0; i
< envc
; ++i
)
1571 env_flat
+= strlen (env
[i
]);
1573 /* Make space for the strings themselves. */
1574 sp_flat
= (DEFAULT_MEM_SIZE
- argv_flat
- env_flat
) & -sizeof (address_word
);
1575 /* Then the pointers to the strings. */
1576 sp
= sp_flat
- ((argc
+ 1 + envc
+ 1) * sizeof (address_word
));
1577 /* Then the argc. */
1578 sp
-= sizeof (unsigned_word
);
1579 /* Align to 16 bytes. */
1580 sp
= align_down (sp
, 16);
1582 /* Set up the regs the libgloss crt0 expects. */
1583 riscv_cpu
->a0
= argc
;
1586 /* First push the argc value. */
1587 sim_write (sd
, sp
, &argc
, sizeof (unsigned_word
));
1588 sp
+= sizeof (unsigned_word
);
1590 /* Then the actual argv strings so we know where to point argv[]. */
1591 for (i
= 0; i
< argc
; ++i
)
1593 unsigned len
= strlen (argv
[i
]) + 1;
1594 sim_write (sd
, sp_flat
, argv
[i
], len
);
1595 sim_write (sd
, sp
, &sp_flat
, sizeof (address_word
));
1597 sp
+= sizeof (address_word
);
1599 sim_write (sd
, sp
, null
, sizeof (address_word
));
1600 sp
+= sizeof (address_word
);
1602 /* Then the actual env strings so we know where to point env[]. */
1603 for (i
= 0; i
< envc
; ++i
)
1605 unsigned len
= strlen (env
[i
]) + 1;
1606 sim_write (sd
, sp_flat
, env
[i
], len
);
1607 sim_write (sd
, sp
, &sp_flat
, sizeof (address_word
));
1609 sp
+= sizeof (address_word
);