xref: /netbsd-src/external/gpl3/gdb/dist/sim/pru/interp.c (revision 4439cfd0acf9c7dc90625e5cd83b2317a9ab8967)
1 /* Simulator for the Texas Instruments PRU processor
2    Copyright 2009-2024 Free Software Foundation, Inc.
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 
21 /* This must come before any other includes.  */
22 #include "defs.h"
23 
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stddef.h>
27 #include "bfd.h"
28 #include "sim/callback.h"
29 #include "libiberty.h"
30 #include "sim/sim.h"
31 #include "sim-main.h"
32 #include "sim-assert.h"
33 #include "sim-options.h"
34 #include "sim-signal.h"
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.  */
40 static bfd_boolean abort_on_dmem_zero_access;
41 
42 enum {
43   OPTION_ERROR_NULL_DEREF = OPTION_START,
44 };
45 
46 /* Extract (from PRU endianess) and return an integer in HOST's endianness.  */
47 static uint32_t
48 pru_extract_unsigned_integer (const uint8_t *addr, size_t len)
49 {
50   uint32_t retval;
51   const uint8_t *p;
52   const uint8_t *startaddr = addr;
53   const uint8_t *endaddr = startaddr + len;
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).  */
66 static void
67 pru_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).  */
84 static inline uint32_t
85 extract_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.  */
107 static inline void
108 write_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.  */
130 static uint32_t
131 imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
132 {
133   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
134 
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.  */
139 static uint16_t
140 imem_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.  */
148 static inline void
149 pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
150 	      int regn, int regb)
151 {
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);
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.  */
198 static inline void
199 pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
200 	      int regn, int regb)
201 {
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);
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.  */
251 static void
252 set_initial_gprs (SIM_CPU *cpu)
253 {
254   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
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.  */
311 static inline unsigned int
312 regsel_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.  */
329 static void
330 pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
331 		 unsigned int rdb, unsigned int length)
332 {
333   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
334 
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.  */
354 static void
355 pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
356 	     unsigned int rd_regn, unsigned int rdb, unsigned int length)
357 {
358   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
359 
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.  */
401 static void
402 pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
403 		  unsigned int rdb, unsigned int length)
404 {
405   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
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.  */
462 static void
463 pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
464 	      unsigned int rd_regn, unsigned int rdb, unsigned int length)
465 {
466   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
467 
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.  */
493 static void
494 pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
495 	      unsigned int rd_regn, unsigned int rdb, unsigned int length)
496 {
497   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
498 
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.  */
522 static void
523 pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
524 {
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];
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.  */
539 static void
540 sim_step_once (SIM_DESC sd)
541 {
542   SIM_CPU *cpu = STATE_CPU (sd, 0);
543   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
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.  */
635 void
636 sim_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.  */
651 static sim_cia
652 pru_pc_get (sim_cpu *cpu)
653 {
654   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
655 
656   /* Present PC as byte address.  */
657   return imem_wordaddr_to_byteaddr (cpu, pru_cpu->pc);
658 }
659 
660 /* Implement callback for standard CPU_PC_STORE routine.  */
661 static void
662 pru_pc_set (sim_cpu *cpu, sim_cia pc)
663 {
664   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
665 
666   /* PC given as byte address.  */
667   pru_cpu->pc = imem_byteaddr_to_wordaddr (cpu, pc);
668 }
669 
670 
671 /* Implement callback for standard CPU_REG_STORE routine.  */
672 static int
673 pru_store_register (SIM_CPU *cpu, int rn, const void *memory, int length)
674 {
675   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
676 
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.  */
697 static int
698 pru_fetch_register (SIM_CPU *cpu, int rn, void *memory, int length)
699 {
700   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
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 
723 static void
724 free_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.  */
733 static DECLARE_OPTION_HANDLER (pru_option_handler);
734 
735 /* Implement the PRU option handler.  */
736 static SIM_RC
737 pru_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.  */
753 static 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.  */
763 SIM_DESC
764 sim_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 
772   /* Set default options before parsing user options.  */
773   current_alignment = STRICT_ALIGNMENT;
774   current_target_byte_order = BFD_ENDIAN_LITTLE;
775 
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)
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.  */
798   if (sim_analyze_program (sd, STATE_PROG_FILE (sd), abfd) != SIM_RC_OK)
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.  */
852 SIM_RC
853 sim_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);
857   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
858   host_callback *cb = STATE_CALLBACK (sd);
859   bfd_vma addr;
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 
876   if (STATE_PROG_ENVP (sd) != env)
877     {
878       freeargv (STATE_PROG_ENVP (sd));
879       STATE_PROG_ENVP (sd) = dupargv (env);
880     }
881 
882   cb->argv = STATE_PROG_ARGV (sd);
883   cb->envp = STATE_PROG_ENVP (sd);
884 
885   return SIM_RC_OK;
886 }
887