]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/pru/interp.c
sim: overhaul & unify endian settings management
[thirdparty/binutils-gdb.git] / sim / pru / interp.c
CommitLineData
ddd44b70 1/* Simulator for the Texas Instruments PRU processor
3666a048 2 Copyright 2009-2021 Free Software Foundation, Inc.
ddd44b70
DD
3 Inspired by the Microblaze simulator
4 Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
5
6 This file is part of the simulators.
7
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.
12
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.
17
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/>. */
20
6df01ab8
MF
21/* This must come before any other includes. */
22#include "defs.h"
23
ddd44b70
DD
24#include <stdbool.h>
25#include <stdint.h>
26#include <stddef.h>
27#include "bfd.h"
df68e12b 28#include "sim/callback.h"
ddd44b70 29#include "libiberty.h"
df68e12b 30#include "sim/sim.h"
ddd44b70
DD
31#include "sim-main.h"
32#include "sim-assert.h"
33#include "sim-options.h"
34#include "sim-syscall.h"
35#include "pru.h"
36
37/* DMEM zero address is perfectly valid. But if CRT leaves the first word
38 alone, we can use it as a trap to catch NULL pointer access. */
39static bfd_boolean abort_on_dmem_zero_access;
40
41enum {
42 OPTION_ERROR_NULL_DEREF = OPTION_START,
43};
44
45/* Extract (from PRU endianess) and return an integer in HOST's endianness. */
46static uint32_t
47pru_extract_unsigned_integer (uint8_t *addr, size_t len)
48{
49 uint32_t retval;
50 uint8_t *p;
51 uint8_t *startaddr = addr;
52 uint8_t *endaddr = startaddr + len;
53
54 /* Start at the most significant end of the integer, and work towards
55 the least significant. */
56 retval = 0;
57
58 for (p = endaddr; p > startaddr;)
59 retval = (retval << 8) | * -- p;
60 return retval;
61}
62
63/* Store "val" (which is in HOST's endianess) into "addr"
64 (using PRU's endianness). */
65static void
66pru_store_unsigned_integer (uint8_t *addr, size_t len, uint32_t val)
67{
68 uint8_t *p;
69 uint8_t *startaddr = (uint8_t *)addr;
70 uint8_t *endaddr = startaddr + len;
71
72 for (p = startaddr; p < endaddr;)
73 {
74 *p++ = val & 0xff;
75 val >>= 8;
76 }
77}
78
79/* Extract a field value from CPU register using the given REGSEL selector.
80
81 Byte number maps directly to first values of RSEL, so we can
82 safely use "regsel" as a register byte number (0..3). */
83static inline uint32_t
84extract_regval (uint32_t val, uint32_t regsel)
85{
86 ASSERT (RSEL_7_0 == 0);
87 ASSERT (RSEL_15_8 == 1);
88 ASSERT (RSEL_23_16 == 2);
89 ASSERT (RSEL_31_24 == 3);
90
91 switch (regsel)
92 {
93 case RSEL_7_0: return (val >> 0) & 0xff;
94 case RSEL_15_8: return (val >> 8) & 0xff;
95 case RSEL_23_16: return (val >> 16) & 0xff;
96 case RSEL_31_24: return (val >> 24) & 0xff;
97 case RSEL_15_0: return (val >> 0) & 0xffff;
98 case RSEL_23_8: return (val >> 8) & 0xffff;
99 case RSEL_31_16: return (val >> 16) & 0xffff;
100 case RSEL_31_0: return val;
101 default: sim_io_error (NULL, "invalid regsel");
102 }
103}
104
105/* Write a value into CPU subregister pointed by reg and regsel. */
106static inline void
107write_regval (uint32_t val, uint32_t *reg, uint32_t regsel)
108{
109 uint32_t mask, sh;
110
111 switch (regsel)
112 {
113 case RSEL_7_0: mask = (0xffu << 0); sh = 0; break;
114 case RSEL_15_8: mask = (0xffu << 8); sh = 8; break;
115 case RSEL_23_16: mask = (0xffu << 16); sh = 16; break;
116 case RSEL_31_24: mask = (0xffu << 24); sh = 24; break;
117 case RSEL_15_0: mask = (0xffffu << 0); sh = 0; break;
118 case RSEL_23_8: mask = (0xffffu << 8); sh = 8; break;
119 case RSEL_31_16: mask = (0xffffu << 16); sh = 16; break;
120 case RSEL_31_0: mask = 0xffffffffu; sh = 0; break;
121 default: sim_io_error (NULL, "invalid regsel");
122 }
123
124 *reg = (*reg & ~mask) | ((val << sh) & mask);
125}
126
127/* Convert the given IMEM word address to a regular byte address used by the
128 GNU ELF container. */
129static uint32_t
130imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
131{
132 return (((uint32_t) wa << 2) & IMEM_ADDR_MASK) | PC_ADDR_SPACE_MARKER;
133}
134
135/* Convert the given ELF text byte address to IMEM word address. */
136static uint16_t
137imem_byteaddr_to_wordaddr (SIM_CPU *cpu, uint32_t ba)
138{
139 return (ba >> 2) & 0xffff;
140}
141
142
143/* Store "nbytes" into DMEM "addr" from CPU register file, starting with
144 register "regn", and byte "regb" within it. */
145static inline void
146pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
147 int regn, int regb)
148{
149 /* GDB assumes unconditional access to all memories, so enable additional
150 checks only in standalone mode. */
151 bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
152
153 if (abort_on_dmem_zero_access && addr < 4)
154 {
155 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
156 nbytes, addr, write_transfer,
157 sim_core_unmapped_signal);
158 }
159 else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
160 || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
161 {
162 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
163 nbytes, addr, write_transfer,
164 sim_core_unmapped_signal);
165 }
166 else if ((regn * 4 + regb + nbytes) > (32 * 4))
167 {
168 sim_io_eprintf (CPU_STATE (cpu),
169 "SBBO/SBCO with invalid store data length\n");
170 RAISE_SIGILL (CPU_STATE (cpu));
171 }
172 else
173 {
174 TRACE_MEMORY (cpu, "write of %d bytes to %08x", nbytes, addr);
175 while (nbytes--)
176 {
177 sim_core_write_1 (cpu,
178 PC_byteaddr,
179 write_map,
180 addr++,
181 extract_regval (CPU.regs[regn], regb));
182
183 if (++regb >= 4)
184 {
185 regb = 0;
186 regn++;
187 }
188 }
189 }
190}
191
192/* Load "nbytes" from DMEM "addr" into CPU register file, starting with
193 register "regn", and byte "regb" within it. */
194static inline void
195pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
196 int regn, int regb)
197{
198 /* GDB assumes unconditional access to all memories, so enable additional
199 checks only in standalone mode. */
200 bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
201
202 if (abort_on_dmem_zero_access && addr < 4)
203 {
204 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
205 nbytes, addr, read_transfer,
206 sim_core_unmapped_signal);
207 }
208 else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
209 || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
210 {
211 /* This check is necessary because our IMEM "address space"
212 is not really accessible, yet we have mapped it as a generic
213 memory space. */
214 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
215 nbytes, addr, read_transfer,
216 sim_core_unmapped_signal);
217 }
218 else if ((regn * 4 + regb + nbytes) > (32 * 4))
219 {
220 sim_io_eprintf (CPU_STATE (cpu),
221 "LBBO/LBCO with invalid load data length\n");
222 RAISE_SIGILL (CPU_STATE (cpu));
223 }
224 else
225 {
226 unsigned int b;
227 TRACE_MEMORY (cpu, "read of %d bytes from %08x", nbytes, addr);
228 while (nbytes--)
229 {
230 b = sim_core_read_1 (cpu, PC_byteaddr, read_map, addr++);
231
232 /* Reuse the fact the Register Byte Number maps directly to RSEL. */
233 ASSERT (RSEL_7_0 == 0);
234 write_regval (b, &CPU.regs[regn], regb);
235
236 if (++regb >= 4)
237 {
238 regb = 0;
239 regn++;
240 }
241 }
242 }
243}
244
245/* Set reset values of general-purpose registers. */
246static void
247set_initial_gprs (SIM_CPU *cpu)
248{
249 int i;
250
251 /* Set up machine just out of reset. */
252 CPU_PC_SET (cpu, 0);
253 PC_ADDR_SPACE_MARKER = IMEM_ADDR_DEFAULT; /* from default linker script? */
254
255 /* Clean out the GPRs. */
256 for (i = 0; i < ARRAY_SIZE (CPU.regs); i++)
257 CPU.regs[i] = 0;
258 for (i = 0; i < ARRAY_SIZE (CPU.macregs); i++)
259 CPU.macregs[i] = 0;
260
261 CPU.loop.looptop = CPU.loop.loopend = 0;
262 CPU.loop.loop_in_progress = 0;
263 CPU.loop.loop_counter = 0;
264
265 CPU.carry = 0;
266 CPU.insts = 0;
267 CPU.cycles = 0;
268
269 /* AM335x should provide sane defaults. */
270 CPU.ctable[0] = 0x00020000;
271 CPU.ctable[1] = 0x48040000;
272 CPU.ctable[2] = 0x4802a000;
273 CPU.ctable[3] = 0x00030000;
274 CPU.ctable[4] = 0x00026000;
275 CPU.ctable[5] = 0x48060000;
276 CPU.ctable[6] = 0x48030000;
277 CPU.ctable[7] = 0x00028000;
278 CPU.ctable[8] = 0x46000000;
279 CPU.ctable[9] = 0x4a100000;
280 CPU.ctable[10] = 0x48318000;
281 CPU.ctable[11] = 0x48022000;
282 CPU.ctable[12] = 0x48024000;
283 CPU.ctable[13] = 0x48310000;
284 CPU.ctable[14] = 0x481cc000;
285 CPU.ctable[15] = 0x481d0000;
286 CPU.ctable[16] = 0x481a0000;
287 CPU.ctable[17] = 0x4819c000;
288 CPU.ctable[18] = 0x48300000;
289 CPU.ctable[19] = 0x48302000;
290 CPU.ctable[20] = 0x48304000;
291 CPU.ctable[21] = 0x00032400;
292 CPU.ctable[22] = 0x480c8000;
293 CPU.ctable[23] = 0x480ca000;
294 CPU.ctable[24] = 0x00000000;
295 CPU.ctable[25] = 0x00002000;
296 CPU.ctable[26] = 0x0002e000;
297 CPU.ctable[27] = 0x00032000;
298 CPU.ctable[28] = 0x00000000;
299 CPU.ctable[29] = 0x49000000;
300 CPU.ctable[30] = 0x40000000;
301 CPU.ctable[31] = 0x80000000;
302}
303
304/* Map regsel selector to subregister field width. */
305static inline unsigned int
306regsel_width (uint32_t regsel)
307{
308 switch (regsel)
309 {
310 case RSEL_7_0: return 8;
311 case RSEL_15_8: return 8;
312 case RSEL_23_16: return 8;
313 case RSEL_31_24: return 8;
314 case RSEL_15_0: return 16;
315 case RSEL_23_8: return 16;
316 case RSEL_31_16: return 16;
317 case RSEL_31_0: return 32;
318 default: sim_io_error (NULL, "invalid regsel");
319 }
320}
321
322/* Handle XIN instruction addressing the MAC peripheral. */
323static void
324pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
325 unsigned int rdb, unsigned int length)
326{
327 if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
328 sim_io_error (sd, "XIN MAC: invalid transfer regn=%u.%u, length=%u\n",
329 rd_regn, rdb, length);
330
331 /* Copy from MAC to PRU regs. Ranges have been validated above. */
332 while (length--)
333 {
334 write_regval (CPU.macregs[rd_regn - 25] >> (rdb * 8),
335 &CPU.regs[rd_regn],
336 rdb);
337 if (++rdb == 4)
338 {
339 rdb = 0;
340 rd_regn++;
341 }
342 }
343}
344
345/* Handle XIN instruction. */
346static void
347pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
348 unsigned int rd_regn, unsigned int rdb, unsigned int length)
349{
350 if (wba == 0)
351 {
352 pru_sim_xin_mac (sd, cpu, rd_regn, rdb, length);
353 }
354 else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
355 || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
356 {
357 while (length--)
358 {
359 unsigned int val;
360
361 val = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
362 write_regval (val, &CPU.regs[rd_regn], rdb);
363 if (++rdb == 4)
364 {
365 rdb = 0;
366 rd_regn++;
367 }
368 }
369 }
370 else if (wba == 254 || wba == 255)
371 {
372 /* FILL/ZERO pseudos implemented via XIN. */
373 unsigned int fillbyte = (wba == 254) ? 0xff : 0x00;
374 while (length--)
375 {
376 write_regval (fillbyte, &CPU.regs[rd_regn], rdb);
377 if (++rdb == 4)
378 {
379 rdb = 0;
380 rd_regn++;
381 }
382 }
383 }
384 else
385 {
386 sim_io_error (sd, "XIN: XFR device %d not supported.\n", wba);
387 }
388}
389
390/* Handle XOUT instruction addressing the MAC peripheral. */
391static void
392pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
393 unsigned int rdb, unsigned int length)
394{
395 const int modereg_accessed = (rd_regn == 25);
396
397 /* Multiple Accumulate. */
398 if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
399 sim_io_error (sd, "XOUT MAC: invalid transfer regn=%u.%u, length=%u\n",
400 rd_regn, rdb, length);
401
402 /* Copy from PRU to MAC regs. Ranges have been validated above. */
403 while (length--)
404 {
405 write_regval (CPU.regs[rd_regn] >> (rdb * 8),
406 &CPU.macregs[rd_regn - 25],
407 rdb);
408 if (++rdb == 4)
409 {
410 rdb = 0;
411 rd_regn++;
412 }
413 }
414
415 if (modereg_accessed
416 && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK))
417 {
418 /* MUL/MAC operands are sampled every XOUT in multiply and
419 accumulate mode. */
420 uint64_t prod, oldsum, sum;
421 CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
422 CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
423
424 prod = CPU.macregs[PRU_MACREG_OP_0];
425 prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
426
427 oldsum = CPU.macregs[PRU_MACREG_ACC_L];
428 oldsum += (uint64_t)CPU.macregs[PRU_MACREG_ACC_H] << 32;
429 sum = oldsum + prod;
430
431 CPU.macregs[PRU_MACREG_PROD_L] = sum & 0xfffffffful;
432 CPU.macregs[PRU_MACREG_PROD_H] = sum >> 32;
433 CPU.macregs[PRU_MACREG_ACC_L] = CPU.macregs[PRU_MACREG_PROD_L];
434 CPU.macregs[PRU_MACREG_ACC_H] = CPU.macregs[PRU_MACREG_PROD_H];
435
436 if (oldsum > sum)
437 CPU.macregs[PRU_MACREG_MODE] |= MAC_R25_ACC_CARRY_MASK;
438 }
439 if (modereg_accessed
440 && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_ACC_CARRY_MASK))
441 {
442 /* store 1 to clear. */
443 CPU.macregs[PRU_MACREG_MODE] &= ~MAC_R25_ACC_CARRY_MASK;
444 CPU.macregs[PRU_MACREG_ACC_L] = 0;
445 CPU.macregs[PRU_MACREG_ACC_H] = 0;
446 }
447
448}
449
450/* Handle XOUT instruction. */
451static void
452pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
453 unsigned int rd_regn, unsigned int rdb, unsigned int length)
454{
455 if (wba == 0)
456 {
457 pru_sim_xout_mac (sd, cpu, rd_regn, rdb, length);
458 }
459 else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
460 || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
461 {
462 while (length--)
463 {
464 unsigned int val;
465
466 val = extract_regval (CPU.regs[rd_regn], rdb);
467 write_regval (val, &CPU.scratchpads[wba][rd_regn], rdb);
468 if (++rdb == 4)
469 {
470 rdb = 0;
471 rd_regn++;
472 }
473 }
474 }
475 else
476 sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
477}
478
479/* Handle XCHG instruction. */
480static void
481pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
482 unsigned int rd_regn, unsigned int rdb, unsigned int length)
483{
484 if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
485 || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
486 {
487 while (length--)
488 {
489 unsigned int valr, vals;
490
491 valr = extract_regval (CPU.regs[rd_regn], rdb);
492 vals = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
493 write_regval (valr, &CPU.scratchpads[wba][rd_regn], rdb);
494 write_regval (vals, &CPU.regs[rd_regn], rdb);
495 if (++rdb == 4)
496 {
497 rdb = 0;
498 rd_regn++;
499 }
500 }
501 }
502 else
503 sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
504}
505
506/* Handle syscall simulation. Its ABI is specific to the GNU simulator. */
507static void
508pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
509{
510 /* If someday TI confirms that the "reserved" HALT opcode fields
511 can be used for extra arguments, then maybe we can embed
512 the syscall number there. Until then, let's use R1. */
513 const uint32_t syscall_num = CPU.regs[1];
514 long ret;
515
516 ret = sim_syscall (cpu, syscall_num,
517 CPU.regs[14], CPU.regs[15],
518 CPU.regs[16], CPU.regs[17]);
519 CPU.regs[14] = ret;
520}
521
522/* Simulate one instruction. */
523static void
524sim_step_once (SIM_DESC sd)
525{
526 SIM_CPU *cpu = STATE_CPU (sd, 0);
527 const struct pru_opcode *op;
528 uint32_t inst;
529 uint32_t _RDVAL, OP2; /* intermediate values. */
530 int rd_is_modified = 0; /* RD modified and must be stored back. */
531
532 /* Fetch the initial instruction that we'll decode. */
533 inst = sim_core_read_4 (cpu, PC_byteaddr, exec_map, PC_byteaddr);
534 TRACE_MEMORY (cpu, "read of insn 0x%08x from %08x", inst, PC_byteaddr);
535
536 op = pru_find_opcode (inst);
537
538 if (!op)
539 {
540 sim_io_eprintf (sd, "Unknown instruction 0x%04x\n", inst);
541 RAISE_SIGILL (sd);
542 }
543 else
544 {
545 TRACE_DISASM (cpu, PC_byteaddr);
546
547 /* In multiply-only mode, R28/R29 operands are sampled on every clock
548 cycle. */
549 if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
550 {
551 CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
552 CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
553 }
554
555 switch (op->type)
556 {
557/* Helper macro to improve clarity of pru.isa. The empty while is a
558 guard against using RD as a left-hand side value. */
559#define RD do { } while (0); rd_is_modified = 1; _RDVAL
560#define INSTRUCTION(NAME, ACTION) \
561 case prui_ ## NAME: \
562 ACTION; \
563 break;
564#include "pru.isa"
565#undef INSTRUCTION
566#undef RD
567
568 default:
569 RAISE_SIGILL (sd);
570 }
571
572 if (rd_is_modified)
573 write_regval (_RDVAL, &CPU.regs[RD_REGN], RDSEL);
574
575 /* Don't treat r30 and r31 as regular registers, they are I/O! */
576 CPU.regs[30] = 0;
577 CPU.regs[31] = 0;
578
579 /* Handle PC match of loop end. */
580 if (LOOP_IN_PROGRESS && (PC == LOOPEND))
581 {
582 SIM_ASSERT (LOOPCNT > 0);
583 if (--LOOPCNT == 0)
584 LOOP_IN_PROGRESS = 0;
585 else
586 PC = LOOPTOP;
587 }
588
589 /* In multiply-only mode, MAC does multiplication every cycle. */
590 if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
591 {
592 uint64_t prod;
593 prod = CPU.macregs[PRU_MACREG_OP_0];
594 prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
595 CPU.macregs[PRU_MACREG_PROD_L] = prod & 0xfffffffful;
596 CPU.macregs[PRU_MACREG_PROD_H] = prod >> 32;
597
598 /* Clear the MAC accumulator when in normal mode. */
599 CPU.macregs[PRU_MACREG_ACC_L] = 0;
600 CPU.macregs[PRU_MACREG_ACC_H] = 0;
601 }
602
603 /* Update cycle counts. */
604 CPU.insts += 1; /* One instruction completed ... */
605 CPU.cycles += 1; /* ... and it takes a single cycle. */
606
607 /* Account for memory access latency with a reasonable estimate.
608 No distinction is currently made between SRAM, DRAM and generic
609 L3 slaves. */
610 if (op->type == prui_lbbo || op->type == prui_sbbo
611 || op->type == prui_lbco || op->type == prui_sbco)
612 CPU.cycles += 2;
613
614 }
615}
616
617/* Implement standard sim_engine_run function. */
618void
619sim_engine_run (SIM_DESC sd,
620 int next_cpu_nr, /* ignore */
621 int nr_cpus, /* ignore */
622 int siggnal) /* ignore */
623{
624 while (1)
625 {
626 sim_step_once (sd);
627 if (sim_events_tick (sd))
628 sim_events_process (sd);
629 }
630}
631
632
633/* Implement callback for standard CPU_PC_FETCH routine. */
634static sim_cia
635pru_pc_get (sim_cpu *cpu)
636{
637 /* Present PC as byte address. */
638 return imem_wordaddr_to_byteaddr (cpu, cpu->pru_cpu.pc);
639}
640
641/* Implement callback for standard CPU_PC_STORE routine. */
642static void
643pru_pc_set (sim_cpu *cpu, sim_cia pc)
644{
645 /* PC given as byte address. */
646 cpu->pru_cpu.pc = imem_byteaddr_to_wordaddr (cpu, pc);
647}
648
649
650/* Implement callback for standard CPU_REG_STORE routine. */
651static int
652pru_store_register (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
653{
654 if (rn < NUM_REGS && rn >= 0)
655 {
656 if (length == 4)
657 {
658 /* Misalignment safe. */
659 long ival = pru_extract_unsigned_integer (memory, 4);
660 if (rn < 32)
661 CPU.regs[rn] = ival;
662 else
663 pru_pc_set (cpu, ival);
664 return 4;
665 }
666 else
667 return 0;
668 }
669 else
670 return 0;
671}
672
673/* Implement callback for standard CPU_REG_FETCH routine. */
674static int
675pru_fetch_register (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
676{
677 long ival;
678
679 if (rn < NUM_REGS && rn >= 0)
680 {
681 if (length == 4)
682 {
683 if (rn < 32)
684 ival = CPU.regs[rn];
685 else
686 ival = pru_pc_get (cpu);
687
688 /* Misalignment-safe. */
689 pru_store_unsigned_integer (memory, 4, ival);
690 return 4;
691 }
692 else
693 return 0;
694 }
695 else
696 return 0;
697}
698
699static void
700free_state (SIM_DESC sd)
701{
702 if (STATE_MODULES (sd) != NULL)
703 sim_module_uninstall (sd);
704 sim_cpu_free_all (sd);
705 sim_state_free (sd);
706}
707
708/* Declare the PRU option handler. */
709static DECLARE_OPTION_HANDLER (pru_option_handler);
710
711/* Implement the PRU option handler. */
712static SIM_RC
713pru_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
714 int is_command)
715{
716 switch (opt)
717 {
718 case OPTION_ERROR_NULL_DEREF:
719 abort_on_dmem_zero_access = TRUE;
720 return SIM_RC_OK;
721
722 default:
723 sim_io_eprintf (sd, "Unknown PRU option %d\n", opt);
724 return SIM_RC_FAIL;
725 }
726}
727
728/* List of PRU-specific options. */
729static const OPTION pru_options[] =
730{
731 { {"error-null-deref", no_argument, NULL, OPTION_ERROR_NULL_DEREF},
732 '\0', NULL, "Trap any access to DMEM address zero",
733 pru_option_handler, NULL },
734
735 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
736};
737
738/* Implement standard sim_open function. */
739SIM_DESC
740sim_open (SIM_OPEN_KIND kind, host_callback *cb,
741 struct bfd *abfd, char * const *argv)
742{
743 int i;
744 char c;
745 SIM_DESC sd = sim_state_alloc (kind, cb);
746 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
747
ba307cdd
MF
748 /* Set default options before parsing user options. */
749 current_alignment = STRICT_ALIGNMENT;
f9a4d543 750 current_target_byte_order = BFD_ENDIAN_LITTLE;
ba307cdd 751
ddd44b70 752 /* The cpu data is kept in a separately allocated chunk of memory. */
d5a71b11 753 if (sim_cpu_alloc_all (sd, 1) != SIM_RC_OK)
ddd44b70
DD
754 {
755 free_state (sd);
756 return 0;
757 }
758
759 if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
760 {
761 free_state (sd);
762 return 0;
763 }
764 sim_add_option_table (sd, NULL, pru_options);
765
766 /* The parser will print an error message for us, so we silently return. */
767 if (sim_parse_args (sd, argv) != SIM_RC_OK)
768 {
769 free_state (sd);
770 return 0;
771 }
772
773 /* Check for/establish a reference program image. */
774 if (sim_analyze_program (sd,
775 (STATE_PROG_ARGV (sd) != NULL
776 ? *STATE_PROG_ARGV (sd)
777 : NULL), abfd) != SIM_RC_OK)
778 {
779 free_state (sd);
780 return 0;
781 }
782
783 /* Configure/verify the target byte order and other runtime
784 configuration options. */
785 if (sim_config (sd) != SIM_RC_OK)
786 {
787 sim_module_uninstall (sd);
788 return 0;
789 }
790
791 if (sim_post_argv_init (sd) != SIM_RC_OK)
792 {
793 /* Uninstall the modules to avoid memory leaks,
794 file descriptor leaks, etc. */
795 sim_module_uninstall (sd);
796 return 0;
797 }
798
799 /* CPU specific initialization. */
800 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
801 {
802 SIM_CPU *cpu = STATE_CPU (sd, i);
803
804 CPU_REG_STORE (cpu) = pru_store_register;
805 CPU_REG_FETCH (cpu) = pru_fetch_register;
806 CPU_PC_FETCH (cpu) = pru_pc_get;
807 CPU_PC_STORE (cpu) = pru_pc_set;
808
809 set_initial_gprs (cpu);
810 }
811
812 /* Allocate external memory if none specified by user.
813 Use address 4 here in case the user wanted address 0 unmapped. */
814 if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
815 {
816 sim_do_commandf (sd, "memory-region 0x%x,0x%x",
817 0,
818 DMEM_DEFAULT_SIZE);
819 }
820 if (sim_core_read_buffer (sd, NULL, read_map, &c, IMEM_ADDR_DEFAULT, 1) == 0)
821 {
822 sim_do_commandf (sd, "memory-region 0x%x,0x%x",
823 IMEM_ADDR_DEFAULT,
824 IMEM_DEFAULT_SIZE);
825 }
826
827 return sd;
828}
829
830/* Implement standard sim_create_inferior function. */
831SIM_RC
832sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
833 char * const *argv, char * const *env)
834{
835 SIM_CPU *cpu = STATE_CPU (sd, 0);
836 SIM_ADDR addr;
837
838 addr = bfd_get_start_address (prog_bfd);
839
840 sim_pc_set (cpu, addr);
841 PC_ADDR_SPACE_MARKER = addr & ~IMEM_ADDR_MASK;
842
843 /* Standalone mode (i.e. `run`) will take care of the argv for us in
844 sim_open () -> sim_parse_args (). But in debug mode (i.e. 'target sim'
845 with `gdb`), we need to handle it because the user can change the
846 argv on the fly via gdb's 'run'. */
847 if (STATE_PROG_ARGV (sd) != argv)
848 {
849 freeargv (STATE_PROG_ARGV (sd));
850 STATE_PROG_ARGV (sd) = dupargv (argv);
851 }
852
853 return SIM_RC_OK;
854}