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@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