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