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