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