1 /* Simulator for the Texas Instruments PRU processor
2 Copyright 2009-2023 Free Software Foundation, Inc.
3 Inspired by the Microblaze simulator
4 Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
6 This file is part of the 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 must come before any other includes. */
28 #include "sim/callback.h"
29 #include "libiberty.h"
32 #include "sim-assert.h"
33 #include "sim-options.h"
34 #include "sim-signal.h"
35 #include "sim-syscall.h"
38 /* DMEM zero address is perfectly valid. But if CRT leaves the first word
39 alone, we can use it as a trap to catch NULL pointer access. */
40 static bfd_boolean abort_on_dmem_zero_access
;
43 OPTION_ERROR_NULL_DEREF
= OPTION_START
,
46 /* Extract (from PRU endianess) and return an integer in HOST's endianness. */
48 pru_extract_unsigned_integer (const uint8_t *addr
, size_t len
)
52 const uint8_t *startaddr
= addr
;
53 const uint8_t *endaddr
= startaddr
+ len
;
55 /* Start at the most significant end of the integer, and work towards
56 the least significant. */
59 for (p
= endaddr
; p
> startaddr
;)
60 retval
= (retval
<< 8) | * -- p
;
64 /* Store "val" (which is in HOST's endianess) into "addr"
65 (using PRU's endianness). */
67 pru_store_unsigned_integer (uint8_t *addr
, size_t len
, uint32_t val
)
70 uint8_t *startaddr
= (uint8_t *)addr
;
71 uint8_t *endaddr
= startaddr
+ len
;
73 for (p
= startaddr
; p
< endaddr
;)
80 /* Extract a field value from CPU register using the given REGSEL selector.
82 Byte number maps directly to first values of RSEL, so we can
83 safely use "regsel" as a register byte number (0..3). */
84 static inline uint32_t
85 extract_regval (uint32_t val
, uint32_t regsel
)
87 ASSERT (RSEL_7_0
== 0);
88 ASSERT (RSEL_15_8
== 1);
89 ASSERT (RSEL_23_16
== 2);
90 ASSERT (RSEL_31_24
== 3);
94 case RSEL_7_0
: return (val
>> 0) & 0xff;
95 case RSEL_15_8
: return (val
>> 8) & 0xff;
96 case RSEL_23_16
: return (val
>> 16) & 0xff;
97 case RSEL_31_24
: return (val
>> 24) & 0xff;
98 case RSEL_15_0
: return (val
>> 0) & 0xffff;
99 case RSEL_23_8
: return (val
>> 8) & 0xffff;
100 case RSEL_31_16
: return (val
>> 16) & 0xffff;
101 case RSEL_31_0
: return val
;
102 default: sim_io_error (NULL
, "invalid regsel");
106 /* Write a value into CPU subregister pointed by reg and regsel. */
108 write_regval (uint32_t val
, uint32_t *reg
, uint32_t regsel
)
114 case RSEL_7_0
: mask
= (0xffu
<< 0); sh
= 0; break;
115 case RSEL_15_8
: mask
= (0xffu
<< 8); sh
= 8; break;
116 case RSEL_23_16
: mask
= (0xffu
<< 16); sh
= 16; break;
117 case RSEL_31_24
: mask
= (0xffu
<< 24); sh
= 24; break;
118 case RSEL_15_0
: mask
= (0xffffu
<< 0); sh
= 0; break;
119 case RSEL_23_8
: mask
= (0xffffu
<< 8); sh
= 8; break;
120 case RSEL_31_16
: mask
= (0xffffu
<< 16); sh
= 16; break;
121 case RSEL_31_0
: mask
= 0xffffffffu
; sh
= 0; break;
122 default: sim_io_error (NULL
, "invalid regsel");
125 *reg
= (*reg
& ~mask
) | ((val
<< sh
) & mask
);
128 /* Convert the given IMEM word address to a regular byte address used by the
129 GNU ELF container. */
131 imem_wordaddr_to_byteaddr (SIM_CPU
*cpu
, uint16_t wa
)
133 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
135 return (((uint32_t) wa
<< 2) & IMEM_ADDR_MASK
) | PC_ADDR_SPACE_MARKER
;
138 /* Convert the given ELF text byte address to IMEM word address. */
140 imem_byteaddr_to_wordaddr (SIM_CPU
*cpu
, uint32_t ba
)
142 return (ba
>> 2) & 0xffff;
146 /* Store "nbytes" into DMEM "addr" from CPU register file, starting with
147 register "regn", and byte "regb" within it. */
149 pru_reg2dmem (SIM_CPU
*cpu
, uint32_t addr
, unsigned int nbytes
,
152 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
153 /* GDB assumes unconditional access to all memories, so enable additional
154 checks only in standalone mode. */
155 bool standalone
= (STATE_OPEN_KIND (CPU_STATE (cpu
)) == SIM_OPEN_STANDALONE
);
157 if (abort_on_dmem_zero_access
&& addr
< 4)
159 sim_core_signal (CPU_STATE (cpu
), cpu
, PC_byteaddr
, write_map
,
160 nbytes
, addr
, write_transfer
,
161 sim_core_unmapped_signal
);
163 else if (standalone
&& ((addr
>= PC_ADDR_SPACE_MARKER
)
164 || (addr
+ nbytes
> PC_ADDR_SPACE_MARKER
)))
166 sim_core_signal (CPU_STATE (cpu
), cpu
, PC_byteaddr
, write_map
,
167 nbytes
, addr
, write_transfer
,
168 sim_core_unmapped_signal
);
170 else if ((regn
* 4 + regb
+ nbytes
) > (32 * 4))
172 sim_io_eprintf (CPU_STATE (cpu
),
173 "SBBO/SBCO with invalid store data length\n");
174 RAISE_SIGILL (CPU_STATE (cpu
));
178 TRACE_MEMORY (cpu
, "write of %d bytes to %08x", nbytes
, addr
);
181 sim_core_write_1 (cpu
,
185 extract_regval (CPU
.regs
[regn
], regb
));
196 /* Load "nbytes" from DMEM "addr" into CPU register file, starting with
197 register "regn", and byte "regb" within it. */
199 pru_dmem2reg (SIM_CPU
*cpu
, uint32_t addr
, unsigned int nbytes
,
202 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
203 /* GDB assumes unconditional access to all memories, so enable additional
204 checks only in standalone mode. */
205 bool standalone
= (STATE_OPEN_KIND (CPU_STATE (cpu
)) == SIM_OPEN_STANDALONE
);
207 if (abort_on_dmem_zero_access
&& addr
< 4)
209 sim_core_signal (CPU_STATE (cpu
), cpu
, PC_byteaddr
, read_map
,
210 nbytes
, addr
, read_transfer
,
211 sim_core_unmapped_signal
);
213 else if (standalone
&& ((addr
>= PC_ADDR_SPACE_MARKER
)
214 || (addr
+ nbytes
> PC_ADDR_SPACE_MARKER
)))
216 /* This check is necessary because our IMEM "address space"
217 is not really accessible, yet we have mapped it as a generic
219 sim_core_signal (CPU_STATE (cpu
), cpu
, PC_byteaddr
, read_map
,
220 nbytes
, addr
, read_transfer
,
221 sim_core_unmapped_signal
);
223 else if ((regn
* 4 + regb
+ nbytes
) > (32 * 4))
225 sim_io_eprintf (CPU_STATE (cpu
),
226 "LBBO/LBCO with invalid load data length\n");
227 RAISE_SIGILL (CPU_STATE (cpu
));
232 TRACE_MEMORY (cpu
, "read of %d bytes from %08x", nbytes
, addr
);
235 b
= sim_core_read_1 (cpu
, PC_byteaddr
, read_map
, addr
++);
237 /* Reuse the fact the Register Byte Number maps directly to RSEL. */
238 ASSERT (RSEL_7_0
== 0);
239 write_regval (b
, &CPU
.regs
[regn
], regb
);
250 /* Set reset values of general-purpose registers. */
252 set_initial_gprs (SIM_CPU
*cpu
)
254 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
257 /* Set up machine just out of reset. */
259 PC_ADDR_SPACE_MARKER
= IMEM_ADDR_DEFAULT
; /* from default linker script? */
261 /* Clean out the GPRs. */
262 for (i
= 0; i
< ARRAY_SIZE (CPU
.regs
); i
++)
264 for (i
= 0; i
< ARRAY_SIZE (CPU
.macregs
); i
++)
267 CPU
.loop
.looptop
= CPU
.loop
.loopend
= 0;
268 CPU
.loop
.loop_in_progress
= 0;
269 CPU
.loop
.loop_counter
= 0;
275 /* AM335x should provide sane defaults. */
276 CPU
.ctable
[0] = 0x00020000;
277 CPU
.ctable
[1] = 0x48040000;
278 CPU
.ctable
[2] = 0x4802a000;
279 CPU
.ctable
[3] = 0x00030000;
280 CPU
.ctable
[4] = 0x00026000;
281 CPU
.ctable
[5] = 0x48060000;
282 CPU
.ctable
[6] = 0x48030000;
283 CPU
.ctable
[7] = 0x00028000;
284 CPU
.ctable
[8] = 0x46000000;
285 CPU
.ctable
[9] = 0x4a100000;
286 CPU
.ctable
[10] = 0x48318000;
287 CPU
.ctable
[11] = 0x48022000;
288 CPU
.ctable
[12] = 0x48024000;
289 CPU
.ctable
[13] = 0x48310000;
290 CPU
.ctable
[14] = 0x481cc000;
291 CPU
.ctable
[15] = 0x481d0000;
292 CPU
.ctable
[16] = 0x481a0000;
293 CPU
.ctable
[17] = 0x4819c000;
294 CPU
.ctable
[18] = 0x48300000;
295 CPU
.ctable
[19] = 0x48302000;
296 CPU
.ctable
[20] = 0x48304000;
297 CPU
.ctable
[21] = 0x00032400;
298 CPU
.ctable
[22] = 0x480c8000;
299 CPU
.ctable
[23] = 0x480ca000;
300 CPU
.ctable
[24] = 0x00000000;
301 CPU
.ctable
[25] = 0x00002000;
302 CPU
.ctable
[26] = 0x0002e000;
303 CPU
.ctable
[27] = 0x00032000;
304 CPU
.ctable
[28] = 0x00000000;
305 CPU
.ctable
[29] = 0x49000000;
306 CPU
.ctable
[30] = 0x40000000;
307 CPU
.ctable
[31] = 0x80000000;
310 /* Map regsel selector to subregister field width. */
311 static inline unsigned int
312 regsel_width (uint32_t regsel
)
316 case RSEL_7_0
: return 8;
317 case RSEL_15_8
: return 8;
318 case RSEL_23_16
: return 8;
319 case RSEL_31_24
: return 8;
320 case RSEL_15_0
: return 16;
321 case RSEL_23_8
: return 16;
322 case RSEL_31_16
: return 16;
323 case RSEL_31_0
: return 32;
324 default: sim_io_error (NULL
, "invalid regsel");
328 /* Handle XIN instruction addressing the MAC peripheral. */
330 pru_sim_xin_mac (SIM_DESC sd
, SIM_CPU
*cpu
, unsigned int rd_regn
,
331 unsigned int rdb
, unsigned int length
)
333 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
335 if (rd_regn
< 25 || (rd_regn
* 4 + rdb
+ length
) > (27 + 1) * 4)
336 sim_io_error (sd
, "XIN MAC: invalid transfer regn=%u.%u, length=%u\n",
337 rd_regn
, rdb
, length
);
339 /* Copy from MAC to PRU regs. Ranges have been validated above. */
342 write_regval (CPU
.macregs
[rd_regn
- 25] >> (rdb
* 8),
353 /* Handle XIN instruction. */
355 pru_sim_xin (SIM_DESC sd
, SIM_CPU
*cpu
, unsigned int wba
,
356 unsigned int rd_regn
, unsigned int rdb
, unsigned int length
)
358 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
362 pru_sim_xin_mac (sd
, cpu
, rd_regn
, rdb
, length
);
364 else if (wba
== XFRID_SCRATCH_BANK_0
|| wba
== XFRID_SCRATCH_BANK_1
365 || wba
== XFRID_SCRATCH_BANK_2
|| wba
== XFRID_SCRATCH_BANK_PEER
)
371 val
= extract_regval (CPU
.scratchpads
[wba
][rd_regn
], rdb
);
372 write_regval (val
, &CPU
.regs
[rd_regn
], rdb
);
380 else if (wba
== 254 || wba
== 255)
382 /* FILL/ZERO pseudos implemented via XIN. */
383 unsigned int fillbyte
= (wba
== 254) ? 0xff : 0x00;
386 write_regval (fillbyte
, &CPU
.regs
[rd_regn
], rdb
);
396 sim_io_error (sd
, "XIN: XFR device %d not supported.\n", wba
);
400 /* Handle XOUT instruction addressing the MAC peripheral. */
402 pru_sim_xout_mac (SIM_DESC sd
, SIM_CPU
*cpu
, unsigned int rd_regn
,
403 unsigned int rdb
, unsigned int length
)
405 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
406 const int modereg_accessed
= (rd_regn
== 25);
408 /* Multiple Accumulate. */
409 if (rd_regn
< 25 || (rd_regn
* 4 + rdb
+ length
) > (27 + 1) * 4)
410 sim_io_error (sd
, "XOUT MAC: invalid transfer regn=%u.%u, length=%u\n",
411 rd_regn
, rdb
, length
);
413 /* Copy from PRU to MAC regs. Ranges have been validated above. */
416 write_regval (CPU
.regs
[rd_regn
] >> (rdb
* 8),
417 &CPU
.macregs
[rd_regn
- 25],
427 && (CPU
.macregs
[PRU_MACREG_MODE
] & MAC_R25_MAC_MODE_MASK
))
429 /* MUL/MAC operands are sampled every XOUT in multiply and
431 uint64_t prod
, oldsum
, sum
;
432 CPU
.macregs
[PRU_MACREG_OP_0
] = CPU
.regs
[28];
433 CPU
.macregs
[PRU_MACREG_OP_1
] = CPU
.regs
[29];
435 prod
= CPU
.macregs
[PRU_MACREG_OP_0
];
436 prod
*= (uint64_t)CPU
.macregs
[PRU_MACREG_OP_1
];
438 oldsum
= CPU
.macregs
[PRU_MACREG_ACC_L
];
439 oldsum
+= (uint64_t)CPU
.macregs
[PRU_MACREG_ACC_H
] << 32;
442 CPU
.macregs
[PRU_MACREG_PROD_L
] = sum
& 0xfffffffful
;
443 CPU
.macregs
[PRU_MACREG_PROD_H
] = sum
>> 32;
444 CPU
.macregs
[PRU_MACREG_ACC_L
] = CPU
.macregs
[PRU_MACREG_PROD_L
];
445 CPU
.macregs
[PRU_MACREG_ACC_H
] = CPU
.macregs
[PRU_MACREG_PROD_H
];
448 CPU
.macregs
[PRU_MACREG_MODE
] |= MAC_R25_ACC_CARRY_MASK
;
451 && (CPU
.macregs
[PRU_MACREG_MODE
] & MAC_R25_ACC_CARRY_MASK
))
453 /* store 1 to clear. */
454 CPU
.macregs
[PRU_MACREG_MODE
] &= ~MAC_R25_ACC_CARRY_MASK
;
455 CPU
.macregs
[PRU_MACREG_ACC_L
] = 0;
456 CPU
.macregs
[PRU_MACREG_ACC_H
] = 0;
461 /* Handle XOUT instruction. */
463 pru_sim_xout (SIM_DESC sd
, SIM_CPU
*cpu
, unsigned int wba
,
464 unsigned int rd_regn
, unsigned int rdb
, unsigned int length
)
466 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
470 pru_sim_xout_mac (sd
, cpu
, rd_regn
, rdb
, length
);
472 else if (wba
== XFRID_SCRATCH_BANK_0
|| wba
== XFRID_SCRATCH_BANK_1
473 || wba
== XFRID_SCRATCH_BANK_2
|| wba
== XFRID_SCRATCH_BANK_PEER
)
479 val
= extract_regval (CPU
.regs
[rd_regn
], rdb
);
480 write_regval (val
, &CPU
.scratchpads
[wba
][rd_regn
], rdb
);
489 sim_io_error (sd
, "XOUT: XFR device %d not supported.\n", wba
);
492 /* Handle XCHG instruction. */
494 pru_sim_xchg (SIM_DESC sd
, SIM_CPU
*cpu
, unsigned int wba
,
495 unsigned int rd_regn
, unsigned int rdb
, unsigned int length
)
497 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
499 if (wba
== XFRID_SCRATCH_BANK_0
|| wba
== XFRID_SCRATCH_BANK_1
500 || wba
== XFRID_SCRATCH_BANK_2
|| wba
== XFRID_SCRATCH_BANK_PEER
)
504 unsigned int valr
, vals
;
506 valr
= extract_regval (CPU
.regs
[rd_regn
], rdb
);
507 vals
= extract_regval (CPU
.scratchpads
[wba
][rd_regn
], rdb
);
508 write_regval (valr
, &CPU
.scratchpads
[wba
][rd_regn
], rdb
);
509 write_regval (vals
, &CPU
.regs
[rd_regn
], rdb
);
518 sim_io_error (sd
, "XOUT: XFR device %d not supported.\n", wba
);
521 /* Handle syscall simulation. Its ABI is specific to the GNU simulator. */
523 pru_sim_syscall (SIM_DESC sd
, SIM_CPU
*cpu
)
525 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
526 /* If someday TI confirms that the "reserved" HALT opcode fields
527 can be used for extra arguments, then maybe we can embed
528 the syscall number there. Until then, let's use R1. */
529 const uint32_t syscall_num
= CPU
.regs
[1];
532 ret
= sim_syscall (cpu
, syscall_num
,
533 CPU
.regs
[14], CPU
.regs
[15],
534 CPU
.regs
[16], CPU
.regs
[17]);
538 /* Simulate one instruction. */
540 sim_step_once (SIM_DESC sd
)
542 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
543 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
544 const struct pru_opcode
*op
;
546 uint32_t _RDVAL
, OP2
; /* intermediate values. */
547 int rd_is_modified
= 0; /* RD modified and must be stored back. */
549 /* Fetch the initial instruction that we'll decode. */
550 inst
= sim_core_read_4 (cpu
, PC_byteaddr
, exec_map
, PC_byteaddr
);
551 TRACE_MEMORY (cpu
, "read of insn 0x%08x from %08x", inst
, PC_byteaddr
);
553 op
= pru_find_opcode (inst
);
557 sim_io_eprintf (sd
, "Unknown instruction 0x%04x\n", inst
);
562 TRACE_DISASM (cpu
, PC_byteaddr
);
564 /* In multiply-only mode, R28/R29 operands are sampled on every clock
566 if ((CPU
.macregs
[PRU_MACREG_MODE
] & MAC_R25_MAC_MODE_MASK
) == 0)
568 CPU
.macregs
[PRU_MACREG_OP_0
] = CPU
.regs
[28];
569 CPU
.macregs
[PRU_MACREG_OP_1
] = CPU
.regs
[29];
574 /* Helper macro to improve clarity of pru.isa. The empty while is a
575 guard against using RD as a left-hand side value. */
576 #define RD do { } while (0); rd_is_modified = 1; _RDVAL
577 #define INSTRUCTION(NAME, ACTION) \
578 case prui_ ## NAME: \
590 write_regval (_RDVAL
, &CPU
.regs
[RD_REGN
], RDSEL
);
592 /* Don't treat r30 and r31 as regular registers, they are I/O! */
596 /* Handle PC match of loop end. */
597 if (LOOP_IN_PROGRESS
&& (PC
== LOOPEND
))
599 SIM_ASSERT (LOOPCNT
> 0);
601 LOOP_IN_PROGRESS
= 0;
606 /* In multiply-only mode, MAC does multiplication every cycle. */
607 if ((CPU
.macregs
[PRU_MACREG_MODE
] & MAC_R25_MAC_MODE_MASK
) == 0)
610 prod
= CPU
.macregs
[PRU_MACREG_OP_0
];
611 prod
*= (uint64_t)CPU
.macregs
[PRU_MACREG_OP_1
];
612 CPU
.macregs
[PRU_MACREG_PROD_L
] = prod
& 0xfffffffful
;
613 CPU
.macregs
[PRU_MACREG_PROD_H
] = prod
>> 32;
615 /* Clear the MAC accumulator when in normal mode. */
616 CPU
.macregs
[PRU_MACREG_ACC_L
] = 0;
617 CPU
.macregs
[PRU_MACREG_ACC_H
] = 0;
620 /* Update cycle counts. */
621 CPU
.insts
+= 1; /* One instruction completed ... */
622 CPU
.cycles
+= 1; /* ... and it takes a single cycle. */
624 /* Account for memory access latency with a reasonable estimate.
625 No distinction is currently made between SRAM, DRAM and generic
627 if (op
->type
== prui_lbbo
|| op
->type
== prui_sbbo
628 || op
->type
== prui_lbco
|| op
->type
== prui_sbco
)
634 /* Implement standard sim_engine_run function. */
636 sim_engine_run (SIM_DESC sd
,
637 int next_cpu_nr
, /* ignore */
638 int nr_cpus
, /* ignore */
639 int siggnal
) /* ignore */
644 if (sim_events_tick (sd
))
645 sim_events_process (sd
);
650 /* Implement callback for standard CPU_PC_FETCH routine. */
652 pru_pc_get (sim_cpu
*cpu
)
654 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
656 /* Present PC as byte address. */
657 return imem_wordaddr_to_byteaddr (cpu
, pru_cpu
->pc
);
660 /* Implement callback for standard CPU_PC_STORE routine. */
662 pru_pc_set (sim_cpu
*cpu
, sim_cia pc
)
664 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
666 /* PC given as byte address. */
667 pru_cpu
->pc
= imem_byteaddr_to_wordaddr (cpu
, pc
);
671 /* Implement callback for standard CPU_REG_STORE routine. */
673 pru_store_register (SIM_CPU
*cpu
, int rn
, const void *memory
, int length
)
675 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
677 if (rn
< NUM_REGS
&& rn
>= 0)
681 /* Misalignment safe. */
682 long ival
= pru_extract_unsigned_integer (memory
, 4);
686 pru_pc_set (cpu
, ival
);
696 /* Implement callback for standard CPU_REG_FETCH routine. */
698 pru_fetch_register (SIM_CPU
*cpu
, int rn
, void *memory
, int length
)
700 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
703 if (rn
< NUM_REGS
&& rn
>= 0)
710 ival
= pru_pc_get (cpu
);
712 /* Misalignment-safe. */
713 pru_store_unsigned_integer (memory
, 4, ival
);
724 free_state (SIM_DESC sd
)
726 if (STATE_MODULES (sd
) != NULL
)
727 sim_module_uninstall (sd
);
728 sim_cpu_free_all (sd
);
732 /* Declare the PRU option handler. */
733 static DECLARE_OPTION_HANDLER (pru_option_handler
);
735 /* Implement the PRU option handler. */
737 pru_option_handler (SIM_DESC sd
, sim_cpu
*cpu
, int opt
, char *arg
,
742 case OPTION_ERROR_NULL_DEREF
:
743 abort_on_dmem_zero_access
= TRUE
;
747 sim_io_eprintf (sd
, "Unknown PRU option %d\n", opt
);
752 /* List of PRU-specific options. */
753 static const OPTION pru_options
[] =
755 { {"error-null-deref", no_argument
, NULL
, OPTION_ERROR_NULL_DEREF
},
756 '\0', NULL
, "Trap any access to DMEM address zero",
757 pru_option_handler
, NULL
},
759 { {NULL
, no_argument
, NULL
, 0}, '\0', NULL
, NULL
, NULL
, NULL
}
762 /* Implement standard sim_open function. */
764 sim_open (SIM_OPEN_KIND kind
, host_callback
*cb
,
765 struct bfd
*abfd
, char * const *argv
)
769 SIM_DESC sd
= sim_state_alloc (kind
, cb
);
770 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
772 /* Set default options before parsing user options. */
773 current_alignment
= STRICT_ALIGNMENT
;
774 current_target_byte_order
= BFD_ENDIAN_LITTLE
;
776 /* The cpu data is kept in a separately allocated chunk of memory. */
777 if (sim_cpu_alloc_all_extra (sd
, 0, sizeof (struct pru_regset
)) != SIM_RC_OK
)
783 if (sim_pre_argv_init (sd
, argv
[0]) != SIM_RC_OK
)
788 sim_add_option_table (sd
, NULL
, pru_options
);
790 /* The parser will print an error message for us, so we silently return. */
791 if (sim_parse_args (sd
, argv
) != SIM_RC_OK
)
797 /* Check for/establish a reference program image. */
798 if (sim_analyze_program (sd
, STATE_PROG_FILE (sd
), abfd
) != SIM_RC_OK
)
804 /* Configure/verify the target byte order and other runtime
805 configuration options. */
806 if (sim_config (sd
) != SIM_RC_OK
)
808 sim_module_uninstall (sd
);
812 if (sim_post_argv_init (sd
) != SIM_RC_OK
)
814 /* Uninstall the modules to avoid memory leaks,
815 file descriptor leaks, etc. */
816 sim_module_uninstall (sd
);
820 /* CPU specific initialization. */
821 for (i
= 0; i
< MAX_NR_PROCESSORS
; ++i
)
823 SIM_CPU
*cpu
= STATE_CPU (sd
, i
);
825 CPU_REG_STORE (cpu
) = pru_store_register
;
826 CPU_REG_FETCH (cpu
) = pru_fetch_register
;
827 CPU_PC_FETCH (cpu
) = pru_pc_get
;
828 CPU_PC_STORE (cpu
) = pru_pc_set
;
830 set_initial_gprs (cpu
);
833 /* Allocate external memory if none specified by user.
834 Use address 4 here in case the user wanted address 0 unmapped. */
835 if (sim_core_read_buffer (sd
, NULL
, read_map
, &c
, 4, 1) == 0)
837 sim_do_commandf (sd
, "memory-region 0x%x,0x%x",
841 if (sim_core_read_buffer (sd
, NULL
, read_map
, &c
, IMEM_ADDR_DEFAULT
, 1) == 0)
843 sim_do_commandf (sd
, "memory-region 0x%x,0x%x",
851 /* Implement standard sim_create_inferior function. */
853 sim_create_inferior (SIM_DESC sd
, struct bfd
*prog_bfd
,
854 char * const *argv
, char * const *env
)
856 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
857 struct pru_regset
*pru_cpu
= PRU_SIM_CPU (cpu
);
858 host_callback
*cb
= STATE_CALLBACK (sd
);
861 addr
= bfd_get_start_address (prog_bfd
);
863 sim_pc_set (cpu
, addr
);
864 PC_ADDR_SPACE_MARKER
= addr
& ~IMEM_ADDR_MASK
;
866 /* Standalone mode (i.e. `run`) will take care of the argv for us in
867 sim_open () -> sim_parse_args (). But in debug mode (i.e. 'target sim'
868 with `gdb`), we need to handle it because the user can change the
869 argv on the fly via gdb's 'run'. */
870 if (STATE_PROG_ARGV (sd
) != argv
)
872 freeargv (STATE_PROG_ARGV (sd
));
873 STATE_PROG_ARGV (sd
) = dupargv (argv
);
876 if (STATE_PROG_ENVP (sd
) != env
)
878 freeargv (STATE_PROG_ENVP (sd
));
879 STATE_PROG_ENVP (sd
) = dupargv (env
);
882 cb
->argv
= STATE_PROG_ARGV (sd
);
883 cb
->envp
= STATE_PROG_ENVP (sd
);