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. */
30 #include "sim-syscall.h"
32 #include "opcode/riscv.h"
34 #include "targ-vals.h"
36 #define TRACE_REG(cpu, reg) \
37 TRACE_REGISTER (cpu, "wrote %s = %#" PRIxTW, riscv_gpr_names_abi[reg], \
40 static const struct riscv_opcode
*riscv_hash
[OP_MASK_OP
+ 1];
41 #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : 0x7f))
43 #define RISCV_ASSERT_RV32(cpu, fmt, args...) \
45 if (RISCV_XLEN (cpu) != 32) \
47 SIM_DESC sd = CPU_STATE (cpu); \
48 TRACE_INSN (cpu, "RV32I-only " fmt, ## args); \
49 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
53 #define RISCV_ASSERT_RV64(cpu, fmt, args...) \
55 if (RISCV_XLEN (cpu) != 64) \
57 SIM_DESC sd = CPU_STATE (cpu); \
58 TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \
59 sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
64 store_rd (SIM_CPU
*cpu
, int rd
, unsigned_word val
)
73 static INLINE unsigned_word
74 fetch_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
)
76 /* Handle pseudo registers. */
79 /* Allow certain registers only in respective modes. */
83 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
91 store_csr (SIM_CPU
*cpu
, const char *name
, int csr
, unsigned_word
*reg
,
96 /* These are pseudo registers that modify sub-fields of fcsr. */
100 cpu
->csr
.fcsr
= (cpu
->csr
.fcsr
& ~0xe0) | (val
<< 5);
105 cpu
->csr
.fcsr
= (cpu
->csr
.fcsr
& ~0x1f) | val
;
107 /* Keep the sub-fields in sync. */
110 cpu
->csr
.frm
= (val
>> 5) & 0x7;
111 cpu
->csr
.fflags
= val
& 0x1f;
114 /* Allow certain registers only in respective modes. */
118 RISCV_ASSERT_RV32 (cpu
, "CSR: %s", name
);
120 /* All the rest are immutable. */
126 TRACE_REGISTER (cpu
, "wrote CSR %s = %#" PRIxTW
, name
, val
);
129 static inline unsigned_word
130 ashiftrt (unsigned_word val
, unsigned_word shift
)
132 unsigned32 sign
= (val
& 0x80000000) ? ~(0xfffffffful
>> shift
) : 0;
133 return (val
>> shift
) | sign
;
136 static inline unsigned_word
137 ashiftrt64 (unsigned_word val
, unsigned_word shift
)
140 (val
& 0x8000000000000000ull
) ? ~(0xffffffffffffffffull
>> shift
) : 0;
141 return (val
>> shift
) | sign
;
145 execute_i (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
147 SIM_DESC sd
= CPU_STATE (cpu
);
148 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
149 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
150 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
151 const char *rd_name
= riscv_gpr_names_abi
[rd
];
152 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
153 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
154 unsigned int csr
= (iw
>> OP_SH_CSR
) & OP_MASK_CSR
;
155 unsigned_word i_imm
= EXTRACT_ITYPE_IMM (iw
);
156 unsigned_word u_imm
= EXTRACT_UTYPE_IMM ((unsigned64
) iw
);
157 unsigned_word s_imm
= EXTRACT_STYPE_IMM (iw
);
158 unsigned_word sb_imm
= EXTRACT_SBTYPE_IMM (iw
);
159 unsigned_word shamt_imm
= ((iw
>> OP_SH_SHAMT
) & OP_MASK_SHAMT
);
161 sim_cia pc
= cpu
->pc
+ 4;
165 "rs1:%-2i:%-4s %0*" PRIxTW
" "
166 "rs2:%-2i:%-4s %0*" PRIxTW
" "
167 "match:%#x mask:%#x",
169 rs1
, rs1_name
, (int) sizeof (unsigned_word
) * 2, cpu
->regs
[rs1
],
170 rs2
, rs2_name
, (int) sizeof (unsigned_word
) * 2, cpu
->regs
[rs2
],
171 (unsigned) op
->match
, (unsigned) op
->mask
);
176 TRACE_INSN (cpu
, "add %s, %s, %s; // %s = %s + %s",
177 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
178 store_rd (cpu
, rd
, cpu
->regs
[rs1
] + cpu
->regs
[rs2
]);
181 TRACE_INSN (cpu
, "addw %s, %s, %s; // %s = %s + %s",
182 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
183 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
184 store_rd (cpu
, rd
, EXTEND32 (cpu
->regs
[rs1
] + cpu
->regs
[rs2
]));
187 TRACE_INSN (cpu
, "addi %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
188 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
189 store_rd (cpu
, rd
, cpu
->regs
[rs1
] + i_imm
);
192 TRACE_INSN (cpu
, "addiw %s, %s, %#" PRIxTW
"; // %s = %s + %#" PRIxTW
,
193 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
194 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
195 store_rd (cpu
, rd
, EXTEND32 (cpu
->regs
[rs1
] + i_imm
));
198 TRACE_INSN (cpu
, "and %s, %s, %s; // %s = %s & %s",
199 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
200 store_rd (cpu
, rd
, cpu
->regs
[rs1
] & cpu
->regs
[rs2
]);
203 TRACE_INSN (cpu
, "andi %s, %s, %" PRIiTW
"; // %s = %s & %#" PRIxTW
,
204 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
205 store_rd (cpu
, rd
, cpu
->regs
[rs1
] & i_imm
);
208 TRACE_INSN (cpu
, "or %s, %s, %s; // %s = %s | %s",
209 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
210 store_rd (cpu
, rd
, cpu
->regs
[rs1
] | cpu
->regs
[rs2
]);
213 TRACE_INSN (cpu
, "ori %s, %s, %" PRIiTW
"; // %s = %s | %#" PRIxTW
,
214 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
215 store_rd (cpu
, rd
, cpu
->regs
[rs1
] | i_imm
);
218 TRACE_INSN (cpu
, "xor %s, %s, %s; // %s = %s ^ %s",
219 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
220 store_rd (cpu
, rd
, cpu
->regs
[rs1
] ^ cpu
->regs
[rs2
]);
223 TRACE_INSN (cpu
, "xori %s, %s, %" PRIiTW
"; // %s = %s ^ %#" PRIxTW
,
224 rd_name
, rs1_name
, i_imm
, rd_name
, rs1_name
, i_imm
);
225 store_rd (cpu
, rd
, cpu
->regs
[rs1
] ^ i_imm
);
228 TRACE_INSN (cpu
, "sub %s, %s, %s; // %s = %s - %s",
229 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
230 store_rd (cpu
, rd
, cpu
->regs
[rs1
] - cpu
->regs
[rs2
]);
233 TRACE_INSN (cpu
, "subw %s, %s, %s; // %s = %s - %s",
234 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
235 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
236 store_rd (cpu
, rd
, EXTEND32 (cpu
->regs
[rs1
] - cpu
->regs
[rs2
]));
239 TRACE_INSN (cpu
, "lui %s, %#" PRIxTW
";", rd_name
, u_imm
);
240 store_rd (cpu
, rd
, u_imm
);
243 TRACE_INSN (cpu
, "sll %s, %s, %s; // %s = %s << %s",
244 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
245 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
246 store_rd (cpu
, rd
, cpu
->regs
[rs1
] << (cpu
->regs
[rs2
] & u_imm
));
249 TRACE_INSN (cpu
, "sllw %s, %s, %s; // %s = %s << %s",
250 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
251 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
252 store_rd (cpu
, rd
, EXTEND32 (
253 (unsigned32
) cpu
->regs
[rs1
] << (cpu
->regs
[rs2
] & 0x1f)));
256 TRACE_INSN (cpu
, "slli %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
257 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
258 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
259 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
260 store_rd (cpu
, rd
, cpu
->regs
[rs1
] << shamt_imm
);
263 TRACE_INSN (cpu
, "slliw %s, %s, %" PRIiTW
"; // %s = %s << %#" PRIxTW
,
264 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
265 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
266 store_rd (cpu
, rd
, EXTEND32 ((unsigned32
) cpu
->regs
[rs1
] << shamt_imm
));
269 TRACE_INSN (cpu
, "srl %s, %s, %s; // %s = %s >> %s",
270 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
271 u_imm
= RISCV_XLEN (cpu
) == 32 ? 0x1f : 0x3f;
272 store_rd (cpu
, rd
, cpu
->regs
[rs1
] >> (cpu
->regs
[rs2
] & u_imm
));
275 TRACE_INSN (cpu
, "srlw %s, %s, %s; // %s = %s >> %s",
276 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
277 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
278 store_rd (cpu
, rd
, EXTEND32 (
279 (unsigned32
) cpu
->regs
[rs1
] >> (cpu
->regs
[rs2
] & 0x1f)));
282 TRACE_INSN (cpu
, "srli %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
283 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
284 if (RISCV_XLEN (cpu
) == 32 && shamt_imm
> 0x1f)
285 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
286 store_rd (cpu
, rd
, cpu
->regs
[rs1
] >> shamt_imm
);
289 TRACE_INSN (cpu
, "srliw %s, %s, %" PRIiTW
"; // %s = %s >> %#" PRIxTW
,
290 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
291 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
292 store_rd (cpu
, rd
, EXTEND32 ((unsigned32
) cpu
->regs
[rs1
] >> shamt_imm
));
295 TRACE_INSN (cpu
, "sra %s, %s, %s; // %s = %s >>> %s",
296 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
297 if (RISCV_XLEN (cpu
) == 32)
298 tmp
= ashiftrt (cpu
->regs
[rs1
], cpu
->regs
[rs2
] & 0x1f);
300 tmp
= ashiftrt64 (cpu
->regs
[rs1
], cpu
->regs
[rs2
] & 0x3f);
301 store_rd (cpu
, rd
, tmp
);
304 TRACE_INSN (cpu
, "sraw %s, %s, %s; // %s = %s >>> %s",
305 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
306 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
307 store_rd (cpu
, rd
, EXTEND32 (
308 ashiftrt ((signed32
) cpu
->regs
[rs1
], cpu
->regs
[rs2
] & 0x1f)));
311 TRACE_INSN (cpu
, "srai %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
312 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
313 if (RISCV_XLEN (cpu
) == 32)
315 if (shamt_imm
> 0x1f)
316 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
317 tmp
= ashiftrt (cpu
->regs
[rs1
], shamt_imm
);
320 tmp
= ashiftrt64 (cpu
->regs
[rs1
], shamt_imm
);
321 store_rd (cpu
, rd
, tmp
);
324 TRACE_INSN (cpu
, "sraiw %s, %s, %" PRIiTW
"; // %s = %s >>> %#" PRIxTW
,
325 rd_name
, rs1_name
, shamt_imm
, rd_name
, rs1_name
, shamt_imm
);
326 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
327 store_rd (cpu
, rd
, EXTEND32 (
328 ashiftrt ((signed32
) cpu
->regs
[rs1
], shamt_imm
)));
331 TRACE_INSN (cpu
, "slt");
333 !!((signed_word
) cpu
->regs
[rs1
] < (signed_word
) cpu
->regs
[rs2
]));
336 TRACE_INSN (cpu
, "sltu");
337 store_rd (cpu
, rd
, !!((unsigned_word
) cpu
->regs
[rs1
] <
338 (unsigned_word
) cpu
->regs
[rs2
]));
341 TRACE_INSN (cpu
, "slti");
342 store_rd (cpu
, rd
, !!((signed_word
) cpu
->regs
[rs1
] <
343 (signed_word
) i_imm
));
346 TRACE_INSN (cpu
, "sltiu");
347 store_rd (cpu
, rd
, !!((unsigned_word
) cpu
->regs
[rs1
] <
348 (unsigned_word
) i_imm
));
351 TRACE_INSN (cpu
, "auipc %s, %" PRIiTW
"; // %s = pc + %" PRIiTW
,
352 rd_name
, u_imm
, rd_name
, u_imm
);
353 store_rd (cpu
, rd
, cpu
->pc
+ u_imm
);
356 TRACE_INSN (cpu
, "beq %s, %s, %#" PRIxTW
"; "
357 "// if (%s == %s) goto %#" PRIxTW
,
358 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
359 if (cpu
->regs
[rs1
] == cpu
->regs
[rs2
])
361 pc
= cpu
->pc
+ sb_imm
;
362 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
366 TRACE_INSN (cpu
, "blt %s, %s, %#" PRIxTW
"; "
367 "// if (%s < %s) goto %#" PRIxTW
,
368 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
369 if ((signed_word
) cpu
->regs
[rs1
] < (signed_word
) cpu
->regs
[rs2
])
371 pc
= cpu
->pc
+ sb_imm
;
372 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
376 TRACE_INSN (cpu
, "bltu %s, %s, %#" PRIxTW
"; "
377 "// if (%s < %s) goto %#" PRIxTW
,
378 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
379 if ((unsigned_word
) cpu
->regs
[rs1
] < (unsigned_word
) cpu
->regs
[rs2
])
381 pc
= cpu
->pc
+ sb_imm
;
382 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
386 TRACE_INSN (cpu
, "bge %s, %s, %#" PRIxTW
"; "
387 "// if (%s >= %s) goto %#" PRIxTW
,
388 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
389 if ((signed_word
) cpu
->regs
[rs1
] >= (signed_word
) cpu
->regs
[rs2
])
391 pc
= cpu
->pc
+ sb_imm
;
392 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
396 TRACE_INSN (cpu
, "bgeu %s, %s, %#" PRIxTW
"; "
397 "// if (%s >= %s) goto %#" PRIxTW
,
398 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
399 if ((unsigned_word
) cpu
->regs
[rs1
] >= (unsigned_word
) cpu
->regs
[rs2
])
401 pc
= cpu
->pc
+ sb_imm
;
402 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
406 TRACE_INSN (cpu
, "bne %s, %s, %#" PRIxTW
"; "
407 "// if (%s != %s) goto %#" PRIxTW
,
408 rs1_name
, rs2_name
, sb_imm
, rs1_name
, rs2_name
, sb_imm
);
409 if (cpu
->regs
[rs1
] != cpu
->regs
[rs2
])
411 pc
= cpu
->pc
+ sb_imm
;
412 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
416 TRACE_INSN (cpu
, "jal %s, %" PRIiTW
";", rd_name
,
417 EXTRACT_UJTYPE_IMM (iw
));
418 store_rd (cpu
, rd
, cpu
->pc
+ 4);
419 pc
= cpu
->pc
+ EXTRACT_UJTYPE_IMM (iw
);
420 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
423 TRACE_INSN (cpu
, "jalr %s, %s, %" PRIiTW
";", rd_name
, rs1_name
, i_imm
);
424 store_rd (cpu
, rd
, cpu
->pc
+ 4);
425 pc
= cpu
->regs
[rs1
] + i_imm
;
426 TRACE_BRANCH (cpu
, "to %#" PRIxTW
, pc
);
430 TRACE_INSN (cpu
, "ld %s, %" PRIiTW
"(%s);",
431 rd_name
, i_imm
, rs1_name
);
432 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
434 sim_core_read_unaligned_8 (cpu
, cpu
->pc
, read_map
,
435 cpu
->regs
[rs1
] + i_imm
));
438 TRACE_INSN (cpu
, "lw %s, %" PRIiTW
"(%s);",
439 rd_name
, i_imm
, rs1_name
);
440 store_rd (cpu
, rd
, EXTEND32 (
441 sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
,
442 cpu
->regs
[rs1
] + i_imm
)));
445 TRACE_INSN (cpu
, "lwu %s, %" PRIiTW
"(%s);",
446 rd_name
, i_imm
, rs1_name
);
448 sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
,
449 cpu
->regs
[rs1
] + i_imm
));
452 TRACE_INSN (cpu
, "lh %s, %" PRIiTW
"(%s);",
453 rd_name
, i_imm
, rs1_name
);
454 store_rd (cpu
, rd
, EXTEND16 (
455 sim_core_read_unaligned_2 (cpu
, cpu
->pc
, read_map
,
456 cpu
->regs
[rs1
] + i_imm
)));
459 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
460 rd_name
, i_imm
, rs1_name
);
462 sim_core_read_unaligned_2 (cpu
, cpu
->pc
, read_map
,
463 cpu
->regs
[rs1
] + i_imm
));
466 TRACE_INSN (cpu
, "lb %s, %" PRIiTW
"(%s);",
467 rd_name
, i_imm
, rs1_name
);
468 store_rd (cpu
, rd
, EXTEND8 (
469 sim_core_read_unaligned_1 (cpu
, cpu
->pc
, read_map
,
470 cpu
->regs
[rs1
] + i_imm
)));
473 TRACE_INSN (cpu
, "lbu %s, %" PRIiTW
"(%s);",
474 rd_name
, i_imm
, rs1_name
);
476 sim_core_read_unaligned_1 (cpu
, cpu
->pc
, read_map
,
477 cpu
->regs
[rs1
] + i_imm
));
480 TRACE_INSN (cpu
, "sd %s, %" PRIiTW
"(%s);",
481 rs2_name
, s_imm
, rs1_name
);
482 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
483 sim_core_write_unaligned_8 (cpu
, cpu
->pc
, write_map
,
484 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
487 TRACE_INSN (cpu
, "sw %s, %" PRIiTW
"(%s);",
488 rs2_name
, s_imm
, rs1_name
);
489 sim_core_write_unaligned_4 (cpu
, cpu
->pc
, write_map
,
490 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
493 TRACE_INSN (cpu
, "sh %s, %" PRIiTW
"(%s);",
494 rs2_name
, s_imm
, rs1_name
);
495 sim_core_write_unaligned_2 (cpu
, cpu
->pc
, write_map
,
496 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
499 TRACE_INSN (cpu
, "sb %s, %" PRIiTW
"(%s);",
500 rs2_name
, s_imm
, rs1_name
);
501 sim_core_write_unaligned_1 (cpu
, cpu
->pc
, write_map
,
502 cpu
->regs
[rs1
] + s_imm
, cpu
->regs
[rs2
]);
506 TRACE_INSN (cpu
, "csrrc");
509 #define DECLARE_CSR(name, num, ...) \
511 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
512 store_csr (cpu, #name, num, &cpu->csr.name, \
513 cpu->csr.name & !cpu->regs[rs1]); \
515 #include "opcode/riscv-opc.h"
520 TRACE_INSN (cpu
, "csrrs");
523 #define DECLARE_CSR(name, num, ...) \
525 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
526 store_csr (cpu, #name, num, &cpu->csr.name, \
527 cpu->csr.name | cpu->regs[rs1]); \
529 #include "opcode/riscv-opc.h"
534 TRACE_INSN (cpu
, "csrrw");
537 #define DECLARE_CSR(name, num, ...) \
539 store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
540 store_csr (cpu, #name, num, &cpu->csr.name, cpu->regs[rs1]); \
542 #include "opcode/riscv-opc.h"
548 TRACE_INSN (cpu
, "rdcycle %s;", rd_name
);
549 store_rd (cpu
, rd
, fetch_csr (cpu
, "cycle", CSR_CYCLE
, &cpu
->csr
.cycle
));
552 TRACE_INSN (cpu
, "rdcycleh %s;", rd_name
);
553 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
555 fetch_csr (cpu
, "cycleh", CSR_CYCLEH
, &cpu
->csr
.cycleh
));
557 case MATCH_RDINSTRET
:
558 TRACE_INSN (cpu
, "rdinstret %s;", rd_name
);
560 fetch_csr (cpu
, "instret", CSR_INSTRET
, &cpu
->csr
.instret
));
562 case MATCH_RDINSTRETH
:
563 TRACE_INSN (cpu
, "rdinstreth %s;", rd_name
);
564 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
566 fetch_csr (cpu
, "instreth", CSR_INSTRETH
, &cpu
->csr
.instreth
));
569 TRACE_INSN (cpu
, "rdtime %s;", rd_name
);
570 store_rd (cpu
, rd
, fetch_csr (cpu
, "time", CSR_TIME
, &cpu
->csr
.time
));
573 TRACE_INSN (cpu
, "rdtimeh %s;", rd_name
);
574 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
575 store_rd (cpu
, rd
, fetch_csr (cpu
, "timeh", CSR_TIMEH
, &cpu
->csr
.timeh
));
579 TRACE_INSN (cpu
, "fence;");
582 TRACE_INSN (cpu
, "fence.i;");
585 TRACE_INSN (cpu
, "sbreak;");
586 /* GDB expects us to step over SBREAK. */
587 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
+ 4, sim_stopped
, SIM_SIGTRAP
);
590 TRACE_INSN (cpu
, "ecall;");
591 cpu
->a0
= sim_syscall (cpu
, cpu
->a7
, cpu
->a0
, cpu
->a1
, cpu
->a2
, cpu
->a3
);
594 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
595 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
602 mulhu (unsigned64 a
, unsigned64 b
)
605 return ((__int128
)a
* b
) >> 64;
609 uint64_t a0
= (uint32_t)a
, a1
= a
>> 32;
610 uint64_t b0
= (uint32_t)b
, b1
= b
>> 32;
612 t
= a1
*b0
+ ((a0
*b0
) >> 32);
619 t
= a1
*b1
+ y2
+ (t
>> 32);
623 return ((uint64_t)y3
<< 32) | y2
;
628 mulh (signed64 a
, signed64 b
)
630 int negate
= (a
< 0) != (b
< 0);
631 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
< 0 ? -b
: b
);
632 return negate
? ~res
+ (a
* b
== 0) : res
;
636 mulhsu (signed64 a
, unsigned64 b
)
639 uint64_t res
= mulhu (a
< 0 ? -a
: a
, b
);
640 return negate
? ~res
+ (a
* b
== 0) : res
;
644 execute_m (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
646 SIM_DESC sd
= CPU_STATE (cpu
);
647 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
648 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
649 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
650 const char *rd_name
= riscv_gpr_names_abi
[rd
];
651 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
652 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
653 unsigned_word tmp
, dividend_max
;
654 sim_cia pc
= cpu
->pc
+ 4;
656 dividend_max
= -((unsigned_word
) 1 << (WITH_TARGET_WORD_BITSIZE
- 1));
661 TRACE_INSN (cpu
, "div %s, %s, %s; // %s = %s / %s",
662 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
663 if (cpu
->regs
[rs1
] == dividend_max
&& cpu
->regs
[rs2
] == -1)
665 else if (cpu
->regs
[rs2
])
666 tmp
= (signed_word
) cpu
->regs
[rs1
] / (signed_word
) cpu
->regs
[rs2
];
669 store_rd (cpu
, rd
, tmp
);
672 TRACE_INSN (cpu
, "divw %s, %s, %s; // %s = %s / %s",
673 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
674 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
675 if (EXTEND32 (cpu
->regs
[rs2
]) == -1)
677 else if (EXTEND32 (cpu
->regs
[rs2
]))
678 tmp
= EXTEND32 (cpu
->regs
[rs1
]) / EXTEND32 (cpu
->regs
[rs2
]);
681 store_rd (cpu
, rd
, EXTEND32 (tmp
));
684 TRACE_INSN (cpu
, "divu %s, %s, %s; // %s = %s / %s",
685 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
687 store_rd (cpu
, rd
, (unsigned_word
) cpu
->regs
[rs1
]
688 / (unsigned_word
) cpu
->regs
[rs2
]);
690 store_rd (cpu
, rd
, -1);
693 TRACE_INSN (cpu
, "divuw %s, %s, %s; // %s = %s / %s",
694 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
695 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
696 if ((unsigned32
) cpu
->regs
[rs2
])
697 tmp
= (unsigned32
) cpu
->regs
[rs1
] / (unsigned32
) cpu
->regs
[rs2
];
700 store_rd (cpu
, rd
, EXTEND32 (tmp
));
703 TRACE_INSN (cpu
, "mul %s, %s, %s; // %s = %s * %s",
704 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
705 store_rd (cpu
, rd
, cpu
->regs
[rs1
] * cpu
->regs
[rs2
]);
708 TRACE_INSN (cpu
, "mulw %s, %s, %s; // %s = %s * %s",
709 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
710 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
711 store_rd (cpu
, rd
, EXTEND32 ((signed32
) cpu
->regs
[rs1
]
712 * (signed32
) cpu
->regs
[rs2
]));
715 TRACE_INSN (cpu
, "mulh %s, %s, %s; // %s = %s * %s",
716 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
717 if (RISCV_XLEN (cpu
) == 32)
718 store_rd (cpu
, rd
, ((signed64
)(signed_word
) cpu
->regs
[rs1
]
719 * (signed64
)(signed_word
) cpu
->regs
[rs2
]) >> 32);
721 store_rd (cpu
, rd
, mulh (cpu
->regs
[rs1
], cpu
->regs
[rs2
]));
724 TRACE_INSN (cpu
, "mulhu %s, %s, %s; // %s = %s * %s",
725 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
726 if (RISCV_XLEN (cpu
) == 32)
727 store_rd (cpu
, rd
, ((unsigned64
)cpu
->regs
[rs1
]
728 * (unsigned64
)cpu
->regs
[rs2
]) >> 32);
730 store_rd (cpu
, rd
, mulhu (cpu
->regs
[rs1
], cpu
->regs
[rs2
]));
733 TRACE_INSN (cpu
, "mulhsu %s, %s, %s; // %s = %s * %s",
734 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
735 if (RISCV_XLEN (cpu
) == 32)
736 store_rd (cpu
, rd
, ((signed64
)(signed_word
) cpu
->regs
[rs1
]
737 * (unsigned64
)cpu
->regs
[rs2
]) >> 32);
739 store_rd (cpu
, rd
, mulhsu (cpu
->regs
[rs1
], cpu
->regs
[rs2
]));
742 TRACE_INSN (cpu
, "rem %s, %s, %s; // %s = %s %% %s",
743 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
744 if (cpu
->regs
[rs1
] == dividend_max
&& cpu
->regs
[rs2
] == -1)
746 else if (cpu
->regs
[rs2
])
747 tmp
= (signed_word
) cpu
->regs
[rs1
] % (signed_word
) cpu
->regs
[rs2
];
749 tmp
= cpu
->regs
[rs1
];
750 store_rd (cpu
, rd
, tmp
);
753 TRACE_INSN (cpu
, "remw %s, %s, %s; // %s = %s %% %s",
754 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
755 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
756 if (EXTEND32 (cpu
->regs
[rs2
]) == -1)
758 else if (EXTEND32 (cpu
->regs
[rs2
]))
759 tmp
= EXTEND32 (cpu
->regs
[rs1
]) % EXTEND32 (cpu
->regs
[rs2
]);
761 tmp
= cpu
->regs
[rs1
];
762 store_rd (cpu
, rd
, EXTEND32 (tmp
));
765 TRACE_INSN (cpu
, "remu %s, %s, %s; // %s = %s %% %s",
766 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
768 store_rd (cpu
, rd
, cpu
->regs
[rs1
] % cpu
->regs
[rs2
]);
770 store_rd (cpu
, rd
, cpu
->regs
[rs1
]);
773 TRACE_INSN (cpu
, "remuw %s, %s, %s; // %s = %s %% %s",
774 rd_name
, rs1_name
, rs2_name
, rd_name
, rs1_name
, rs2_name
);
775 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
776 if ((unsigned32
) cpu
->regs
[rs2
])
777 tmp
= (unsigned32
) cpu
->regs
[rs1
] % (unsigned32
) cpu
->regs
[rs2
];
779 tmp
= cpu
->regs
[rs1
];
780 store_rd (cpu
, rd
, EXTEND32 (tmp
));
783 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
784 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
790 #define MAX(a, b) ((a) > (b) ? (a) : (b))
791 #define MIN(a, b) ((a) < (b) ? (a) : (b))
794 execute_a (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
796 SIM_DESC sd
= CPU_STATE (cpu
);
797 int rd
= (iw
>> OP_SH_RD
) & OP_MASK_RD
;
798 int rs1
= (iw
>> OP_SH_RS1
) & OP_MASK_RS1
;
799 int rs2
= (iw
>> OP_SH_RS2
) & OP_MASK_RS2
;
800 const char *rd_name
= riscv_gpr_names_abi
[rd
];
801 const char *rs1_name
= riscv_gpr_names_abi
[rs1
];
802 const char *rs2_name
= riscv_gpr_names_abi
[rs2
];
803 struct atomic_mem_reserved_list
*amo_prev
, *amo_curr
;
805 sim_cia pc
= cpu
->pc
+ 4;
807 /* Handle these two load/store operations specifically. */
811 TRACE_INSN (cpu
, "%s %s, (%s);", op
->name
, rd_name
, rs1_name
);
813 sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
, cpu
->regs
[rs1
]));
815 /* Walk the reservation list to find an existing match. */
816 amo_curr
= sd
->amo_reserved_list
;
819 if (amo_curr
->addr
== cpu
->regs
[rs1
])
821 amo_curr
= amo_curr
->next
;
824 /* No reservation exists, so add one. */
825 amo_curr
= xmalloc (sizeof (*amo_curr
));
826 amo_curr
->addr
= cpu
->regs
[rs1
];
827 amo_curr
->next
= sd
->amo_reserved_list
;
828 sd
->amo_reserved_list
= amo_curr
;
831 TRACE_INSN (cpu
, "%s %s, %s, (%s);", op
->name
, rd_name
, rs2_name
,
834 /* Walk the reservation list to find a match. */
835 amo_curr
= amo_prev
= sd
->amo_reserved_list
;
838 if (amo_curr
->addr
== cpu
->regs
[rs1
])
840 /* We found a reservation, so operate it. */
841 sim_core_write_unaligned_4 (cpu
, cpu
->pc
, write_map
,
842 cpu
->regs
[rs1
], cpu
->regs
[rs2
]);
843 store_rd (cpu
, rd
, 0);
844 if (amo_curr
== sd
->amo_reserved_list
)
845 sd
->amo_reserved_list
= amo_curr
->next
;
847 amo_prev
->next
= amo_curr
->next
;
852 amo_curr
= amo_curr
->next
;
855 /* If we're still here, then no reservation exists, so mark as failed. */
856 store_rd (cpu
, rd
, 1);
860 /* Handle the rest of the atomic insns with common code paths. */
861 TRACE_INSN (cpu
, "%s %s, %s, (%s);",
862 op
->name
, rd_name
, rs2_name
, rs1_name
);
863 if (op
->xlen_requirement
== 64)
864 tmp
= sim_core_read_unaligned_8 (cpu
, cpu
->pc
, read_map
, cpu
->regs
[rs1
]);
866 tmp
= EXTEND32 (sim_core_read_unaligned_4 (cpu
, cpu
->pc
, read_map
,
868 store_rd (cpu
, rd
, tmp
);
874 tmp
= cpu
->regs
[rd
] + cpu
->regs
[rs2
];
878 tmp
= cpu
->regs
[rd
] & cpu
->regs
[rs2
];
882 tmp
= MAX ((signed_word
) cpu
->regs
[rd
], (signed_word
) cpu
->regs
[rs2
]);
884 case MATCH_AMOMAXU_D
:
885 case MATCH_AMOMAXU_W
:
886 tmp
= MAX ((unsigned_word
) cpu
->regs
[rd
], (unsigned_word
) cpu
->regs
[rs2
]);
890 tmp
= MIN ((signed_word
) cpu
->regs
[rd
], (signed_word
) cpu
->regs
[rs2
]);
892 case MATCH_AMOMINU_D
:
893 case MATCH_AMOMINU_W
:
894 tmp
= MIN ((unsigned_word
) cpu
->regs
[rd
], (unsigned_word
) cpu
->regs
[rs2
]);
898 tmp
= cpu
->regs
[rd
] | cpu
->regs
[rs2
];
900 case MATCH_AMOSWAP_D
:
901 case MATCH_AMOSWAP_W
:
902 tmp
= cpu
->regs
[rs2
];
906 tmp
= cpu
->regs
[rd
] ^ cpu
->regs
[rs2
];
909 TRACE_INSN (cpu
, "UNHANDLED INSN: %s", op
->name
);
910 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
913 if (op
->xlen_requirement
== 64)
914 sim_core_write_unaligned_8 (cpu
, cpu
->pc
, write_map
, cpu
->regs
[rs1
], tmp
);
916 sim_core_write_unaligned_4 (cpu
, cpu
->pc
, write_map
, cpu
->regs
[rs1
], tmp
);
923 execute_one (SIM_CPU
*cpu
, unsigned_word iw
, const struct riscv_opcode
*op
)
925 SIM_DESC sd
= CPU_STATE (cpu
);
927 if (op
->xlen_requirement
== 32)
928 RISCV_ASSERT_RV32 (cpu
, "insn: %s", op
->name
);
929 else if (op
->xlen_requirement
== 64)
930 RISCV_ASSERT_RV64 (cpu
, "insn: %s", op
->name
);
932 switch (op
->insn_class
)
935 return execute_a (cpu
, iw
, op
);
937 return execute_i (cpu
, iw
, op
);
939 return execute_m (cpu
, iw
, op
);
941 TRACE_INSN (cpu
, "UNHANDLED EXTENSION: %d", op
->insn_class
);
942 sim_engine_halt (sd
, cpu
, NULL
, cpu
->pc
, sim_signalled
, SIM_SIGILL
);
945 return cpu
->pc
+ riscv_insn_length (iw
);
948 /* Decode & execute a single instruction. */
949 void step_once (SIM_CPU
*cpu
)
951 SIM_DESC sd
= CPU_STATE (cpu
);
954 sim_cia pc
= cpu
->pc
;
955 const struct riscv_opcode
*op
;
956 int xlen
= RISCV_XLEN (cpu
);
958 if (TRACE_ANY_P (cpu
))
959 trace_prefix (sd
, cpu
, NULL_CIA
, pc
, TRACE_LINENUM_P (cpu
),
960 NULL
, 0, " "); /* Use a space for gcc warnings. */
962 iw
= sim_core_read_aligned_2 (cpu
, pc
, exec_map
, pc
);
964 /* Reject non-32-bit opcodes first. */
965 len
= riscv_insn_length (iw
);
968 sim_io_printf (sd
, "sim: bad insn len %#x @ %#" PRIxTA
": %#" PRIxTW
"\n",
970 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
973 iw
|= ((unsigned_word
) sim_core_read_aligned_2 (
974 cpu
, pc
, exec_map
, pc
+ 2) << 16);
976 TRACE_CORE (cpu
, "0x%08" PRIxTW
, iw
);
978 op
= riscv_hash
[OP_HASH_IDX (iw
)];
980 sim_engine_halt (sd
, cpu
, NULL
, pc
, sim_signalled
, SIM_SIGILL
);
982 /* NB: Same loop logic as riscv_disassemble_insn. */
983 for (; op
->name
; op
++)
985 /* Does the opcode match? */
986 if (! op
->match_func (op
, iw
))
988 /* Is this a pseudo-instruction and may we print it as such? */
989 if (op
->pinfo
& INSN_ALIAS
)
991 /* Is this instruction restricted to a certain value of XLEN? */
992 if (op
->xlen_requirement
!= 0 && op
->xlen_requirement
!= xlen
)
996 pc
= execute_one (cpu
, iw
, op
);
1000 /* TODO: Handle overflow into high 32 bits. */
1001 /* TODO: Try to use a common counter and only update on demand (reads). */
1008 /* Return the program counter for this cpu. */
1010 pc_get (sim_cpu
*cpu
)
1015 /* Set the program counter for this cpu to the new pc value. */
1017 pc_set (sim_cpu
*cpu
, sim_cia pc
)
1022 /* Initialize the state for a single cpu. Usuaully this involves clearing all
1023 registers back to their reset state. Should also hook up the fetch/store
1024 helper functions too. */
1026 initialize_cpu (SIM_DESC sd
, SIM_CPU
*cpu
, int mhartid
)
1028 const char *extensions
;
1031 memset (cpu
->regs
, 0, sizeof (cpu
->regs
));
1033 CPU_PC_FETCH (cpu
) = pc_get
;
1034 CPU_PC_STORE (cpu
) = pc_set
;
1038 const struct riscv_opcode
*op
;
1040 for (op
= riscv_opcodes
; op
->name
; op
++)
1041 if (!riscv_hash
[OP_HASH_IDX (op
->match
)])
1042 riscv_hash
[OP_HASH_IDX (op
->match
)] = op
;
1046 /* RV32 sets this field to 0, and we don't really support RV128 yet. */
1047 if (RISCV_XLEN (cpu
) == 64)
1048 cpu
->csr
.misa
|= (unsigned64
)2 << 62;
1050 /* Skip the leading "rv" prefix and the two numbers. */
1051 extensions
= MODEL_NAME (CPU_MODEL (cpu
)) + 4;
1052 for (i
= 0; i
< 26; ++i
)
1058 else if (strchr (extensions
, ext
) != NULL
)
1061 cpu
->csr
.misa
|= 0x1129; /* G = IMAFD. */
1063 cpu
->csr
.misa
|= (1 << i
);
1067 cpu
->csr
.mimpid
= 0x8000;
1068 cpu
->csr
.mhartid
= mhartid
;
1071 /* Some utils don't like having a NULL environ. */
1072 static const char * const simple_env
[] = { "HOME=/", "PATH=/bin", NULL
};
1074 /* Count the number of arguments in an argv. */
1076 count_argv (const char * const *argv
)
1083 for (i
= 0; argv
[i
] != NULL
; ++i
)
1089 initialize_env (SIM_DESC sd
, const char * const *argv
, const char * const *env
)
1091 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
1093 int argc
, argv_flat
;
1095 address_word sp
, sp_flat
;
1096 unsigned char null
[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
1098 /* Figure out how many bytes the argv strings take up. */
1099 argc
= count_argv (argv
);
1102 argv_flat
= argc
; /* NUL bytes. */
1103 for (i
= 0; i
< argc
; ++i
)
1104 argv_flat
+= strlen (argv
[i
]);
1106 /* Figure out how many bytes the environ strings take up. */
1109 envc
= count_argv (env
);
1110 env_flat
= envc
; /* NUL bytes. */
1111 for (i
= 0; i
< envc
; ++i
)
1112 env_flat
+= strlen (env
[i
]);
1114 /* Make space for the strings themselves. */
1115 sp_flat
= (DEFAULT_MEM_SIZE
- argv_flat
- env_flat
) & -sizeof (address_word
);
1116 /* Then the pointers to the strings. */
1117 sp
= sp_flat
- ((argc
+ 1 + envc
+ 1) * sizeof (address_word
));
1118 /* Then the argc. */
1119 sp
-= sizeof (unsigned_word
);
1121 /* Set up the regs the libgloss crt0 expects. */
1125 /* First push the argc value. */
1126 sim_write (sd
, sp
, (void *)&argc
, sizeof (unsigned_word
));
1127 sp
+= sizeof (unsigned_word
);
1129 /* Then the actual argv strings so we know where to point argv[]. */
1130 for (i
= 0; i
< argc
; ++i
)
1132 unsigned len
= strlen (argv
[i
]) + 1;
1133 sim_write (sd
, sp_flat
, (void *)argv
[i
], len
);
1134 sim_write (sd
, sp
, (void *)&sp_flat
, sizeof (address_word
));
1136 sp
+= sizeof (address_word
);
1138 sim_write (sd
, sp
, null
, sizeof (address_word
));
1139 sp
+= sizeof (address_word
);
1141 /* Then the actual env strings so we know where to point env[]. */
1142 for (i
= 0; i
< envc
; ++i
)
1144 unsigned len
= strlen (env
[i
]) + 1;
1145 sim_write (sd
, sp_flat
, (void *)env
[i
], len
);
1146 sim_write (sd
, sp
, (void *)&sp_flat
, sizeof (address_word
));
1148 sp
+= sizeof (address_word
);
This page took 0.059108 seconds and 5 git commands to generate.