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