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