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