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