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