3 Copyright (C) 2005-2021 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 "gdb/sim-riscv.h"
38 #include "targ-vals.h"
40 #define TRACE_REG(cpu, reg) \
41 TRACE_REGISTER (cpu, "wrote %s = %#" PRIxTW, riscv_gpr_names_abi[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, cpu->pc, sim_signalled, SIM_SIGILL); \
57 #define RISCV_ASSERT_RV64(cpu, fmt, args...) \
59 if (RISCV_XLEN (cpu) != 64) \
61 SIM_DESC sd = CPU_STATE (cpu); \
62 TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \
63 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
68 store_rd (SIM_CPU
*cpu
, int rd
, unsigned_word val
)
77 static INLINE unsigned_word
78 fetch_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
)
80 /* Handle pseudo registers. */
83 /* Allow certain registers only in respective modes. */
87 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
95 store_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
,
100 /* These are pseudo registers that modify sub-fields of fcsr. */
104 cpu
->csr
.fcsr
= (cpu
->csr
.fcsr
& ~0xe0) | (val
<< 5);
109 cpu
->csr
.fcsr
= (cpu
->csr
.fcsr
& ~0x1f) | val
;
111 /* Keep the sub-fields in sync. */
114 cpu
->csr
.frm
= (val
>> 5) & 0x7;
115 cpu
->csr
.fflags
= val
& 0x1f;
118 /* Allow certain registers only in respective modes. */
122 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
124 /* All the rest are immutable. */
130 TRACE_REGISTER (cpu
, "wrote CSR %s = %#" PRIxTW
, name
, val
);
133 static inline unsigned_word
134 ashiftrt (unsigned_word val
, unsigned_word shift
)
136 unsigned32 sign
= (val
& 0x80000000) ? ~(0xfffffffful
>> shift
) : 0;
137 return (val
>> shift
) | sign
;
140 static inline unsigned_word
141 ashiftrt64 (unsigned_word val
, unsigned_word shift
)
144 (val
& 0x8000000000000000ull
) ? ~(0xffffffffffffffffull
>> shift
) : 0;
145 return (val
>> shift
) | sign
;
149 execute_i (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
151 SIM_DESC sd
= CPU_STATE (cpu
);
152 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
153 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
154 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
155 const char *rd_name
= riscv_gpr_names_abi
[rd
];
156 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
157 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
158 unsigned int csr
= (iw
>> OP_SH_CSR
) & OP_MASK_CSR
;
159 unsigned_word i_imm
= EXTRACT_ITYPE_IMM (iw
);
160 unsigned_word u_imm
= EXTRACT_UTYPE_IMM ((unsigned64
) iw
);
161 unsigned_word s_imm
= EXTRACT_STYPE_IMM (iw
);
162 unsigned_word sb_imm
= EXTRACT_BTYPE_IMM (iw
);
163 unsigned_word shamt_imm
= ((iw
>> OP_SH_SHAMT
) & OP_MASK_SHAMT
);
165 sim_cia pc
= cpu
->pc
+ 4;
169 "rs1:%-2i:%-4s %0*" PRIxTW
" "
170 "rs2:%-2i:%-4s %0*" PRIxTW
" "
171 "match:%#x mask:%#x",
173 rs1
, rs1_name
, (int) sizeof (unsigned_word
) * 2, cpu
->regs
[rs1
],
174 rs2
, rs2_name
, (int) sizeof (unsigned_word
) * 2, cpu
->regs
[rs2
],
175 (unsigned) op
->match
, (unsigned) op
->mask
);
180 TRACE_INSN (cpu
, "add %s, %s, %s; // %s = %s + %s",
181 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
182 store_rd (cpu
, rd
, cpu
->regs
[rs1
] + cpu
->regs
[rs2
]);
185 TRACE_INSN (cpu
, "addw %s, %s, %s; // %s = %s + %s",
186 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
187 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
188 store_rd (cpu
, rd
, EXTEND32 (cpu
->regs
[rs1
] + cpu
->regs
[rs2
]));
191 TRACE_INSN (cpu
, "addi %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
192 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
193 store_rd (cpu
, rd
, cpu
->regs
[rs1
] + i_imm
);
196 TRACE_INSN (cpu
, "addiw %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
197 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
198 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
199 store_rd (cpu
, rd
, EXTEND32 (cpu
->regs
[rs1
] + i_imm
));
202 TRACE_INSN (cpu
, "and %s, %s, %s; // %s = %s & %s",
203 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
204 store_rd (cpu
, rd
, cpu
->regs
[rs1
] & cpu
->regs
[rs2
]);
207 TRACE_INSN (cpu
, "andi %s, %s, %" PRIiTW
"; // %s = %s & %#" PRIxTW
,
208 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
209 store_rd (cpu
, rd
, cpu
->regs
[rs1
] & i_imm
);
212 TRACE_INSN (cpu
, "or %s, %s, %s; // %s = %s | %s",
213 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
214 store_rd (cpu
, rd
, cpu
->regs
[rs1
] | cpu
->regs
[rs2
]);
217 TRACE_INSN (cpu
, "ori %s, %s, %" PRIiTW
"; // %s = %s | %#" PRIxTW
,
218 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
219 store_rd (cpu
, rd
, cpu
->regs
[rs1
] | i_imm
);
222 TRACE_INSN (cpu
, "xor %s, %s, %s; // %s = %s ^ %s",
223 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
224 store_rd (cpu
, rd
, cpu
->regs
[rs1
] ^ cpu
->regs
[rs2
]);
227 TRACE_INSN (cpu
, "xori %s, %s, %" PRIiTW
"; // %s = %s ^ %#" PRIxTW
,
228 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
229 store_rd (cpu
, rd
, cpu
->regs
[rs1
] ^ i_imm
);
232 TRACE_INSN (cpu
, "sub %s, %s, %s; // %s = %s - %s",
233 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
234 store_rd (cpu
, rd
, cpu
->regs
[rs1
] - cpu
->regs
[rs2
]);
237 TRACE_INSN (cpu
, "subw %s, %s, %s; // %s = %s - %s",
238 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
239 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
240 store_rd (cpu
, rd
, EXTEND32 (cpu
->regs
[rs1
] - cpu
->regs
[rs2
]));
243 TRACE_INSN (cpu
, "lui %s, %#" PRIxTW
";", rd_name
, u_imm
);
244 store_rd (cpu
, rd
, u_imm
);
247 TRACE_INSN (cpu
, "sll %s, %s, %s; // %s = %s << %s",
248 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
249 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
250 store_rd (cpu
, rd
, cpu
->regs
[rs1
] << (cpu
->regs
[rs2
] & u_imm
));
253 TRACE_INSN (cpu
, "sllw %s, %s, %s; // %s = %s << %s",
254 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
255 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
256 store_rd (cpu
, rd
, EXTEND32 (
257 (unsigned32
) cpu
->regs
[rs1
] << (cpu
->regs
[rs2
] & 0x1f)));
260 TRACE_INSN (cpu
, "slli %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
261 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
262 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
263 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
264 store_rd (cpu
, rd
, cpu
->regs
[rs1
] << shamt_imm
);
267 TRACE_INSN (cpu
, "slliw %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
268 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
269 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
270 store_rd (cpu
, rd
, EXTEND32 ((unsigned32
) cpu
->regs
[rs1
] << shamt_imm
));
273 TRACE_INSN (cpu
, "srl %s, %s, %s; // %s = %s >> %s",
274 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
275 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
276 store_rd (cpu
, rd
, cpu
->regs
[rs1
] >> (cpu
->regs
[rs2
] & u_imm
));
279 TRACE_INSN (cpu
, "srlw %s, %s, %s; // %s = %s >> %s",
280 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
281 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
282 store_rd (cpu
, rd
, EXTEND32 (
283 (unsigned32
) cpu
->regs
[rs1
] >> (cpu
->regs
[rs2
] & 0x1f)));
286 TRACE_INSN (cpu
, "srli %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
287 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
288 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
289 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
290 store_rd (cpu
, rd
, cpu
->regs
[rs1
] >> shamt_imm
);
293 TRACE_INSN (cpu
, "srliw %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
294 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
295 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
296 store_rd (cpu
, rd
, EXTEND32 ((unsigned32
) cpu
->regs
[rs1
] >> shamt_imm
));
299 TRACE_INSN (cpu
, "sra %s, %s, %s; // %s = %s >>> %s",
300 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
301 if (RISCV_XLEN (cpu
) == 32)
302 tmp
= ashiftrt (cpu
->regs
[rs1
], cpu
->regs
[rs2
] & 0x1f);
304 tmp
= ashiftrt64 (cpu
->regs
[rs1
], cpu
->regs
[rs2
] & 0x3f);
305 store_rd (cpu
, rd
, tmp
);
308 TRACE_INSN (cpu
, "sraw %s, %s, %s; // %s = %s >>> %s",
309 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
310 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
311 store_rd (cpu
, rd
, EXTEND32 (
312 ashiftrt ((signed32
) cpu
->regs
[rs1
], cpu
->regs
[rs2
] & 0x1f)));
315 TRACE_INSN (cpu
, "srai %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
316 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
317 if (RISCV_XLEN (cpu
) == 32)
319 if (shamt_imm
> 0x1f)
320 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
321 tmp
= ashiftrt (cpu
->regs
[rs1
], shamt_imm
);
324 tmp
= ashiftrt64 (cpu
->regs
[rs1
], shamt_imm
);
325 store_rd (cpu
, rd
, tmp
);
328 TRACE_INSN (cpu
, "sraiw %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
329 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
330 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
331 store_rd (cpu
, rd
, EXTEND32 (
332 ashiftrt ((signed32
) cpu
->regs
[rs1
], shamt_imm
)));
335 TRACE_INSN (cpu
, "slt");
337 !!((signed_word
) cpu
->regs
[rs1
] < (signed_word
) cpu
->regs
[rs2
]));
340 TRACE_INSN (cpu
, "sltu");
341 store_rd (cpu
, rd
, !!((unsigned_word
) cpu
->regs
[rs1
] <
342 (unsigned_word
) cpu
->regs
[rs2
]));
345 TRACE_INSN (cpu
, "slti");
346 store_rd (cpu
, rd
, !!((signed_word
) cpu
->regs
[rs1
] <
347 (signed_word
) i_imm
));
350 TRACE_INSN (cpu
, "sltiu");
351 store_rd (cpu
, rd
, !!((unsigned_word
) cpu
->regs
[rs1
] <
352 (unsigned_word
) i_imm
));
355 TRACE_INSN (cpu
, "auipc %s, %" PRIiTW
"; // %s = pc + %" PRIiTW
,
356 rd_name
, u_imm
, rd_name
, u_imm
);
357 store_rd (cpu
, rd
, cpu
->pc
+ u_imm
);
360 TRACE_INSN (cpu
, "beq %s, %s, %#" PRIxTW
"; "
361 "// if (%s == %s) goto %#" PRIxTW
,
362 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
363 if (cpu
->regs
[rs1
] == cpu
->regs
[rs2
])
365 pc
= cpu
->pc
+ sb_imm
;
366 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
370 TRACE_INSN (cpu
, "blt %s, %s, %#" PRIxTW
"; "
371 "// if (%s < %s) goto %#" PRIxTW
,
372 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
373 if ((signed_word
) cpu
->regs
[rs1
] < (signed_word
) cpu
->regs
[rs2
])
375 pc
= cpu
->pc
+ sb_imm
;
376 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
380 TRACE_INSN (cpu
, "bltu %s, %s, %#" PRIxTW
"; "
381 "// if (%s < %s) goto %#" PRIxTW
,
382 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
383 if ((unsigned_word
) cpu
->regs
[rs1
] < (unsigned_word
) cpu
->regs
[rs2
])
385 pc
= cpu
->pc
+ sb_imm
;
386 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
390 TRACE_INSN (cpu
, "bge %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
) cpu
->regs
[rs1
] >= (signed_word
) cpu
->regs
[rs2
])
395 pc
= cpu
->pc
+ sb_imm
;
396 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
400 TRACE_INSN (cpu
, "bgeu %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
) cpu
->regs
[rs1
] >= (unsigned_word
) cpu
->regs
[rs2
])
405 pc
= cpu
->pc
+ sb_imm
;
406 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
410 TRACE_INSN (cpu
, "bne %s, %s, %#" PRIxTW
"; "
411 "// if (%s != %s) goto %#" PRIxTW
,
412 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
413 if (cpu
->regs
[rs1
] != cpu
->regs
[rs2
])
415 pc
= cpu
->pc
+ sb_imm
;
416 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
420 TRACE_INSN (cpu
, "jal %s, %" PRIiTW
";", rd_name
,
421 EXTRACT_JTYPE_IMM (iw
));
422 store_rd (cpu
, rd
, cpu
->pc
+ 4);
423 pc
= cpu
->pc
+ EXTRACT_JTYPE_IMM (iw
);
424 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
427 TRACE_INSN (cpu
, "jalr %s, %s, %" PRIiTW
";", rd_name
, rs1_name
, i_imm
);
428 store_rd (cpu
, rd
, cpu
->pc
+ 4);
429 pc
= cpu
->regs
[rs1
] + i_imm
;
430 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
434 TRACE_INSN (cpu
, "ld %s, %" PRIiTW
"(%s);",
435 rd_name
, i_imm
, rs1_name
);
436 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
438 sim_core_read_unaligned_8 (cpu
, cpu
->pc
, read_map
,
439 cpu
->regs
[rs1
] + i_imm
));
442 TRACE_INSN (cpu
, "lw %s, %" PRIiTW
"(%s);",
443 rd_name
, i_imm
, rs1_name
);
444 store_rd (cpu
, rd
, EXTEND32 (
445 sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
,
446 cpu
->regs
[rs1
] + i_imm
)));
449 TRACE_INSN (cpu
, "lwu %s, %" PRIiTW
"(%s);",
450 rd_name
, i_imm
, rs1_name
);
452 sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
,
453 cpu
->regs
[rs1
] + i_imm
));
456 TRACE_INSN (cpu
, "lh %s, %" PRIiTW
"(%s);",
457 rd_name
, i_imm
, rs1_name
);
458 store_rd (cpu
, rd
, EXTEND16 (
459 sim_core_read_unaligned_2 (cpu
, cpu
->pc
, read_map
,
460 cpu
->regs
[rs1
] + i_imm
)));
463 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
464 rd_name
, i_imm
, rs1_name
);
466 sim_core_read_unaligned_2 (cpu
, cpu
->pc
, read_map
,
467 cpu
->regs
[rs1
] + i_imm
));
470 TRACE_INSN (cpu
, "lb %s, %" PRIiTW
"(%s);",
471 rd_name
, i_imm
, rs1_name
);
472 store_rd (cpu
, rd
, EXTEND8 (
473 sim_core_read_unaligned_1 (cpu
, cpu
->pc
, read_map
,
474 cpu
->regs
[rs1
] + i_imm
)));
477 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
478 rd_name
, i_imm
, rs1_name
);
480 sim_core_read_unaligned_1 (cpu
, cpu
->pc
, read_map
,
481 cpu
->regs
[rs1
] + i_imm
));
484 TRACE_INSN (cpu
, "sd %s, %" PRIiTW
"(%s);",
485 rs2_name
, s_imm
, rs1_name
);
486 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
487 sim_core_write_unaligned_8 (cpu
, cpu
->pc
, write_map
,
488 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
491 TRACE_INSN (cpu
, "sw %s, %" PRIiTW
"(%s);",
492 rs2_name
, s_imm
, rs1_name
);
493 sim_core_write_unaligned_4 (cpu
, cpu
->pc
, write_map
,
494 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
497 TRACE_INSN (cpu
, "sh %s, %" PRIiTW
"(%s);",
498 rs2_name
, s_imm
, rs1_name
);
499 sim_core_write_unaligned_2 (cpu
, cpu
->pc
, write_map
,
500 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
503 TRACE_INSN (cpu
, "sb %s, %" PRIiTW
"(%s);",
504 rs2_name
, s_imm
, rs1_name
);
505 sim_core_write_unaligned_1 (cpu
, cpu
->pc
, write_map
,
506 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
510 TRACE_INSN (cpu
, "csrrc");
513 #define DECLARE_CSR(name, num, ...) \
515 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
516 store_csr (cpu, #name, num, &cpu->csr.name, \
517 cpu->csr.name & !cpu->regs[rs1]); \
519 #include "opcode/riscv-opc.h"
524 TRACE_INSN (cpu
, "csrrs");
527 #define DECLARE_CSR(name, num, ...) \
529 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
530 store_csr (cpu, #name, num, &cpu->csr.name, \
531 cpu->csr.name | cpu->regs[rs1]); \
533 #include "opcode/riscv-opc.h"
538 TRACE_INSN (cpu
, "csrrw");
541 #define DECLARE_CSR(name, num, ...) \
543 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
544 store_csr (cpu, #name, num, &cpu->csr.name, cpu->regs[rs1]); \
546 #include "opcode/riscv-opc.h"
552 TRACE_INSN (cpu
, "rdcycle %s;", rd_name
);
553 store_rd (cpu
, rd
, fetch_csr (cpu
, "cycle", CSR_CYCLE
, &cpu
->csr
.cycle
));
556 TRACE_INSN (cpu
, "rdcycleh %s;", rd_name
);
557 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
559 fetch_csr (cpu
, "cycleh", CSR_CYCLEH
, &cpu
->csr
.cycleh
));
561 case MATCH_RDINSTRET
:
562 TRACE_INSN (cpu
, "rdinstret %s;", rd_name
);
564 fetch_csr (cpu
, "instret", CSR_INSTRET
, &cpu
->csr
.instret
));
566 case MATCH_RDINSTRETH
:
567 TRACE_INSN (cpu
, "rdinstreth %s;", rd_name
);
568 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
570 fetch_csr (cpu
, "instreth", CSR_INSTRETH
, &cpu
->csr
.instreth
));
573 TRACE_INSN (cpu
, "rdtime %s;", rd_name
);
574 store_rd (cpu
, rd
, fetch_csr (cpu
, "time", CSR_TIME
, &cpu
->csr
.time
));
577 TRACE_INSN (cpu
, "rdtimeh %s;", rd_name
);
578 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
579 store_rd (cpu
, rd
, fetch_csr (cpu
, "timeh", CSR_TIMEH
, &cpu
->csr
.timeh
));
583 TRACE_INSN (cpu
, "fence;");
586 TRACE_INSN (cpu
, "fence.i;");
589 TRACE_INSN (cpu
, "sbreak;");
590 /* GDB expects us to step over SBREAK. */
591 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
+ 4, sim_stopped
, SIM_SIGTRAP
);
594 TRACE_INSN (cpu
, "ecall;");
595 cpu
->a0
= sim_syscall (cpu
, cpu
->a7
, cpu
->a0
, cpu
->a1
, cpu
->a2
, cpu
->a3
);
598 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
599 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
606 mulhu (unsigned64 a
, unsigned64 b
)
609 return ((__int128
)a
* b
) >> 64;
613 uint64_t a0
= (uint32_t)a
, a1
= a
>> 32;
614 uint64_t b0
= (uint32_t)b
, b1
= b
>> 32;
616 t
= a1
*b0
+ ((a0
*b0
) >> 32);
623 t
= a1
*b1
+ y2
+ (t
>> 32);
627 return ((uint64_t)y3
<< 32) | y2
;
632 mulh (signed64 a
, signed64 b
)
634 int negate
= (a
< 0) != (b
< 0);
635 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
< 0 ? -b
: b
);
636 return negate
? ~res
+ (a
* b
== 0) : res
;
640 mulhsu (signed64 a
, unsigned64 b
)
643 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
);
644 return negate
? ~res
+ (a
* b
== 0) : res
;
648 execute_m (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
650 SIM_DESC sd
= CPU_STATE (cpu
);
651 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
652 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
653 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
654 const char *rd_name
= riscv_gpr_names_abi
[rd
];
655 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
656 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
657 unsigned_word tmp
, dividend_max
;
658 sim_cia pc
= cpu
->pc
+ 4;
660 dividend_max
= -((unsigned_word
) 1 << (WITH_TARGET_WORD_BITSIZE
- 1));
665 TRACE_INSN (cpu
, "div %s, %s, %s; // %s = %s / %s",
666 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
667 if (cpu
->regs
[rs1
] == dividend_max
&& cpu
->regs
[rs2
] == -1)
669 else if (cpu
->regs
[rs2
])
670 tmp
= (signed_word
) cpu
->regs
[rs1
] / (signed_word
) cpu
->regs
[rs2
];
673 store_rd (cpu
, rd
, tmp
);
676 TRACE_INSN (cpu
, "divw %s, %s, %s; // %s = %s / %s",
677 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
678 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
679 if (EXTEND32 (cpu
->regs
[rs2
]) == -1)
681 else if (EXTEND32 (cpu
->regs
[rs2
]))
682 tmp
= EXTEND32 (cpu
->regs
[rs1
]) / EXTEND32 (cpu
->regs
[rs2
]);
685 store_rd (cpu
, rd
, EXTEND32 (tmp
));
688 TRACE_INSN (cpu
, "divu %s, %s, %s; // %s = %s / %s",
689 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
691 store_rd (cpu
, rd
, (unsigned_word
) cpu
->regs
[rs1
]
692 / (unsigned_word
) cpu
->regs
[rs2
]);
694 store_rd (cpu
, rd
, -1);
697 TRACE_INSN (cpu
, "divuw %s, %s, %s; // %s = %s / %s",
698 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
699 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
700 if ((unsigned32
) cpu
->regs
[rs2
])
701 tmp
= (unsigned32
) cpu
->regs
[rs1
] / (unsigned32
) cpu
->regs
[rs2
];
704 store_rd (cpu
, rd
, EXTEND32 (tmp
));
707 TRACE_INSN (cpu
, "mul %s, %s, %s; // %s = %s * %s",
708 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
709 store_rd (cpu
, rd
, cpu
->regs
[rs1
] * cpu
->regs
[rs2
]);
712 TRACE_INSN (cpu
, "mulw %s, %s, %s; // %s = %s * %s",
713 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
714 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
715 store_rd (cpu
, rd
, EXTEND32 ((signed32
) cpu
->regs
[rs1
]
716 * (signed32
) cpu
->regs
[rs2
]));
719 TRACE_INSN (cpu
, "mulh %s, %s, %s; // %s = %s * %s",
720 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
721 if (RISCV_XLEN (cpu
) == 32)
722 store_rd (cpu
, rd
, ((signed64
)(signed_word
) cpu
->regs
[rs1
]
723 * (signed64
)(signed_word
) cpu
->regs
[rs2
]) >> 32);
725 store_rd (cpu
, rd
, mulh (cpu
->regs
[rs1
], cpu
->regs
[rs2
]));
728 TRACE_INSN (cpu
, "mulhu %s, %s, %s; // %s = %s * %s",
729 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
730 if (RISCV_XLEN (cpu
) == 32)
731 store_rd (cpu
, rd
, ((unsigned64
)cpu
->regs
[rs1
]
732 * (unsigned64
)cpu
->regs
[rs2
]) >> 32);
734 store_rd (cpu
, rd
, mulhu (cpu
->regs
[rs1
], cpu
->regs
[rs2
]));
737 TRACE_INSN (cpu
, "mulhsu %s, %s, %s; // %s = %s * %s",
738 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
739 if (RISCV_XLEN (cpu
) == 32)
740 store_rd (cpu
, rd
, ((signed64
)(signed_word
) cpu
->regs
[rs1
]
741 * (unsigned64
)cpu
->regs
[rs2
]) >> 32);
743 store_rd (cpu
, rd
, mulhsu (cpu
->regs
[rs1
], cpu
->regs
[rs2
]));
746 TRACE_INSN (cpu
, "rem %s, %s, %s; // %s = %s %% %s",
747 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
748 if (cpu
->regs
[rs1
] == dividend_max
&& cpu
->regs
[rs2
] == -1)
750 else if (cpu
->regs
[rs2
])
751 tmp
= (signed_word
) cpu
->regs
[rs1
] % (signed_word
) cpu
->regs
[rs2
];
753 tmp
= cpu
->regs
[rs1
];
754 store_rd (cpu
, rd
, tmp
);
757 TRACE_INSN (cpu
, "remw %s, %s, %s; // %s = %s %% %s",
758 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
759 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
760 if (EXTEND32 (cpu
->regs
[rs2
]) == -1)
762 else if (EXTEND32 (cpu
->regs
[rs2
]))
763 tmp
= EXTEND32 (cpu
->regs
[rs1
]) % EXTEND32 (cpu
->regs
[rs2
]);
765 tmp
= cpu
->regs
[rs1
];
766 store_rd (cpu
, rd
, EXTEND32 (tmp
));
769 TRACE_INSN (cpu
, "remu %s, %s, %s; // %s = %s %% %s",
770 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
772 store_rd (cpu
, rd
, cpu
->regs
[rs1
] % cpu
->regs
[rs2
]);
774 store_rd (cpu
, rd
, cpu
->regs
[rs1
]);
777 TRACE_INSN (cpu
, "remuw %s, %s, %s; // %s = %s %% %s",
778 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
779 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
780 if ((unsigned32
) cpu
->regs
[rs2
])
781 tmp
= (unsigned32
) cpu
->regs
[rs1
] % (unsigned32
) cpu
->regs
[rs2
];
783 tmp
= cpu
->regs
[rs1
];
784 store_rd (cpu
, rd
, EXTEND32 (tmp
));
787 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
788 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
795 execute_a (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
797 SIM_DESC sd
= CPU_STATE (cpu
);
798 struct riscv_sim_state
*state
= RISCV_SIM_STATE (sd
);
799 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
800 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
801 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
802 const char *rd_name
= riscv_gpr_names_abi
[rd
];
803 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
804 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
805 struct atomic_mem_reserved_list
*amo_prev
, *amo_curr
;
807 sim_cia pc
= cpu
->pc
+ 4;
809 /* Handle these two load/store operations specifically. */
813 TRACE_INSN (cpu
, "%s %s, (%s);", op
->name
, rd_name
, rs1_name
);
815 sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
, cpu
->regs
[rs1
]));
817 /* Walk the reservation list to find an existing match. */
818 amo_curr
= state
->amo_reserved_list
;
821 if (amo_curr
->addr
== cpu
->regs
[rs1
])
823 amo_curr
= amo_curr
->next
;
826 /* No reservation exists, so add one. */
827 amo_curr
= xmalloc (sizeof (*amo_curr
));
828 amo_curr
->addr
= cpu
->regs
[rs1
];
829 amo_curr
->next
= state
->amo_reserved_list
;
830 state
->amo_reserved_list
= amo_curr
;
833 TRACE_INSN (cpu
, "%s %s, %s, (%s);", op
->name
, rd_name
, rs2_name
,
836 /* Walk the reservation list to find a match. */
837 amo_curr
= amo_prev
= state
->amo_reserved_list
;
840 if (amo_curr
->addr
== cpu
->regs
[rs1
])
842 /* We found a reservation, so operate it. */
843 sim_core_write_unaligned_4 (cpu
, cpu
->pc
, write_map
,
844 cpu
->regs
[rs1
], cpu
->regs
[rs2
]);
845 store_rd (cpu
, rd
, 0);
846 if (amo_curr
== state
->amo_reserved_list
)
847 state
->amo_reserved_list
= amo_curr
->next
;
849 amo_prev
->next
= amo_curr
->next
;
854 amo_curr
= amo_curr
->next
;
857 /* If we're still here, then no reservation exists, so mark as failed. */
858 store_rd (cpu
, rd
, 1);
862 /* Handle the rest of the atomic insns with common code paths. */
863 TRACE_INSN (cpu
, "%s %s, %s, (%s);",
864 op
->name
, rd_name
, rs2_name
, rs1_name
);
865 if (op
->xlen_requirement
== 64)
866 tmp
= sim_core_read_unaligned_8 (cpu
, cpu
->pc
, read_map
, cpu
->regs
[rs1
]);
868 tmp
= EXTEND32 (sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
,
870 store_rd (cpu
, rd
, tmp
);
876 tmp
= cpu
->regs
[rd
] + cpu
->regs
[rs2
];
880 tmp
= cpu
->regs
[rd
] & cpu
->regs
[rs2
];
884 tmp
= max ((signed_word
) cpu
->regs
[rd
], (signed_word
) cpu
->regs
[rs2
]);
886 case MATCH_AMOMAXU_D
:
887 case MATCH_AMOMAXU_W
:
888 tmp
= max ((unsigned_word
) cpu
->regs
[rd
], (unsigned_word
) cpu
->regs
[rs2
]);
892 tmp
= min ((signed_word
) cpu
->regs
[rd
], (signed_word
) cpu
->regs
[rs2
]);
894 case MATCH_AMOMINU_D
:
895 case MATCH_AMOMINU_W
:
896 tmp
= min ((unsigned_word
) cpu
->regs
[rd
], (unsigned_word
) cpu
->regs
[rs2
]);
900 tmp
= cpu
->regs
[rd
] | cpu
->regs
[rs2
];
902 case MATCH_AMOSWAP_D
:
903 case MATCH_AMOSWAP_W
:
904 tmp
= cpu
->regs
[rs2
];
908 tmp
= cpu
->regs
[rd
] ^ cpu
->regs
[rs2
];
911 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
912 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
915 if (op
->xlen_requirement
== 64)
916 sim_core_write_unaligned_8 (cpu
, cpu
->pc
, write_map
, cpu
->regs
[rs1
], tmp
);
918 sim_core_write_unaligned_4 (cpu
, cpu
->pc
, write_map
, cpu
->regs
[rs1
], tmp
);
925 execute_one (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
927 SIM_DESC sd
= CPU_STATE (cpu
);
929 if (op
->xlen_requirement
== 32)
930 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
931 else if (op
->xlen_requirement
== 64)
932 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
934 switch (op
->insn_class
)
937 return execute_a (cpu
, iw
, op
);
939 return execute_i (cpu
, iw
, op
);
941 return execute_m (cpu
, iw
, op
);
943 TRACE_INSN (cpu
, "UNHANDLED EXTENSION: %d", op
->insn_class
);
944 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
947 return cpu
->pc
+ riscv_insn_length (iw
);
950 /* Decode & execute a single instruction. */
951 void step_once (SIM_CPU
*cpu
)
953 SIM_DESC sd
= CPU_STATE (cpu
);
956 sim_cia pc
= cpu
->pc
;
957 const struct riscv_opcode
*op
;
958 int xlen
= RISCV_XLEN (cpu
);
960 if (TRACE_ANY_P (cpu
))
961 trace_prefix (sd
, cpu
, NULL_CIA
, pc
, TRACE_LINENUM_P (cpu
),
962 NULL
, 0, " "); /* Use a space for gcc warnings. */
964 iw
= sim_core_read_aligned_2 (cpu
, pc
, exec_map
, pc
);
966 /* Reject non-32-bit opcodes first. */
967 len
= riscv_insn_length (iw
);
970 sim_io_printf (sd
, "sim: bad insn len %#x @ %#" PRIxTA
": %#" PRIxTW
"\n",
972 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
975 iw
|= ((unsigned_word
) sim_core_read_aligned_2 (
976 cpu
, pc
, exec_map
, pc
+ 2) << 16);
978 TRACE_CORE (cpu
, "0x%08" PRIxTW
, iw
);
980 op
= riscv_hash
[OP_HASH_IDX (iw
)];
982 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
984 /* NB: Same loop logic as riscv_disassemble_insn. */
985 for (; op
->name
; op
++)
987 /* Does the opcode match? */
988 if (! op
->match_func (op
, iw
))
990 /* Is this a pseudo-instruction and may we print it as such? */
991 if (op
->pinfo
& INSN_ALIAS
)
993 /* Is this instruction restricted to a certain value of XLEN? */
994 if (op
->xlen_requirement
!= 0 && op
->xlen_requirement
!= xlen
)
998 pc
= execute_one (cpu
, iw
, op
);
1002 /* TODO: Handle overflow into high 32 bits. */
1003 /* TODO: Try to use a common counter and only update on demand (reads). */
1010 /* Return the program counter for this cpu. */
1012 pc_get (sim_cpu
*cpu
)
1017 /* Set the program counter for this cpu to the new pc value. */
1019 pc_set (sim_cpu
*cpu
, sim_cia pc
)
1025 reg_fetch (sim_cpu
*cpu
, int rn
, unsigned char *buf
, int len
)
1027 if (len
<= 0 || len
> sizeof (unsigned_word
))
1032 case SIM_RISCV_ZERO_REGNUM
:
1033 memset (buf
, 0, len
);
1035 case SIM_RISCV_RA_REGNUM
... SIM_RISCV_T6_REGNUM
:
1036 memcpy (buf
, &cpu
->regs
[rn
], len
);
1038 case SIM_RISCV_FIRST_FP_REGNUM
... SIM_RISCV_LAST_FP_REGNUM
:
1039 memcpy (buf
, &cpu
->fpregs
[rn
- SIM_RISCV_FIRST_FP_REGNUM
], len
);
1041 case SIM_RISCV_PC_REGNUM
:
1042 memcpy (buf
, &cpu
->pc
, len
);
1045 #define DECLARE_CSR(name, num, ...) \
1046 case SIM_RISCV_ ## num ## _REGNUM: \
1047 memcpy (buf, &cpu->csr.name, len); \
1049 #include "opcode/riscv-opc.h"
1058 reg_store (sim_cpu
*cpu
, int rn
, unsigned char *buf
, int len
)
1060 if (len
<= 0 || len
> sizeof (unsigned_word
))
1065 case SIM_RISCV_ZERO_REGNUM
:
1066 /* Ignore writes. */
1068 case SIM_RISCV_RA_REGNUM
... SIM_RISCV_T6_REGNUM
:
1069 memcpy (&cpu
->regs
[rn
], buf
, len
);
1071 case SIM_RISCV_FIRST_FP_REGNUM
... SIM_RISCV_LAST_FP_REGNUM
:
1072 memcpy (&cpu
->fpregs
[rn
- SIM_RISCV_FIRST_FP_REGNUM
], buf
, len
);
1074 case SIM_RISCV_PC_REGNUM
:
1075 memcpy (&cpu
->pc
, buf
, len
);
1078 #define DECLARE_CSR(name, num, ...) \
1079 case SIM_RISCV_ ## num ## _REGNUM: \
1080 memcpy (&cpu->csr.name, buf, len); \
1082 #include "opcode/riscv-opc.h"
1090 /* Initialize the state for a single cpu. Usuaully this involves clearing all
1091 registers back to their reset state. Should also hook up the fetch/store
1092 helper functions too. */
1094 initialize_cpu (SIM_DESC sd
, SIM_CPU
*cpu
, int mhartid
)
1096 const char *extensions
;
1099 memset (cpu
->regs
, 0, sizeof (cpu
->regs
));
1101 CPU_PC_FETCH (cpu
) = pc_get
;
1102 CPU_PC_STORE (cpu
) = pc_set
;
1103 CPU_REG_FETCH (cpu
) = reg_fetch
;
1104 CPU_REG_STORE (cpu
) = reg_store
;
1108 const struct riscv_opcode
*op
;
1110 for (op
= riscv_opcodes
; op
->name
; op
++)
1111 if (!riscv_hash
[OP_HASH_IDX (op
->match
)])
1112 riscv_hash
[OP_HASH_IDX (op
->match
)] = op
;
1116 /* RV32 sets this field to 0, and we don't really support RV128 yet. */
1117 if (RISCV_XLEN (cpu
) == 64)
1118 cpu
->csr
.misa
|= (unsigned64
)2 << 62;
1120 /* Skip the leading "rv" prefix and the two numbers. */
1121 extensions
= MODEL_NAME (CPU_MODEL (cpu
)) + 4;
1122 for (i
= 0; i
< 26; ++i
)
1128 else if (strchr (extensions
, ext
) != NULL
)
1131 cpu
->csr
.misa
|= 0x1129; /* G = IMAFD. */
1133 cpu
->csr
.misa
|= (1 << i
);
1137 cpu
->csr
.mimpid
= 0x8000;
1138 cpu
->csr
.mhartid
= mhartid
;
1141 /* Some utils don't like having a NULL environ. */
1142 static const char * const simple_env
[] = { "HOME=/", "PATH=/bin", NULL
};
1144 /* Count the number of arguments in an argv. */
1146 count_argv (const char * const *argv
)
1153 for (i
= 0; argv
[i
] != NULL
; ++i
)
1159 initialize_env (SIM_DESC sd
, const char * const *argv
, const char * const *env
)
1161 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
1163 int argc
, argv_flat
;
1165 address_word sp
, sp_flat
;
1166 unsigned char null
[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
1168 /* Figure out how many bytes the argv strings take up. */
1169 argc
= count_argv (argv
);
1172 argv_flat
= argc
; /* NUL bytes. */
1173 for (i
= 0; i
< argc
; ++i
)
1174 argv_flat
+= strlen (argv
[i
]);
1176 /* Figure out how many bytes the environ strings take up. */
1179 envc
= count_argv (env
);
1180 env_flat
= envc
; /* NUL bytes. */
1181 for (i
= 0; i
< envc
; ++i
)
1182 env_flat
+= strlen (env
[i
]);
1184 /* Make space for the strings themselves. */
1185 sp_flat
= (DEFAULT_MEM_SIZE
- argv_flat
- env_flat
) & -sizeof (address_word
);
1186 /* Then the pointers to the strings. */
1187 sp
= sp_flat
- ((argc
+ 1 + envc
+ 1) * sizeof (address_word
));
1188 /* Then the argc. */
1189 sp
-= sizeof (unsigned_word
);
1191 /* Set up the regs the libgloss crt0 expects. */
1195 /* First push the argc value. */
1196 sim_write (sd
, sp
, (void *)&argc
, sizeof (unsigned_word
));
1197 sp
+= sizeof (unsigned_word
);
1199 /* Then the actual argv strings so we know where to point argv[]. */
1200 for (i
= 0; i
< argc
; ++i
)
1202 unsigned len
= strlen (argv
[i
]) + 1;
1203 sim_write (sd
, sp_flat
, (void *)argv
[i
], len
);
1204 sim_write (sd
, sp
, (void *)&sp_flat
, sizeof (address_word
));
1206 sp
+= sizeof (address_word
);
1208 sim_write (sd
, sp
, null
, sizeof (address_word
));
1209 sp
+= sizeof (address_word
);
1211 /* Then the actual env strings so we know where to point env[]. */
1212 for (i
= 0; i
< envc
; ++i
)
1214 unsigned len
= strlen (env
[i
]) + 1;
1215 sim_write (sd
, sp_flat
, (void *)env
[i
], len
);
1216 sim_write (sd
, sp
, (void *)&sp_flat
, sizeof (address_word
));
1218 sp
+= sizeof (address_word
);