xref: /netbsd-src/external/gpl3/gdb/dist/sim/pru/interp.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
18dffb485Schristos /* Simulator for the Texas Instruments PRU processor
2*1f4e7eb9Schristos    Copyright 2009-2024 Free Software Foundation, Inc.
38dffb485Schristos    Inspired by the Microblaze simulator
48dffb485Schristos    Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
58dffb485Schristos 
68dffb485Schristos    This file is part of the simulators.
78dffb485Schristos 
88dffb485Schristos    This program is free software; you can redistribute it and/or modify
98dffb485Schristos    it under the terms of the GNU General Public License as published by
108dffb485Schristos    the Free Software Foundation; either version 3 of the License, or
118dffb485Schristos    (at your option) any later version.
128dffb485Schristos 
138dffb485Schristos    This program is distributed in the hope that it will be useful,
148dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
158dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
168dffb485Schristos    GNU General Public License for more details.
178dffb485Schristos 
188dffb485Schristos    You should have received a copy of the GNU General Public License
198dffb485Schristos    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
208dffb485Schristos 
214b169a6bSchristos /* This must come before any other includes.  */
224b169a6bSchristos #include "defs.h"
234b169a6bSchristos 
248dffb485Schristos #include <stdbool.h>
258dffb485Schristos #include <stdint.h>
268dffb485Schristos #include <stddef.h>
278dffb485Schristos #include "bfd.h"
284b169a6bSchristos #include "sim/callback.h"
298dffb485Schristos #include "libiberty.h"
304b169a6bSchristos #include "sim/sim.h"
318dffb485Schristos #include "sim-main.h"
328dffb485Schristos #include "sim-assert.h"
338dffb485Schristos #include "sim-options.h"
344b169a6bSchristos #include "sim-signal.h"
358dffb485Schristos #include "sim-syscall.h"
368dffb485Schristos #include "pru.h"
378dffb485Schristos 
388dffb485Schristos /* DMEM zero address is perfectly valid.  But if CRT leaves the first word
398dffb485Schristos    alone, we can use it as a trap to catch NULL pointer access.  */
408dffb485Schristos static bfd_boolean abort_on_dmem_zero_access;
418dffb485Schristos 
428dffb485Schristos enum {
438dffb485Schristos   OPTION_ERROR_NULL_DEREF = OPTION_START,
448dffb485Schristos };
458dffb485Schristos 
468dffb485Schristos /* Extract (from PRU endianess) and return an integer in HOST's endianness.  */
478dffb485Schristos static uint32_t
484b169a6bSchristos pru_extract_unsigned_integer (const uint8_t *addr, size_t len)
498dffb485Schristos {
508dffb485Schristos   uint32_t retval;
514b169a6bSchristos   const uint8_t *p;
524b169a6bSchristos   const uint8_t *startaddr = addr;
534b169a6bSchristos   const uint8_t *endaddr = startaddr + len;
548dffb485Schristos 
558dffb485Schristos   /* Start at the most significant end of the integer, and work towards
568dffb485Schristos      the least significant.  */
578dffb485Schristos   retval = 0;
588dffb485Schristos 
598dffb485Schristos   for (p = endaddr; p > startaddr;)
608dffb485Schristos     retval = (retval << 8) | * -- p;
618dffb485Schristos   return retval;
628dffb485Schristos }
638dffb485Schristos 
648dffb485Schristos /* Store "val" (which is in HOST's endianess) into "addr"
658dffb485Schristos    (using PRU's endianness).  */
668dffb485Schristos static void
678dffb485Schristos pru_store_unsigned_integer (uint8_t *addr, size_t len, uint32_t val)
688dffb485Schristos {
698dffb485Schristos   uint8_t *p;
708dffb485Schristos   uint8_t *startaddr = (uint8_t *)addr;
718dffb485Schristos   uint8_t *endaddr = startaddr + len;
728dffb485Schristos 
738dffb485Schristos   for (p = startaddr; p < endaddr;)
748dffb485Schristos     {
758dffb485Schristos       *p++ = val & 0xff;
768dffb485Schristos       val >>= 8;
778dffb485Schristos     }
788dffb485Schristos }
798dffb485Schristos 
808dffb485Schristos /* Extract a field value from CPU register using the given REGSEL selector.
818dffb485Schristos 
828dffb485Schristos    Byte number maps directly to first values of RSEL, so we can
838dffb485Schristos    safely use "regsel" as a register byte number (0..3).  */
848dffb485Schristos static inline uint32_t
858dffb485Schristos extract_regval (uint32_t val, uint32_t regsel)
868dffb485Schristos {
878dffb485Schristos   ASSERT (RSEL_7_0 == 0);
888dffb485Schristos   ASSERT (RSEL_15_8 == 1);
898dffb485Schristos   ASSERT (RSEL_23_16 == 2);
908dffb485Schristos   ASSERT (RSEL_31_24 == 3);
918dffb485Schristos 
928dffb485Schristos   switch (regsel)
938dffb485Schristos     {
948dffb485Schristos     case RSEL_7_0:    return (val >> 0) & 0xff;
958dffb485Schristos     case RSEL_15_8:   return (val >> 8) & 0xff;
968dffb485Schristos     case RSEL_23_16:  return (val >> 16) & 0xff;
978dffb485Schristos     case RSEL_31_24:  return (val >> 24) & 0xff;
988dffb485Schristos     case RSEL_15_0:   return (val >> 0) & 0xffff;
998dffb485Schristos     case RSEL_23_8:   return (val >> 8) & 0xffff;
1008dffb485Schristos     case RSEL_31_16:  return (val >> 16) & 0xffff;
1018dffb485Schristos     case RSEL_31_0:   return val;
1028dffb485Schristos     default:	      sim_io_error (NULL, "invalid regsel");
1038dffb485Schristos     }
1048dffb485Schristos }
1058dffb485Schristos 
1068dffb485Schristos /* Write a value into CPU subregister pointed by reg and regsel.  */
1078dffb485Schristos static inline void
1088dffb485Schristos write_regval (uint32_t val, uint32_t *reg, uint32_t regsel)
1098dffb485Schristos {
1108dffb485Schristos   uint32_t mask, sh;
1118dffb485Schristos 
1128dffb485Schristos   switch (regsel)
1138dffb485Schristos     {
1148dffb485Schristos     case RSEL_7_0:    mask = (0xffu << 0); sh = 0; break;
1158dffb485Schristos     case RSEL_15_8:   mask = (0xffu << 8); sh = 8; break;
1168dffb485Schristos     case RSEL_23_16:  mask = (0xffu << 16); sh = 16; break;
1178dffb485Schristos     case RSEL_31_24:  mask = (0xffu << 24); sh = 24; break;
1188dffb485Schristos     case RSEL_15_0:   mask = (0xffffu << 0); sh = 0; break;
1198dffb485Schristos     case RSEL_23_8:   mask = (0xffffu << 8); sh = 8; break;
1208dffb485Schristos     case RSEL_31_16:  mask = (0xffffu << 16); sh = 16; break;
1218dffb485Schristos     case RSEL_31_0:   mask = 0xffffffffu; sh = 0; break;
1228dffb485Schristos     default:	      sim_io_error (NULL, "invalid regsel");
1238dffb485Schristos     }
1248dffb485Schristos 
1258dffb485Schristos   *reg = (*reg & ~mask) | ((val << sh) & mask);
1268dffb485Schristos }
1278dffb485Schristos 
1288dffb485Schristos /* Convert the given IMEM word address to a regular byte address used by the
1298dffb485Schristos    GNU ELF container.  */
1308dffb485Schristos static uint32_t
1318dffb485Schristos imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
1328dffb485Schristos {
133*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
134*1f4e7eb9Schristos 
1358dffb485Schristos   return (((uint32_t) wa << 2) & IMEM_ADDR_MASK) | PC_ADDR_SPACE_MARKER;
1368dffb485Schristos }
1378dffb485Schristos 
1388dffb485Schristos /* Convert the given ELF text byte address to IMEM word address.  */
1398dffb485Schristos static uint16_t
1408dffb485Schristos imem_byteaddr_to_wordaddr (SIM_CPU *cpu, uint32_t ba)
1418dffb485Schristos {
1428dffb485Schristos   return (ba >> 2) & 0xffff;
1438dffb485Schristos }
1448dffb485Schristos 
1458dffb485Schristos 
1468dffb485Schristos /* Store "nbytes" into DMEM "addr" from CPU register file, starting with
1478dffb485Schristos    register "regn", and byte "regb" within it.  */
1488dffb485Schristos static inline void
1498dffb485Schristos pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
1508dffb485Schristos 	      int regn, int regb)
1518dffb485Schristos {
152*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
1538dffb485Schristos   /* GDB assumes unconditional access to all memories, so enable additional
1548dffb485Schristos      checks only in standalone mode.  */
1558dffb485Schristos   bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
1568dffb485Schristos 
1578dffb485Schristos   if (abort_on_dmem_zero_access && addr < 4)
1588dffb485Schristos     {
1598dffb485Schristos       sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
1608dffb485Schristos 		       nbytes, addr, write_transfer,
1618dffb485Schristos 		       sim_core_unmapped_signal);
1628dffb485Schristos     }
1638dffb485Schristos   else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
1648dffb485Schristos 			  || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
1658dffb485Schristos     {
1668dffb485Schristos       sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
1678dffb485Schristos 		       nbytes, addr, write_transfer,
1688dffb485Schristos 		       sim_core_unmapped_signal);
1698dffb485Schristos     }
1708dffb485Schristos   else if ((regn * 4 + regb + nbytes) > (32 * 4))
1718dffb485Schristos     {
1728dffb485Schristos       sim_io_eprintf (CPU_STATE (cpu),
1738dffb485Schristos 		      "SBBO/SBCO with invalid store data length\n");
1748dffb485Schristos       RAISE_SIGILL (CPU_STATE (cpu));
1758dffb485Schristos     }
1768dffb485Schristos   else
1778dffb485Schristos     {
1788dffb485Schristos       TRACE_MEMORY (cpu, "write of %d bytes to %08x", nbytes, addr);
1798dffb485Schristos       while (nbytes--)
1808dffb485Schristos 	{
1818dffb485Schristos 	  sim_core_write_1 (cpu,
1828dffb485Schristos 			    PC_byteaddr,
1838dffb485Schristos 			    write_map,
1848dffb485Schristos 			    addr++,
1858dffb485Schristos 			    extract_regval (CPU.regs[regn], regb));
1868dffb485Schristos 
1878dffb485Schristos 	  if (++regb >= 4)
1888dffb485Schristos 	    {
1898dffb485Schristos 	      regb = 0;
1908dffb485Schristos 	      regn++;
1918dffb485Schristos 	    }
1928dffb485Schristos 	}
1938dffb485Schristos     }
1948dffb485Schristos }
1958dffb485Schristos 
1968dffb485Schristos /* Load "nbytes" from DMEM "addr" into CPU register file, starting with
1978dffb485Schristos    register "regn", and byte "regb" within it.  */
1988dffb485Schristos static inline void
1998dffb485Schristos pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
2008dffb485Schristos 	      int regn, int regb)
2018dffb485Schristos {
202*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
2038dffb485Schristos   /* GDB assumes unconditional access to all memories, so enable additional
2048dffb485Schristos      checks only in standalone mode.  */
2058dffb485Schristos   bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
2068dffb485Schristos 
2078dffb485Schristos   if (abort_on_dmem_zero_access && addr < 4)
2088dffb485Schristos     {
2098dffb485Schristos       sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
2108dffb485Schristos 		       nbytes, addr, read_transfer,
2118dffb485Schristos 		       sim_core_unmapped_signal);
2128dffb485Schristos     }
2138dffb485Schristos   else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
2148dffb485Schristos 			  || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
2158dffb485Schristos     {
2168dffb485Schristos       /* This check is necessary because our IMEM "address space"
2178dffb485Schristos 	 is not really accessible, yet we have mapped it as a generic
2188dffb485Schristos 	 memory space.  */
2198dffb485Schristos       sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
2208dffb485Schristos 		       nbytes, addr, read_transfer,
2218dffb485Schristos 		       sim_core_unmapped_signal);
2228dffb485Schristos     }
2238dffb485Schristos   else if ((regn * 4 + regb + nbytes) > (32 * 4))
2248dffb485Schristos     {
2258dffb485Schristos       sim_io_eprintf (CPU_STATE (cpu),
2268dffb485Schristos 		      "LBBO/LBCO with invalid load data length\n");
2278dffb485Schristos       RAISE_SIGILL (CPU_STATE (cpu));
2288dffb485Schristos     }
2298dffb485Schristos   else
2308dffb485Schristos     {
2318dffb485Schristos       unsigned int b;
2328dffb485Schristos       TRACE_MEMORY (cpu, "read of %d bytes from %08x", nbytes, addr);
2338dffb485Schristos       while (nbytes--)
2348dffb485Schristos 	{
2358dffb485Schristos 	  b = sim_core_read_1 (cpu, PC_byteaddr, read_map, addr++);
2368dffb485Schristos 
2378dffb485Schristos 	  /* Reuse the fact the Register Byte Number maps directly to RSEL.  */
2388dffb485Schristos 	  ASSERT (RSEL_7_0 == 0);
2398dffb485Schristos 	  write_regval (b, &CPU.regs[regn], regb);
2408dffb485Schristos 
2418dffb485Schristos 	  if (++regb >= 4)
2428dffb485Schristos 	    {
2438dffb485Schristos 	      regb = 0;
2448dffb485Schristos 	      regn++;
2458dffb485Schristos 	    }
2468dffb485Schristos 	}
2478dffb485Schristos     }
2488dffb485Schristos }
2498dffb485Schristos 
2508dffb485Schristos /* Set reset values of general-purpose registers.  */
2518dffb485Schristos static void
2528dffb485Schristos set_initial_gprs (SIM_CPU *cpu)
2538dffb485Schristos {
254*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
2558dffb485Schristos   int i;
2568dffb485Schristos 
2578dffb485Schristos   /* Set up machine just out of reset.  */
2588dffb485Schristos   CPU_PC_SET (cpu, 0);
2598dffb485Schristos   PC_ADDR_SPACE_MARKER = IMEM_ADDR_DEFAULT; /* from default linker script? */
2608dffb485Schristos 
2618dffb485Schristos   /* Clean out the GPRs.  */
2628dffb485Schristos   for (i = 0; i < ARRAY_SIZE (CPU.regs); i++)
2638dffb485Schristos     CPU.regs[i] = 0;
2648dffb485Schristos   for (i = 0; i < ARRAY_SIZE (CPU.macregs); i++)
2658dffb485Schristos     CPU.macregs[i] = 0;
2668dffb485Schristos 
2678dffb485Schristos   CPU.loop.looptop = CPU.loop.loopend = 0;
2688dffb485Schristos   CPU.loop.loop_in_progress = 0;
2698dffb485Schristos   CPU.loop.loop_counter = 0;
2708dffb485Schristos 
2718dffb485Schristos   CPU.carry = 0;
2728dffb485Schristos   CPU.insts = 0;
2738dffb485Schristos   CPU.cycles = 0;
2748dffb485Schristos 
2758dffb485Schristos   /* AM335x should provide sane defaults.  */
2768dffb485Schristos   CPU.ctable[0] = 0x00020000;
2778dffb485Schristos   CPU.ctable[1] = 0x48040000;
2788dffb485Schristos   CPU.ctable[2] = 0x4802a000;
2798dffb485Schristos   CPU.ctable[3] = 0x00030000;
2808dffb485Schristos   CPU.ctable[4] = 0x00026000;
2818dffb485Schristos   CPU.ctable[5] = 0x48060000;
2828dffb485Schristos   CPU.ctable[6] = 0x48030000;
2838dffb485Schristos   CPU.ctable[7] = 0x00028000;
2848dffb485Schristos   CPU.ctable[8] = 0x46000000;
2858dffb485Schristos   CPU.ctable[9] = 0x4a100000;
2868dffb485Schristos   CPU.ctable[10] = 0x48318000;
2878dffb485Schristos   CPU.ctable[11] = 0x48022000;
2888dffb485Schristos   CPU.ctable[12] = 0x48024000;
2898dffb485Schristos   CPU.ctable[13] = 0x48310000;
2908dffb485Schristos   CPU.ctable[14] = 0x481cc000;
2918dffb485Schristos   CPU.ctable[15] = 0x481d0000;
2928dffb485Schristos   CPU.ctable[16] = 0x481a0000;
2938dffb485Schristos   CPU.ctable[17] = 0x4819c000;
2948dffb485Schristos   CPU.ctable[18] = 0x48300000;
2958dffb485Schristos   CPU.ctable[19] = 0x48302000;
2968dffb485Schristos   CPU.ctable[20] = 0x48304000;
2978dffb485Schristos   CPU.ctable[21] = 0x00032400;
2988dffb485Schristos   CPU.ctable[22] = 0x480c8000;
2998dffb485Schristos   CPU.ctable[23] = 0x480ca000;
3008dffb485Schristos   CPU.ctable[24] = 0x00000000;
3018dffb485Schristos   CPU.ctable[25] = 0x00002000;
3028dffb485Schristos   CPU.ctable[26] = 0x0002e000;
3038dffb485Schristos   CPU.ctable[27] = 0x00032000;
3048dffb485Schristos   CPU.ctable[28] = 0x00000000;
3058dffb485Schristos   CPU.ctable[29] = 0x49000000;
3068dffb485Schristos   CPU.ctable[30] = 0x40000000;
3078dffb485Schristos   CPU.ctable[31] = 0x80000000;
3088dffb485Schristos }
3098dffb485Schristos 
3108dffb485Schristos /* Map regsel selector to subregister field width.  */
3118dffb485Schristos static inline unsigned int
3128dffb485Schristos regsel_width (uint32_t regsel)
3138dffb485Schristos {
3148dffb485Schristos   switch (regsel)
3158dffb485Schristos     {
3168dffb485Schristos     case RSEL_7_0:    return 8;
3178dffb485Schristos     case RSEL_15_8:   return 8;
3188dffb485Schristos     case RSEL_23_16:  return 8;
3198dffb485Schristos     case RSEL_31_24:  return 8;
3208dffb485Schristos     case RSEL_15_0:   return 16;
3218dffb485Schristos     case RSEL_23_8:   return 16;
3228dffb485Schristos     case RSEL_31_16:  return 16;
3238dffb485Schristos     case RSEL_31_0:   return 32;
3248dffb485Schristos     default:	      sim_io_error (NULL, "invalid regsel");
3258dffb485Schristos     }
3268dffb485Schristos }
3278dffb485Schristos 
3288dffb485Schristos /* Handle XIN instruction addressing the MAC peripheral.  */
3298dffb485Schristos static void
3308dffb485Schristos pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
3318dffb485Schristos 		 unsigned int rdb, unsigned int length)
3328dffb485Schristos {
333*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
334*1f4e7eb9Schristos 
3358dffb485Schristos   if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
3368dffb485Schristos     sim_io_error (sd, "XIN MAC: invalid transfer regn=%u.%u, length=%u\n",
3378dffb485Schristos 		  rd_regn, rdb, length);
3388dffb485Schristos 
3398dffb485Schristos   /* Copy from MAC to PRU regs.  Ranges have been validated above.  */
3408dffb485Schristos   while (length--)
3418dffb485Schristos     {
3428dffb485Schristos       write_regval (CPU.macregs[rd_regn - 25] >> (rdb * 8),
3438dffb485Schristos 		    &CPU.regs[rd_regn],
3448dffb485Schristos 		    rdb);
3458dffb485Schristos       if (++rdb == 4)
3468dffb485Schristos 	{
3478dffb485Schristos 	  rdb = 0;
3488dffb485Schristos 	  rd_regn++;
3498dffb485Schristos 	}
3508dffb485Schristos     }
3518dffb485Schristos }
3528dffb485Schristos 
3538dffb485Schristos /* Handle XIN instruction.  */
3548dffb485Schristos static void
3558dffb485Schristos pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
3568dffb485Schristos 	     unsigned int rd_regn, unsigned int rdb, unsigned int length)
3578dffb485Schristos {
358*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
359*1f4e7eb9Schristos 
3608dffb485Schristos   if (wba == 0)
3618dffb485Schristos     {
3628dffb485Schristos       pru_sim_xin_mac (sd, cpu, rd_regn, rdb, length);
3638dffb485Schristos     }
3648dffb485Schristos   else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
3658dffb485Schristos 	   || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
3668dffb485Schristos     {
3678dffb485Schristos       while (length--)
3688dffb485Schristos 	{
3698dffb485Schristos 	  unsigned int val;
3708dffb485Schristos 
3718dffb485Schristos 	  val = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
3728dffb485Schristos 	  write_regval (val, &CPU.regs[rd_regn], rdb);
3738dffb485Schristos 	  if (++rdb == 4)
3748dffb485Schristos 	    {
3758dffb485Schristos 	      rdb = 0;
3768dffb485Schristos 	      rd_regn++;
3778dffb485Schristos 	    }
3788dffb485Schristos 	}
3798dffb485Schristos     }
3808dffb485Schristos   else if (wba == 254 || wba == 255)
3818dffb485Schristos     {
3828dffb485Schristos       /* FILL/ZERO pseudos implemented via XIN.  */
3838dffb485Schristos       unsigned int fillbyte = (wba == 254) ? 0xff : 0x00;
3848dffb485Schristos       while (length--)
3858dffb485Schristos 	{
3868dffb485Schristos 	  write_regval (fillbyte, &CPU.regs[rd_regn], rdb);
3878dffb485Schristos 	  if (++rdb == 4)
3888dffb485Schristos 	    {
3898dffb485Schristos 	      rdb = 0;
3908dffb485Schristos 	      rd_regn++;
3918dffb485Schristos 	    }
3928dffb485Schristos 	}
3938dffb485Schristos     }
3948dffb485Schristos   else
3958dffb485Schristos     {
3968dffb485Schristos       sim_io_error (sd, "XIN: XFR device %d not supported.\n", wba);
3978dffb485Schristos     }
3988dffb485Schristos }
3998dffb485Schristos 
4008dffb485Schristos /* Handle XOUT instruction addressing the MAC peripheral.  */
4018dffb485Schristos static void
4028dffb485Schristos pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
4038dffb485Schristos 		  unsigned int rdb, unsigned int length)
4048dffb485Schristos {
405*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
4068dffb485Schristos   const int modereg_accessed = (rd_regn == 25);
4078dffb485Schristos 
4088dffb485Schristos   /* Multiple Accumulate.  */
4098dffb485Schristos   if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
4108dffb485Schristos     sim_io_error (sd, "XOUT MAC: invalid transfer regn=%u.%u, length=%u\n",
4118dffb485Schristos 		  rd_regn, rdb, length);
4128dffb485Schristos 
4138dffb485Schristos   /* Copy from PRU to MAC regs.  Ranges have been validated above.  */
4148dffb485Schristos   while (length--)
4158dffb485Schristos     {
4168dffb485Schristos       write_regval (CPU.regs[rd_regn] >> (rdb * 8),
4178dffb485Schristos 		    &CPU.macregs[rd_regn - 25],
4188dffb485Schristos 		    rdb);
4198dffb485Schristos       if (++rdb == 4)
4208dffb485Schristos 	{
4218dffb485Schristos 	  rdb = 0;
4228dffb485Schristos 	  rd_regn++;
4238dffb485Schristos 	}
4248dffb485Schristos     }
4258dffb485Schristos 
4268dffb485Schristos   if (modereg_accessed
4278dffb485Schristos       && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK))
4288dffb485Schristos     {
4298dffb485Schristos       /* MUL/MAC operands are sampled every XOUT in multiply and
4308dffb485Schristos 	 accumulate mode.  */
4318dffb485Schristos       uint64_t prod, oldsum, sum;
4328dffb485Schristos       CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
4338dffb485Schristos       CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
4348dffb485Schristos 
4358dffb485Schristos       prod = CPU.macregs[PRU_MACREG_OP_0];
4368dffb485Schristos       prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
4378dffb485Schristos 
4388dffb485Schristos       oldsum = CPU.macregs[PRU_MACREG_ACC_L];
4398dffb485Schristos       oldsum += (uint64_t)CPU.macregs[PRU_MACREG_ACC_H] << 32;
4408dffb485Schristos       sum = oldsum + prod;
4418dffb485Schristos 
4428dffb485Schristos       CPU.macregs[PRU_MACREG_PROD_L] = sum & 0xfffffffful;
4438dffb485Schristos       CPU.macregs[PRU_MACREG_PROD_H] = sum >> 32;
4448dffb485Schristos       CPU.macregs[PRU_MACREG_ACC_L] = CPU.macregs[PRU_MACREG_PROD_L];
4458dffb485Schristos       CPU.macregs[PRU_MACREG_ACC_H] = CPU.macregs[PRU_MACREG_PROD_H];
4468dffb485Schristos 
4478dffb485Schristos       if (oldsum > sum)
4488dffb485Schristos 	CPU.macregs[PRU_MACREG_MODE] |= MAC_R25_ACC_CARRY_MASK;
4498dffb485Schristos     }
4508dffb485Schristos   if (modereg_accessed
4518dffb485Schristos       && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_ACC_CARRY_MASK))
4528dffb485Schristos     {
4538dffb485Schristos       /* store 1 to clear.  */
4548dffb485Schristos       CPU.macregs[PRU_MACREG_MODE] &= ~MAC_R25_ACC_CARRY_MASK;
4558dffb485Schristos       CPU.macregs[PRU_MACREG_ACC_L] = 0;
4568dffb485Schristos       CPU.macregs[PRU_MACREG_ACC_H] = 0;
4578dffb485Schristos     }
4588dffb485Schristos 
4598dffb485Schristos }
4608dffb485Schristos 
4618dffb485Schristos /* Handle XOUT instruction.  */
4628dffb485Schristos static void
4638dffb485Schristos pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
4648dffb485Schristos 	      unsigned int rd_regn, unsigned int rdb, unsigned int length)
4658dffb485Schristos {
466*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
467*1f4e7eb9Schristos 
4688dffb485Schristos   if (wba == 0)
4698dffb485Schristos     {
4708dffb485Schristos       pru_sim_xout_mac (sd, cpu, rd_regn, rdb, length);
4718dffb485Schristos     }
4728dffb485Schristos   else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
4738dffb485Schristos 	   || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
4748dffb485Schristos     {
4758dffb485Schristos       while (length--)
4768dffb485Schristos 	{
4778dffb485Schristos 	  unsigned int val;
4788dffb485Schristos 
4798dffb485Schristos 	  val = extract_regval (CPU.regs[rd_regn], rdb);
4808dffb485Schristos 	  write_regval (val, &CPU.scratchpads[wba][rd_regn], rdb);
4818dffb485Schristos 	  if (++rdb == 4)
4828dffb485Schristos 	    {
4838dffb485Schristos 	      rdb = 0;
4848dffb485Schristos 	      rd_regn++;
4858dffb485Schristos 	    }
4868dffb485Schristos 	}
4878dffb485Schristos     }
4888dffb485Schristos   else
4898dffb485Schristos     sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
4908dffb485Schristos }
4918dffb485Schristos 
4928dffb485Schristos /* Handle XCHG instruction.  */
4938dffb485Schristos static void
4948dffb485Schristos pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
4958dffb485Schristos 	      unsigned int rd_regn, unsigned int rdb, unsigned int length)
4968dffb485Schristos {
497*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
498*1f4e7eb9Schristos 
4998dffb485Schristos   if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
5008dffb485Schristos 	   || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
5018dffb485Schristos     {
5028dffb485Schristos       while (length--)
5038dffb485Schristos 	{
5048dffb485Schristos 	  unsigned int valr, vals;
5058dffb485Schristos 
5068dffb485Schristos 	  valr = extract_regval (CPU.regs[rd_regn], rdb);
5078dffb485Schristos 	  vals = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
5088dffb485Schristos 	  write_regval (valr, &CPU.scratchpads[wba][rd_regn], rdb);
5098dffb485Schristos 	  write_regval (vals, &CPU.regs[rd_regn], rdb);
5108dffb485Schristos 	  if (++rdb == 4)
5118dffb485Schristos 	    {
5128dffb485Schristos 	      rdb = 0;
5138dffb485Schristos 	      rd_regn++;
5148dffb485Schristos 	    }
5158dffb485Schristos 	}
5168dffb485Schristos     }
5178dffb485Schristos   else
5188dffb485Schristos     sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
5198dffb485Schristos }
5208dffb485Schristos 
5218dffb485Schristos /* Handle syscall simulation.  Its ABI is specific to the GNU simulator.  */
5228dffb485Schristos static void
5238dffb485Schristos pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
5248dffb485Schristos {
525*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
5268dffb485Schristos   /* If someday TI confirms that the "reserved" HALT opcode fields
5278dffb485Schristos      can be used for extra arguments, then maybe we can embed
5288dffb485Schristos      the syscall number there.  Until then, let's use R1.  */
5298dffb485Schristos   const uint32_t syscall_num = CPU.regs[1];
5308dffb485Schristos   long ret;
5318dffb485Schristos 
5328dffb485Schristos   ret = sim_syscall (cpu, syscall_num,
5338dffb485Schristos 		     CPU.regs[14], CPU.regs[15],
5348dffb485Schristos 		     CPU.regs[16], CPU.regs[17]);
5358dffb485Schristos   CPU.regs[14] = ret;
5368dffb485Schristos }
5378dffb485Schristos 
5388dffb485Schristos /* Simulate one instruction.  */
5398dffb485Schristos static void
5408dffb485Schristos sim_step_once (SIM_DESC sd)
5418dffb485Schristos {
5428dffb485Schristos   SIM_CPU *cpu = STATE_CPU (sd, 0);
543*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
5448dffb485Schristos   const struct pru_opcode *op;
5458dffb485Schristos   uint32_t inst;
5468dffb485Schristos   uint32_t _RDVAL, OP2;	/* intermediate values.  */
5478dffb485Schristos   int rd_is_modified = 0;	/* RD modified and must be stored back.  */
5488dffb485Schristos 
5498dffb485Schristos   /* Fetch the initial instruction that we'll decode.  */
5508dffb485Schristos   inst = sim_core_read_4 (cpu, PC_byteaddr, exec_map, PC_byteaddr);
5518dffb485Schristos   TRACE_MEMORY (cpu, "read of insn 0x%08x from %08x", inst, PC_byteaddr);
5528dffb485Schristos 
5538dffb485Schristos   op = pru_find_opcode (inst);
5548dffb485Schristos 
5558dffb485Schristos   if (!op)
5568dffb485Schristos     {
5578dffb485Schristos       sim_io_eprintf (sd, "Unknown instruction 0x%04x\n", inst);
5588dffb485Schristos       RAISE_SIGILL (sd);
5598dffb485Schristos     }
5608dffb485Schristos   else
5618dffb485Schristos     {
5628dffb485Schristos       TRACE_DISASM (cpu, PC_byteaddr);
5638dffb485Schristos 
5648dffb485Schristos       /* In multiply-only mode, R28/R29 operands are sampled on every clock
5658dffb485Schristos 	 cycle.  */
5668dffb485Schristos       if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
5678dffb485Schristos 	{
5688dffb485Schristos 	  CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
5698dffb485Schristos 	  CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
5708dffb485Schristos 	}
5718dffb485Schristos 
5728dffb485Schristos       switch (op->type)
5738dffb485Schristos 	{
5748dffb485Schristos /* Helper macro to improve clarity of pru.isa.  The empty while is a
5758dffb485Schristos    guard against using RD as a left-hand side value.  */
5768dffb485Schristos #define RD  do { } while (0); rd_is_modified = 1; _RDVAL
5778dffb485Schristos #define INSTRUCTION(NAME, ACTION)		\
5788dffb485Schristos 	case prui_ ## NAME:			\
5798dffb485Schristos 		ACTION;				\
5808dffb485Schristos 	  break;
5818dffb485Schristos #include "pru.isa"
5828dffb485Schristos #undef INSTRUCTION
5838dffb485Schristos #undef RD
5848dffb485Schristos 
5858dffb485Schristos 	default:
5868dffb485Schristos 	  RAISE_SIGILL (sd);
5878dffb485Schristos 	}
5888dffb485Schristos 
5898dffb485Schristos       if (rd_is_modified)
5908dffb485Schristos 	write_regval (_RDVAL, &CPU.regs[RD_REGN], RDSEL);
5918dffb485Schristos 
5928dffb485Schristos       /* Don't treat r30 and r31 as regular registers, they are I/O!  */
5938dffb485Schristos       CPU.regs[30] = 0;
5948dffb485Schristos       CPU.regs[31] = 0;
5958dffb485Schristos 
5968dffb485Schristos       /* Handle PC match of loop end.  */
5978dffb485Schristos       if (LOOP_IN_PROGRESS && (PC == LOOPEND))
5988dffb485Schristos 	{
5998dffb485Schristos 	  SIM_ASSERT (LOOPCNT > 0);
6008dffb485Schristos 	  if (--LOOPCNT == 0)
6018dffb485Schristos 	    LOOP_IN_PROGRESS = 0;
6028dffb485Schristos 	  else
6038dffb485Schristos 	    PC = LOOPTOP;
6048dffb485Schristos 	}
6058dffb485Schristos 
6068dffb485Schristos       /* In multiply-only mode, MAC does multiplication every cycle.  */
6078dffb485Schristos       if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
6088dffb485Schristos 	{
6098dffb485Schristos 	  uint64_t prod;
6108dffb485Schristos 	  prod = CPU.macregs[PRU_MACREG_OP_0];
6118dffb485Schristos 	  prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
6128dffb485Schristos 	  CPU.macregs[PRU_MACREG_PROD_L] = prod & 0xfffffffful;
6138dffb485Schristos 	  CPU.macregs[PRU_MACREG_PROD_H] = prod >> 32;
6148dffb485Schristos 
6158dffb485Schristos 	  /* Clear the MAC accumulator when in normal mode.  */
6168dffb485Schristos 	  CPU.macregs[PRU_MACREG_ACC_L] = 0;
6178dffb485Schristos 	  CPU.macregs[PRU_MACREG_ACC_H] = 0;
6188dffb485Schristos 	}
6198dffb485Schristos 
6208dffb485Schristos       /* Update cycle counts.  */
6218dffb485Schristos       CPU.insts += 1;		  /* One instruction completed ...  */
6228dffb485Schristos       CPU.cycles += 1;		  /* ... and it takes a single cycle.  */
6238dffb485Schristos 
6248dffb485Schristos       /* Account for memory access latency with a reasonable estimate.
6258dffb485Schristos 	 No distinction is currently made between SRAM, DRAM and generic
6268dffb485Schristos 	 L3 slaves.  */
6278dffb485Schristos       if (op->type == prui_lbbo || op->type == prui_sbbo
6288dffb485Schristos 	  || op->type == prui_lbco || op->type == prui_sbco)
6298dffb485Schristos 	CPU.cycles += 2;
6308dffb485Schristos 
6318dffb485Schristos     }
6328dffb485Schristos }
6338dffb485Schristos 
6348dffb485Schristos /* Implement standard sim_engine_run function.  */
6358dffb485Schristos void
6368dffb485Schristos sim_engine_run (SIM_DESC sd,
6378dffb485Schristos 		int next_cpu_nr, /* ignore  */
6388dffb485Schristos 		int nr_cpus, /* ignore  */
6398dffb485Schristos 		int siggnal) /* ignore  */
6408dffb485Schristos {
6418dffb485Schristos   while (1)
6428dffb485Schristos     {
6438dffb485Schristos       sim_step_once (sd);
6448dffb485Schristos       if (sim_events_tick (sd))
6458dffb485Schristos 	sim_events_process (sd);
6468dffb485Schristos     }
6478dffb485Schristos }
6488dffb485Schristos 
6498dffb485Schristos 
6508dffb485Schristos /* Implement callback for standard CPU_PC_FETCH routine.  */
6518dffb485Schristos static sim_cia
6528dffb485Schristos pru_pc_get (sim_cpu *cpu)
6538dffb485Schristos {
654*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
655*1f4e7eb9Schristos 
6568dffb485Schristos   /* Present PC as byte address.  */
657*1f4e7eb9Schristos   return imem_wordaddr_to_byteaddr (cpu, pru_cpu->pc);
6588dffb485Schristos }
6598dffb485Schristos 
6608dffb485Schristos /* Implement callback for standard CPU_PC_STORE routine.  */
6618dffb485Schristos static void
6628dffb485Schristos pru_pc_set (sim_cpu *cpu, sim_cia pc)
6638dffb485Schristos {
664*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
665*1f4e7eb9Schristos 
6668dffb485Schristos   /* PC given as byte address.  */
667*1f4e7eb9Schristos   pru_cpu->pc = imem_byteaddr_to_wordaddr (cpu, pc);
6688dffb485Schristos }
6698dffb485Schristos 
6708dffb485Schristos 
6718dffb485Schristos /* Implement callback for standard CPU_REG_STORE routine.  */
6728dffb485Schristos static int
6734b169a6bSchristos pru_store_register (SIM_CPU *cpu, int rn, const void *memory, int length)
6748dffb485Schristos {
675*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
676*1f4e7eb9Schristos 
6778dffb485Schristos   if (rn < NUM_REGS && rn >= 0)
6788dffb485Schristos     {
6798dffb485Schristos       if (length == 4)
6808dffb485Schristos 	{
6818dffb485Schristos 	  /* Misalignment safe.  */
6828dffb485Schristos 	  long ival = pru_extract_unsigned_integer (memory, 4);
6838dffb485Schristos 	  if (rn < 32)
6848dffb485Schristos 	    CPU.regs[rn] = ival;
6858dffb485Schristos 	  else
6868dffb485Schristos 	    pru_pc_set (cpu, ival);
6878dffb485Schristos 	  return 4;
6888dffb485Schristos 	}
6898dffb485Schristos       else
6908dffb485Schristos 	return 0;
6918dffb485Schristos     }
6928dffb485Schristos   else
6938dffb485Schristos     return 0;
6948dffb485Schristos }
6958dffb485Schristos 
6968dffb485Schristos /* Implement callback for standard CPU_REG_FETCH routine.  */
6978dffb485Schristos static int
6984b169a6bSchristos pru_fetch_register (SIM_CPU *cpu, int rn, void *memory, int length)
6998dffb485Schristos {
700*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
7018dffb485Schristos   long ival;
7028dffb485Schristos 
7038dffb485Schristos   if (rn < NUM_REGS && rn >= 0)
7048dffb485Schristos     {
7058dffb485Schristos       if (length == 4)
7068dffb485Schristos 	{
7078dffb485Schristos 	  if (rn < 32)
7088dffb485Schristos 	    ival = CPU.regs[rn];
7098dffb485Schristos 	  else
7108dffb485Schristos 	    ival = pru_pc_get (cpu);
7118dffb485Schristos 
7128dffb485Schristos 	  /* Misalignment-safe.  */
7138dffb485Schristos 	  pru_store_unsigned_integer (memory, 4, ival);
7148dffb485Schristos 	  return 4;
7158dffb485Schristos 	}
7168dffb485Schristos       else
7178dffb485Schristos 	return 0;
7188dffb485Schristos     }
7198dffb485Schristos   else
7208dffb485Schristos     return 0;
7218dffb485Schristos }
7228dffb485Schristos 
7238dffb485Schristos static void
7248dffb485Schristos free_state (SIM_DESC sd)
7258dffb485Schristos {
7268dffb485Schristos   if (STATE_MODULES (sd) != NULL)
7278dffb485Schristos     sim_module_uninstall (sd);
7288dffb485Schristos   sim_cpu_free_all (sd);
7298dffb485Schristos   sim_state_free (sd);
7308dffb485Schristos }
7318dffb485Schristos 
7328dffb485Schristos /* Declare the PRU option handler.  */
7338dffb485Schristos static DECLARE_OPTION_HANDLER (pru_option_handler);
7348dffb485Schristos 
7358dffb485Schristos /* Implement the PRU option handler.  */
7368dffb485Schristos static SIM_RC
7378dffb485Schristos pru_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
7388dffb485Schristos 		    int is_command)
7398dffb485Schristos {
7408dffb485Schristos   switch (opt)
7418dffb485Schristos     {
7428dffb485Schristos     case OPTION_ERROR_NULL_DEREF:
7438dffb485Schristos       abort_on_dmem_zero_access = TRUE;
7448dffb485Schristos       return SIM_RC_OK;
7458dffb485Schristos 
7468dffb485Schristos     default:
7478dffb485Schristos       sim_io_eprintf (sd, "Unknown PRU option %d\n", opt);
7488dffb485Schristos       return SIM_RC_FAIL;
7498dffb485Schristos     }
7508dffb485Schristos }
7518dffb485Schristos 
7528dffb485Schristos /* List of PRU-specific options.  */
7538dffb485Schristos static const OPTION pru_options[] =
7548dffb485Schristos {
7558dffb485Schristos   { {"error-null-deref", no_argument, NULL, OPTION_ERROR_NULL_DEREF},
7568dffb485Schristos       '\0', NULL, "Trap any access to DMEM address zero",
7578dffb485Schristos       pru_option_handler, NULL },
7588dffb485Schristos 
7598dffb485Schristos   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
7608dffb485Schristos };
7618dffb485Schristos 
7628dffb485Schristos /* Implement standard sim_open function.  */
7638dffb485Schristos SIM_DESC
7648dffb485Schristos sim_open (SIM_OPEN_KIND kind, host_callback *cb,
7658dffb485Schristos 	  struct bfd *abfd, char * const *argv)
7668dffb485Schristos {
7678dffb485Schristos   int i;
7688dffb485Schristos   char c;
7698dffb485Schristos   SIM_DESC sd = sim_state_alloc (kind, cb);
7708dffb485Schristos   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
7718dffb485Schristos 
7724b169a6bSchristos   /* Set default options before parsing user options.  */
7734b169a6bSchristos   current_alignment = STRICT_ALIGNMENT;
7744b169a6bSchristos   current_target_byte_order = BFD_ENDIAN_LITTLE;
7754b169a6bSchristos 
7768dffb485Schristos   /* The cpu data is kept in a separately allocated chunk of memory.  */
777*1f4e7eb9Schristos   if (sim_cpu_alloc_all_extra (sd, 0, sizeof (struct pru_regset)) != SIM_RC_OK)
7788dffb485Schristos     {
7798dffb485Schristos       free_state (sd);
7808dffb485Schristos       return 0;
7818dffb485Schristos     }
7828dffb485Schristos 
7838dffb485Schristos   if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
7848dffb485Schristos     {
7858dffb485Schristos       free_state (sd);
7868dffb485Schristos       return 0;
7878dffb485Schristos     }
7888dffb485Schristos   sim_add_option_table (sd, NULL, pru_options);
7898dffb485Schristos 
7908dffb485Schristos   /* The parser will print an error message for us, so we silently return.  */
7918dffb485Schristos   if (sim_parse_args (sd, argv) != SIM_RC_OK)
7928dffb485Schristos     {
7938dffb485Schristos       free_state (sd);
7948dffb485Schristos       return 0;
7958dffb485Schristos     }
7968dffb485Schristos 
7978dffb485Schristos   /* Check for/establish a reference program image.  */
7984b169a6bSchristos   if (sim_analyze_program (sd, STATE_PROG_FILE (sd), abfd) != SIM_RC_OK)
7998dffb485Schristos     {
8008dffb485Schristos       free_state (sd);
8018dffb485Schristos       return 0;
8028dffb485Schristos     }
8038dffb485Schristos 
8048dffb485Schristos   /* Configure/verify the target byte order and other runtime
8058dffb485Schristos      configuration options.  */
8068dffb485Schristos   if (sim_config (sd) != SIM_RC_OK)
8078dffb485Schristos     {
8088dffb485Schristos       sim_module_uninstall (sd);
8098dffb485Schristos       return 0;
8108dffb485Schristos     }
8118dffb485Schristos 
8128dffb485Schristos   if (sim_post_argv_init (sd) != SIM_RC_OK)
8138dffb485Schristos     {
8148dffb485Schristos       /* Uninstall the modules to avoid memory leaks,
8158dffb485Schristos 	 file descriptor leaks, etc.  */
8168dffb485Schristos       sim_module_uninstall (sd);
8178dffb485Schristos       return 0;
8188dffb485Schristos     }
8198dffb485Schristos 
8208dffb485Schristos   /* CPU specific initialization.  */
8218dffb485Schristos   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
8228dffb485Schristos     {
8238dffb485Schristos       SIM_CPU *cpu = STATE_CPU (sd, i);
8248dffb485Schristos 
8258dffb485Schristos       CPU_REG_STORE (cpu) = pru_store_register;
8268dffb485Schristos       CPU_REG_FETCH (cpu) = pru_fetch_register;
8278dffb485Schristos       CPU_PC_FETCH (cpu) = pru_pc_get;
8288dffb485Schristos       CPU_PC_STORE (cpu) = pru_pc_set;
8298dffb485Schristos 
8308dffb485Schristos       set_initial_gprs (cpu);
8318dffb485Schristos     }
8328dffb485Schristos 
8338dffb485Schristos   /* Allocate external memory if none specified by user.
8348dffb485Schristos      Use address 4 here in case the user wanted address 0 unmapped.  */
8358dffb485Schristos   if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
8368dffb485Schristos     {
8378dffb485Schristos       sim_do_commandf (sd, "memory-region 0x%x,0x%x",
8388dffb485Schristos 		       0,
8398dffb485Schristos 		       DMEM_DEFAULT_SIZE);
8408dffb485Schristos     }
8418dffb485Schristos   if (sim_core_read_buffer (sd, NULL, read_map, &c, IMEM_ADDR_DEFAULT, 1) == 0)
8428dffb485Schristos     {
8438dffb485Schristos       sim_do_commandf (sd, "memory-region 0x%x,0x%x",
8448dffb485Schristos 		       IMEM_ADDR_DEFAULT,
8458dffb485Schristos 		       IMEM_DEFAULT_SIZE);
8468dffb485Schristos     }
8478dffb485Schristos 
8488dffb485Schristos   return sd;
8498dffb485Schristos }
8508dffb485Schristos 
8518dffb485Schristos /* Implement standard sim_create_inferior function.  */
8528dffb485Schristos SIM_RC
8538dffb485Schristos sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
8548dffb485Schristos 		     char * const *argv, char * const *env)
8558dffb485Schristos {
8568dffb485Schristos   SIM_CPU *cpu = STATE_CPU (sd, 0);
857*1f4e7eb9Schristos   struct pru_regset *pru_cpu = PRU_SIM_CPU (cpu);
8584b169a6bSchristos   host_callback *cb = STATE_CALLBACK (sd);
859*1f4e7eb9Schristos   bfd_vma addr;
8608dffb485Schristos 
8618dffb485Schristos   addr = bfd_get_start_address (prog_bfd);
8628dffb485Schristos 
8638dffb485Schristos   sim_pc_set (cpu, addr);
8648dffb485Schristos   PC_ADDR_SPACE_MARKER = addr & ~IMEM_ADDR_MASK;
8658dffb485Schristos 
8668dffb485Schristos   /* Standalone mode (i.e. `run`) will take care of the argv for us in
8678dffb485Schristos      sim_open () -> sim_parse_args ().  But in debug mode (i.e. 'target sim'
8688dffb485Schristos      with `gdb`), we need to handle it because the user can change the
8698dffb485Schristos      argv on the fly via gdb's 'run'.  */
8708dffb485Schristos   if (STATE_PROG_ARGV (sd) != argv)
8718dffb485Schristos     {
8728dffb485Schristos       freeargv (STATE_PROG_ARGV (sd));
8738dffb485Schristos       STATE_PROG_ARGV (sd) = dupargv (argv);
8748dffb485Schristos     }
8758dffb485Schristos 
8764b169a6bSchristos   if (STATE_PROG_ENVP (sd) != env)
8774b169a6bSchristos     {
8784b169a6bSchristos       freeargv (STATE_PROG_ENVP (sd));
8794b169a6bSchristos       STATE_PROG_ENVP (sd) = dupargv (env);
8804b169a6bSchristos     }
8814b169a6bSchristos 
8824b169a6bSchristos   cb->argv = STATE_PROG_ARGV (sd);
8834b169a6bSchristos   cb->envp = STATE_PROG_ENVP (sd);
8844b169a6bSchristos 
8858dffb485Schristos   return SIM_RC_OK;
8868dffb485Schristos }
887