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