]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/pru/interp.c
Fix build issues with mingw toolchain
[thirdparty/binutils-gdb.git] / sim / pru / interp.c
CommitLineData
ddd44b70 1/* Simulator for the Texas Instruments PRU processor
1d506c26 2 Copyright 2009-2024 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"
1fef66b0 34#include "sim-signal.h"
ddd44b70
DD
35#include "sim-syscall.h"
36#include "pru.h"
37
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. */
40static bfd_boolean abort_on_dmem_zero_access;
41
42enum {
43 OPTION_ERROR_NULL_DEREF = OPTION_START,
44};
45
46/* Extract (from PRU endianess) and return an integer in HOST's endianness. */
47static uint32_t
ed60d3ed 48pru_extract_unsigned_integer (const uint8_t *addr, size_t len)
ddd44b70
DD
49{
50 uint32_t retval;
ed60d3ed
MF
51 const uint8_t *p;
52 const uint8_t *startaddr = addr;
53 const uint8_t *endaddr = startaddr + len;
ddd44b70
DD
54
55 /* Start at the most significant end of the integer, and work towards
56 the least significant. */
57 retval = 0;
58
59 for (p = endaddr; p > startaddr;)
60 retval = (retval << 8) | * -- p;
61 return retval;
62}
63
64/* Store "val" (which is in HOST's endianess) into "addr"
65 (using PRU's endianness). */
66static void
67pru_store_unsigned_integer (uint8_t *addr, size_t len, uint32_t val)
68{
69 uint8_t *p;
70 uint8_t *startaddr = (uint8_t *)addr;
71 uint8_t *endaddr = startaddr + len;
72
73 for (p = startaddr; p < endaddr;)
74 {
75 *p++ = val & 0xff;
76 val >>= 8;
77 }
78}
79
80/* Extract a field value from CPU register using the given REGSEL selector.
81
82 Byte number maps directly to first values of RSEL, so we can
83 safely use "regsel" as a register byte number (0..3). */
84static inline uint32_t
85extract_regval (uint32_t val, uint32_t regsel)
86{
87 ASSERT (RSEL_7_0 == 0);
88 ASSERT (RSEL_15_8 == 1);
89 ASSERT (RSEL_23_16 == 2);
90 ASSERT (RSEL_31_24 == 3);
91
92 switch (regsel)
93 {
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");
103 }
104}
105
106/* Write a value into CPU subregister pointed by reg and regsel. */
107static inline void
108write_regval (uint32_t val, uint32_t *reg, uint32_t regsel)
109{
110 uint32_t mask, sh;
111
112 switch (regsel)
113 {
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");
123 }
124
125 *reg = (*reg & ~mask) | ((val << sh) & mask);
126}
127
128/* Convert the given IMEM word address to a regular byte address used by the
129 GNU ELF container. */
130static uint32_t
131imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
132{
3d165c11
MF
133 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
134
ddd44b70
DD
135 return (((uint32_t) wa << 2) & IMEM_ADDR_MASK) | PC_ADDR_SPACE_MARKER;
136}
137
138/* Convert the given ELF text byte address to IMEM word address. */
139static uint16_t
140imem_byteaddr_to_wordaddr (SIM_CPU *cpu, uint32_t ba)
141{
142 return (ba >> 2) & 0xffff;
143}
144
145
146/* Store "nbytes" into DMEM "addr" from CPU register file, starting with
147 register "regn", and byte "regb" within it. */
148static inline void
149pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
150 int regn, int regb)
151{
3d165c11 152 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
ddd44b70
DD
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);
156
157 if (abort_on_dmem_zero_access && addr < 4)
158 {
159 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
160 nbytes, addr, write_transfer,
161 sim_core_unmapped_signal);
162 }
163 else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
164 || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
165 {
166 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
167 nbytes, addr, write_transfer,
168 sim_core_unmapped_signal);
169 }
170 else if ((regn * 4 + regb + nbytes) > (32 * 4))
171 {
172 sim_io_eprintf (CPU_STATE (cpu),
173 "SBBO/SBCO with invalid store data length\n");
174 RAISE_SIGILL (CPU_STATE (cpu));
175 }
176 else
177 {
178 TRACE_MEMORY (cpu, "write of %d bytes to %08x", nbytes, addr);
179 while (nbytes--)
180 {
181 sim_core_write_1 (cpu,
182 PC_byteaddr,
183 write_map,
184 addr++,
185 extract_regval (CPU.regs[regn], regb));
186
187 if (++regb >= 4)
188 {
189 regb = 0;
190 regn++;
191 }
192 }
193 }
194}
195
196/* Load "nbytes" from DMEM "addr" into CPU register file, starting with
197 register "regn", and byte "regb" within it. */
198static inline void
199pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
200 int regn, int regb)
201{
3d165c11 202 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
ddd44b70
DD
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);
206
207 if (abort_on_dmem_zero_access && addr < 4)
208 {
209 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
210 nbytes, addr, read_transfer,
211 sim_core_unmapped_signal);
212 }
213 else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
214 || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
215 {
216 /* This check is necessary because our IMEM "address space"
217 is not really accessible, yet we have mapped it as a generic
218 memory space. */
219 sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
220 nbytes, addr, read_transfer,
221 sim_core_unmapped_signal);
222 }
223 else if ((regn * 4 + regb + nbytes) > (32 * 4))
224 {
225 sim_io_eprintf (CPU_STATE (cpu),
226 "LBBO/LBCO with invalid load data length\n");
227 RAISE_SIGILL (CPU_STATE (cpu));
228 }
229 else
230 {
231 unsigned int b;
232 TRACE_MEMORY (cpu, "read of %d bytes from %08x", nbytes, addr);
233 while (nbytes--)
234 {
235 b = sim_core_read_1 (cpu, PC_byteaddr, read_map, addr++);
236
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);
240
241 if (++regb >= 4)
242 {
243 regb = 0;
244 regn++;
245 }
246 }
247 }
248}
249
250/* Set reset values of general-purpose registers. */
251static void
252set_initial_gprs (SIM_CPU *cpu)
253{
3d165c11 254 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
ddd44b70
DD
255 int i;
256
257 /* Set up machine just out of reset. */
258 CPU_PC_SET (cpu, 0);
259 PC_ADDR_SPACE_MARKER = IMEM_ADDR_DEFAULT; /* from default linker script? */
260
261 /* Clean out the GPRs. */
262 for (i = 0; i < ARRAY_SIZE (CPU.regs); i++)
263 CPU.regs[i] = 0;
264 for (i = 0; i < ARRAY_SIZE (CPU.macregs); i++)
265 CPU.macregs[i] = 0;
266
267 CPU.loop.looptop = CPU.loop.loopend = 0;
268 CPU.loop.loop_in_progress = 0;
269 CPU.loop.loop_counter = 0;
270
271 CPU.carry = 0;
272 CPU.insts = 0;
273 CPU.cycles = 0;
274
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;
308}
309
310/* Map regsel selector to subregister field width. */
311static inline unsigned int
312regsel_width (uint32_t regsel)
313{
314 switch (regsel)
315 {
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");
325 }
326}
327
328/* Handle XIN instruction addressing the MAC peripheral. */
329static void
330pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
331 unsigned int rdb, unsigned int length)
332{
3d165c11
MF
333 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
334
ddd44b70
DD
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);
338
339 /* Copy from MAC to PRU regs. Ranges have been validated above. */
340 while (length--)
341 {
342 write_regval (CPU.macregs[rd_regn - 25] >> (rdb * 8),
343 &CPU.regs[rd_regn],
344 rdb);
345 if (++rdb == 4)
346 {
347 rdb = 0;
348 rd_regn++;
349 }
350 }
351}
352
353/* Handle XIN instruction. */
354static void
355pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
356 unsigned int rd_regn, unsigned int rdb, unsigned int length)
357{
3d165c11
MF
358 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
359
ddd44b70
DD
360 if (wba == 0)
361 {
362 pru_sim_xin_mac (sd, cpu, rd_regn, rdb, length);
363 }
364 else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
365 || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
366 {
367 while (length--)
368 {
369 unsigned int val;
370
371 val = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
372 write_regval (val, &CPU.regs[rd_regn], rdb);
373 if (++rdb == 4)
374 {
375 rdb = 0;
376 rd_regn++;
377 }
378 }
379 }
380 else if (wba == 254 || wba == 255)
381 {
382 /* FILL/ZERO pseudos implemented via XIN. */
383 unsigned int fillbyte = (wba == 254) ? 0xff : 0x00;
384 while (length--)
385 {
386 write_regval (fillbyte, &CPU.regs[rd_regn], rdb);
387 if (++rdb == 4)
388 {
389 rdb = 0;
390 rd_regn++;
391 }
392 }
393 }
394 else
395 {
396 sim_io_error (sd, "XIN: XFR device %d not supported.\n", wba);
397 }
398}
399
400/* Handle XOUT instruction addressing the MAC peripheral. */
401static void
402pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
403 unsigned int rdb, unsigned int length)
404{
3d165c11 405 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
ddd44b70
DD
406 const int modereg_accessed = (rd_regn == 25);
407
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);
412
413 /* Copy from PRU to MAC regs. Ranges have been validated above. */
414 while (length--)
415 {
416 write_regval (CPU.regs[rd_regn] >> (rdb * 8),
417 &CPU.macregs[rd_regn - 25],
418 rdb);
419 if (++rdb == 4)
420 {
421 rdb = 0;
422 rd_regn++;
423 }
424 }
425
426 if (modereg_accessed
427 && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK))
428 {
429 /* MUL/MAC operands are sampled every XOUT in multiply and
430 accumulate mode. */
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];
434
435 prod = CPU.macregs[PRU_MACREG_OP_0];
436 prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
437
438 oldsum = CPU.macregs[PRU_MACREG_ACC_L];
439 oldsum += (uint64_t)CPU.macregs[PRU_MACREG_ACC_H] << 32;
440 sum = oldsum + prod;
441
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];
446
447 if (oldsum > sum)
448 CPU.macregs[PRU_MACREG_MODE] |= MAC_R25_ACC_CARRY_MASK;
449 }
450 if (modereg_accessed
451 && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_ACC_CARRY_MASK))
452 {
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;
457 }
458
459}
460
461/* Handle XOUT instruction. */
462static void
463pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
464 unsigned int rd_regn, unsigned int rdb, unsigned int length)
465{
3d165c11
MF
466 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
467
ddd44b70
DD
468 if (wba == 0)
469 {
470 pru_sim_xout_mac (sd, cpu, rd_regn, rdb, length);
471 }
472 else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
473 || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
474 {
475 while (length--)
476 {
477 unsigned int val;
478
479 val = extract_regval (CPU.regs[rd_regn], rdb);
480 write_regval (val, &CPU.scratchpads[wba][rd_regn], rdb);
481 if (++rdb == 4)
482 {
483 rdb = 0;
484 rd_regn++;
485 }
486 }
487 }
488 else
489 sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
490}
491
492/* Handle XCHG instruction. */
493static void
494pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
495 unsigned int rd_regn, unsigned int rdb, unsigned int length)
496{
3d165c11
MF
497 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
498
ddd44b70
DD
499 if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
500 || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
501 {
502 while (length--)
503 {
504 unsigned int valr, vals;
505
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);
510 if (++rdb == 4)
511 {
512 rdb = 0;
513 rd_regn++;
514 }
515 }
516 }
517 else
518 sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
519}
520
521/* Handle syscall simulation. Its ABI is specific to the GNU simulator. */
522static void
523pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
524{
3d165c11 525 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
ddd44b70
DD
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];
530 long ret;
531
532 ret = sim_syscall (cpu, syscall_num,
533 CPU.regs[14], CPU.regs[15],
534 CPU.regs[16], CPU.regs[17]);
535 CPU.regs[14] = ret;
536}
537
538/* Simulate one instruction. */
539static void
540sim_step_once (SIM_DESC sd)
541{
542 SIM_CPU *cpu = STATE_CPU (sd, 0);
3d165c11 543 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
ddd44b70
DD
544 const struct pru_opcode *op;
545 uint32_t inst;
546 uint32_t _RDVAL, OP2; /* intermediate values. */
547 int rd_is_modified = 0; /* RD modified and must be stored back. */
548
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);
552
553 op = pru_find_opcode (inst);
554
555 if (!op)
556 {
557 sim_io_eprintf (sd, "Unknown instruction 0x%04x\n", inst);
558 RAISE_SIGILL (sd);
559 }
560 else
561 {
562 TRACE_DISASM (cpu, PC_byteaddr);
563
564 /* In multiply-only mode, R28/R29 operands are sampled on every clock
565 cycle. */
566 if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
567 {
568 CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
569 CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
570 }
571
572 switch (op->type)
573 {
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: \
579 ACTION; \
580 break;
581#include "pru.isa"
582#undef INSTRUCTION
583#undef RD
584
585 default:
586 RAISE_SIGILL (sd);
587 }
588
589 if (rd_is_modified)
590 write_regval (_RDVAL, &CPU.regs[RD_REGN], RDSEL);
591
592 /* Don't treat r30 and r31 as regular registers, they are I/O! */
593 CPU.regs[30] = 0;
594 CPU.regs[31] = 0;
595
596 /* Handle PC match of loop end. */
597 if (LOOP_IN_PROGRESS && (PC == LOOPEND))
598 {
599 SIM_ASSERT (LOOPCNT > 0);
600 if (--LOOPCNT == 0)
601 LOOP_IN_PROGRESS = 0;
602 else
603 PC = LOOPTOP;
604 }
605
606 /* In multiply-only mode, MAC does multiplication every cycle. */
607 if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
608 {
609 uint64_t prod;
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;
614
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;
618 }
619
620 /* Update cycle counts. */
621 CPU.insts += 1; /* One instruction completed ... */
622 CPU.cycles += 1; /* ... and it takes a single cycle. */
623
624 /* Account for memory access latency with a reasonable estimate.
625 No distinction is currently made between SRAM, DRAM and generic
626 L3 slaves. */
627 if (op->type == prui_lbbo || op->type == prui_sbbo
628 || op->type == prui_lbco || op->type == prui_sbco)
629 CPU.cycles += 2;
630
631 }
632}
633
634/* Implement standard sim_engine_run function. */
635void
636sim_engine_run (SIM_DESC sd,
637 int next_cpu_nr, /* ignore */
638 int nr_cpus, /* ignore */
639 int siggnal) /* ignore */
640{
641 while (1)
642 {
643 sim_step_once (sd);
644 if (sim_events_tick (sd))
645 sim_events_process (sd);
646 }
647}
648
649
650/* Implement callback for standard CPU_PC_FETCH routine. */
651static sim_cia
652pru_pc_get (sim_cpu *cpu)
653{
3d165c11
MF
654 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
655
ddd44b70 656 /* Present PC as byte address. */
3d165c11 657 return imem_wordaddr_to_byteaddr (cpu, pru_cpu->pc);
ddd44b70
DD
658}
659
660/* Implement callback for standard CPU_PC_STORE routine. */
661static void
662pru_pc_set (sim_cpu *cpu, sim_cia pc)
663{
3d165c11
MF
664 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
665
ddd44b70 666 /* PC given as byte address. */
3d165c11 667 pru_cpu->pc = imem_byteaddr_to_wordaddr (cpu, pc);
ddd44b70
DD
668}
669
670
671/* Implement callback for standard CPU_REG_STORE routine. */
672static int
ee1cffd3 673pru_store_register (SIM_CPU *cpu, int rn, const void *memory, int length)
ddd44b70 674{
3d165c11
MF
675 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
676
ddd44b70
DD
677 if (rn < NUM_REGS && rn >= 0)
678 {
679 if (length == 4)
680 {
681 /* Misalignment safe. */
682 long ival = pru_extract_unsigned_integer (memory, 4);
683 if (rn < 32)
684 CPU.regs[rn] = ival;
685 else
686 pru_pc_set (cpu, ival);
687 return 4;
688 }
689 else
690 return 0;
691 }
692 else
693 return 0;
694}
695
696/* Implement callback for standard CPU_REG_FETCH routine. */
697static int
ee1cffd3 698pru_fetch_register (SIM_CPU *cpu, int rn, void *memory, int length)
ddd44b70 699{
3d165c11 700 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
ddd44b70
DD
701 long ival;
702
703 if (rn < NUM_REGS && rn >= 0)
704 {
705 if (length == 4)
706 {
707 if (rn < 32)
708 ival = CPU.regs[rn];
709 else
710 ival = pru_pc_get (cpu);
711
712 /* Misalignment-safe. */
713 pru_store_unsigned_integer (memory, 4, ival);
714 return 4;
715 }
716 else
717 return 0;
718 }
719 else
720 return 0;
721}
722
723static void
724free_state (SIM_DESC sd)
725{
726 if (STATE_MODULES (sd) != NULL)
727 sim_module_uninstall (sd);
728 sim_cpu_free_all (sd);
729 sim_state_free (sd);
730}
731
732/* Declare the PRU option handler. */
733static DECLARE_OPTION_HANDLER (pru_option_handler);
734
735/* Implement the PRU option handler. */
736static SIM_RC
737pru_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
738 int is_command)
739{
740 switch (opt)
741 {
742 case OPTION_ERROR_NULL_DEREF:
743 abort_on_dmem_zero_access = TRUE;
744 return SIM_RC_OK;
745
746 default:
747 sim_io_eprintf (sd, "Unknown PRU option %d\n", opt);
748 return SIM_RC_FAIL;
749 }
750}
751
752/* List of PRU-specific options. */
753static const OPTION pru_options[] =
754{
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 },
758
759 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
760};
761
762/* Implement standard sim_open function. */
763SIM_DESC
764sim_open (SIM_OPEN_KIND kind, host_callback *cb,
765 struct bfd *abfd, char * const *argv)
766{
767 int i;
768 char c;
769 SIM_DESC sd = sim_state_alloc (kind, cb);
770 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
771
ba307cdd
MF
772 /* Set default options before parsing user options. */
773 current_alignment = STRICT_ALIGNMENT;
f9a4d543 774 current_target_byte_order = BFD_ENDIAN_LITTLE;
ba307cdd 775
ddd44b70 776 /* The cpu data is kept in a separately allocated chunk of memory. */
883be197 777 if (sim_cpu_alloc_all_extra (sd, 0, sizeof (struct pru_regset)) != SIM_RC_OK)
ddd44b70
DD
778 {
779 free_state (sd);
780 return 0;
781 }
782
783 if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
784 {
785 free_state (sd);
786 return 0;
787 }
788 sim_add_option_table (sd, NULL, pru_options);
789
790 /* The parser will print an error message for us, so we silently return. */
791 if (sim_parse_args (sd, argv) != SIM_RC_OK)
792 {
793 free_state (sd);
794 return 0;
795 }
796
797 /* Check for/establish a reference program image. */
e8f20a28 798 if (sim_analyze_program (sd, STATE_PROG_FILE (sd), abfd) != SIM_RC_OK)
ddd44b70
DD
799 {
800 free_state (sd);
801 return 0;
802 }
803
804 /* Configure/verify the target byte order and other runtime
805 configuration options. */
806 if (sim_config (sd) != SIM_RC_OK)
807 {
808 sim_module_uninstall (sd);
809 return 0;
810 }
811
812 if (sim_post_argv_init (sd) != SIM_RC_OK)
813 {
814 /* Uninstall the modules to avoid memory leaks,
815 file descriptor leaks, etc. */
816 sim_module_uninstall (sd);
817 return 0;
818 }
819
820 /* CPU specific initialization. */
821 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
822 {
823 SIM_CPU *cpu = STATE_CPU (sd, i);
824
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;
829
830 set_initial_gprs (cpu);
831 }
832
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)
836 {
837 sim_do_commandf (sd, "memory-region 0x%x,0x%x",
838 0,
839 DMEM_DEFAULT_SIZE);
840 }
841 if (sim_core_read_buffer (sd, NULL, read_map, &c, IMEM_ADDR_DEFAULT, 1) == 0)
842 {
843 sim_do_commandf (sd, "memory-region 0x%x,0x%x",
844 IMEM_ADDR_DEFAULT,
845 IMEM_DEFAULT_SIZE);
846 }
847
848 return sd;
849}
850
851/* Implement standard sim_create_inferior function. */
852SIM_RC
853sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
854 char * const *argv, char * const *env)
855{
856 SIM_CPU *cpu = STATE_CPU (sd, 0);
3d165c11 857 struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
8cfc9a18 858 host_callback *cb = STATE_CALLBACK (sd);
20fea663 859 bfd_vma addr;
ddd44b70
DD
860
861 addr = bfd_get_start_address (prog_bfd);
862
863 sim_pc_set (cpu, addr);
864 PC_ADDR_SPACE_MARKER = addr & ~IMEM_ADDR_MASK;
865
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)
871 {
872 freeargv (STATE_PROG_ARGV (sd));
873 STATE_PROG_ARGV (sd) = dupargv (argv);
874 }
875
54f7a83a
MF
876 if (STATE_PROG_ENVP (sd) != env)
877 {
878 freeargv (STATE_PROG_ENVP (sd));
879 STATE_PROG_ENVP (sd) = dupargv (env);
880 }
881
8cfc9a18
MF
882 cb->argv = STATE_PROG_ARGV (sd);
883 cb->envp = STATE_PROG_ENVP (sd);
884
ddd44b70
DD
885 return SIM_RC_OK;
886}