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