]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/microblaze/interp.c
sim: split sim-signal.h include out
[thirdparty/binutils-gdb.git] / sim / microblaze / interp.c
CommitLineData
bd30e45a 1/* Simulator for Xilinx MicroBlaze processor
3666a048 2 Copyright 2009-2021 Free Software Foundation, Inc.
bd30e45a
ME
3
4 This file is part of GDB, the GNU debugger.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
3fd725ef 8 the Free Software Foundation; either version 3 of the License, or
bd30e45a
ME
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
51b318de 17 along with this program; if not, see <http://www.gnu.org/licenses/>. */
bd30e45a 18
6df01ab8
MF
19/* This must come before any other includes. */
20#include "defs.h"
21
bd30e45a 22#include <signal.h>
dc049bf4
MF
23#include <stdlib.h>
24#include <string.h>
dc049bf4 25#include <unistd.h>
bd30e45a 26#include "bfd.h"
df68e12b 27#include "sim/callback.h"
bd30e45a 28#include "libiberty.h"
df68e12b 29#include "sim/sim.h"
2b4bc832 30
bd30e45a 31#include "sim-main.h"
2b4bc832 32#include "sim-options.h"
1fef66b0 33#include "sim-signal.h"
cd09ab7c 34#include "sim-syscall.h"
2b4bc832 35
419c2fda 36#include "microblaze-dis.h"
bd30e45a 37
e7cd2680 38#define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
bd30e45a 39
feb703b3 40static unsigned long
bd30e45a
ME
41microblaze_extract_unsigned_integer (unsigned char *addr, int len)
42{
43 unsigned long retval;
44 unsigned char *p;
45 unsigned char *startaddr = (unsigned char *)addr;
46 unsigned char *endaddr = startaddr + len;
47
48 if (len > (int) sizeof (unsigned long))
49 printf ("That operation is not available on integers of more than "
3e95021c 50 "%zu bytes.", sizeof (unsigned long));
bd30e45a
ME
51
52 /* Start at the most significant end of the integer, and work towards
53 the least significant. */
54 retval = 0;
55
56 if (!target_big_endian)
57 {
58 for (p = endaddr; p > startaddr;)
59 retval = (retval << 8) | * -- p;
60 }
61 else
62 {
63 for (p = startaddr; p < endaddr;)
64 retval = (retval << 8) | * p ++;
65 }
66
67 return retval;
68}
69
feb703b3 70static void
bd30e45a
ME
71microblaze_store_unsigned_integer (unsigned char *addr, int len,
72 unsigned long val)
73{
74 unsigned char *p;
75 unsigned char *startaddr = (unsigned char *)addr;
76 unsigned char *endaddr = startaddr + len;
77
78 if (!target_big_endian)
79 {
80 for (p = startaddr; p < endaddr;)
81 {
82 *p++ = val & 0xff;
83 val >>= 8;
84 }
85 }
86 else
87 {
88 for (p = endaddr; p > startaddr;)
89 {
90 *--p = val & 0xff;
91 val >>= 8;
92 }
93 }
94}
95
bd30e45a 96static void
2b4bc832 97set_initial_gprs (SIM_CPU *cpu)
bd30e45a
ME
98{
99 int i;
100 long space;
bd30e45a
ME
101
102 /* Set up machine just out of reset. */
103 PC = 0;
104 MSR = 0;
105
bd30e45a
ME
106 /* Clean out the GPRs */
107 for (i = 0; i < 32; i++)
108 CPU.regs[i] = 0;
109 CPU.insts = 0;
110 CPU.cycles = 0;
111 CPU.imm_enable = 0;
bd30e45a
ME
112}
113
bd30e45a
ME
114static int tracing = 0;
115
116void
31557ecc
MF
117sim_engine_run (SIM_DESC sd,
118 int next_cpu_nr, /* ignore */
119 int nr_cpus, /* ignore */
120 int siggnal) /* ignore */
bd30e45a 121{
2b4bc832 122 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a
ME
123 int needfetch;
124 word inst;
125 enum microblaze_instr op;
bd30e45a
ME
126 int memops;
127 int bonus_cycles;
128 int insts;
129 int w;
130 int cycs;
131 word WLhash;
132 ubyte carry;
caaf412e 133 bool imm_unsigned;
bd30e45a
ME
134 short ra, rb, rd;
135 long immword;
136 uword oldpc, newpc;
137 short delay_slot_enable;
138 short branch_taken;
139 short num_delay_slot; /* UNUSED except as reqd parameter */
140 enum microblaze_instr_type insn_type;
141
bd30e45a
ME
142 memops = 0;
143 bonus_cycles = 0;
144 insts = 0;
ba14f941 145
31557ecc 146 while (1)
bd30e45a
ME
147 {
148 /* Fetch the initial instructions that we'll decode. */
c85fc610 149 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a 150
ba14f941 151 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
bd30e45a
ME
152 &num_delay_slot);
153
154 if (op == invalid_inst)
155 fprintf (stderr, "Unknown instruction 0x%04x", inst);
156
157 if (tracing)
158 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
159
160 rd = GET_RD;
161 rb = GET_RB;
162 ra = GET_RA;
163 /* immword = IMM_W; */
164
165 oldpc = PC;
166 delay_slot_enable = 0;
167 branch_taken = 0;
168 if (op == microblaze_brk)
31557ecc 169 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
bd30e45a
ME
170 else if (inst == MICROBLAZE_HALT_INST)
171 {
bd30e45a
ME
172 insts += 1;
173 bonus_cycles++;
4d47dcfc 174 TRACE_INSN (cpu, "HALT (%i)", RETREG);
31557ecc 175 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_exited, RETREG);
bd30e45a
ME
176 }
177 else
178 {
179 switch(op)
180 {
181#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
182 case NAME: \
4d47dcfc 183 TRACE_INSN (cpu, #NAME); \
bd30e45a
ME
184 ACTION; \
185 break;
186#include "microblaze.isa"
187#undef INSTRUCTION
188
189 default:
31557ecc
MF
190 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
191 SIM_SIGILL);
bd30e45a
ME
192 fprintf (stderr, "ERROR: Unknown opcode\n");
193 }
194 /* Make R0 consistent */
195 CPU.regs[0] = 0;
196
197 /* Check for imm instr */
198 if (op == imm)
199 IMM_ENABLE = 1;
200 else
201 IMM_ENABLE = 0;
202
203 /* Update cycle counts */
204 insts ++;
205 if (insn_type == memory_store_inst || insn_type == memory_load_inst)
206 memops++;
207 if (insn_type == mult_inst)
208 bonus_cycles++;
209 if (insn_type == barrel_shift_inst)
210 bonus_cycles++;
211 if (insn_type == anyware_inst)
212 bonus_cycles++;
213 if (insn_type == div_inst)
214 bonus_cycles += 33;
215
216 if ((insn_type == branch_inst || insn_type == return_inst)
ba14f941 217 && branch_taken)
bd30e45a
ME
218 {
219 /* Add an extra cycle for taken branches */
220 bonus_cycles++;
221 /* For branch instructions handle the instruction in the delay slot */
ba14f941 222 if (delay_slot_enable)
bd30e45a
ME
223 {
224 newpc = PC;
225 PC = oldpc + INST_SIZE;
c85fc610 226 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a
ME
227 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
228 &num_delay_slot);
229 if (op == invalid_inst)
230 fprintf (stderr, "Unknown instruction 0x%04x", inst);
231 if (tracing)
232 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
233 rd = GET_RD;
234 rb = GET_RB;
235 ra = GET_RA;
236 /* immword = IMM_W; */
237 if (op == microblaze_brk)
238 {
c85fc610 239 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
240 fprintf (stderr, "Breakpoint set in delay slot "
241 "(at address 0x%x) will not be honored\n", PC);
242 /* ignore the breakpoint */
243 }
244 else if (insn_type == branch_inst || insn_type == return_inst)
245 {
c85fc610 246 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
247 fprintf (stderr, "Cannot have branch or return instructions "
248 "in delay slot (at address 0x%x)\n", PC);
31557ecc
MF
249 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
250 SIM_SIGILL);
bd30e45a
ME
251 }
252 else
253 {
254 switch(op)
255 {
256#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
257 case NAME: \
258 ACTION; \
259 break;
260#include "microblaze.isa"
261#undef INSTRUCTION
262
263 default:
31557ecc
MF
264 sim_engine_halt (sd, NULL, NULL, NULL_CIA,
265 sim_signalled, SIM_SIGILL);
bd30e45a
ME
266 fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC);
267 }
268 /* Update cycle counts */
269 insts++;
270 if (insn_type == memory_store_inst
ba14f941 271 || insn_type == memory_load_inst)
bd30e45a
ME
272 memops++;
273 if (insn_type == mult_inst)
274 bonus_cycles++;
275 if (insn_type == barrel_shift_inst)
276 bonus_cycles++;
277 if (insn_type == anyware_inst)
278 bonus_cycles++;
279 if (insn_type == div_inst)
280 bonus_cycles += 33;
281 }
282 /* Restore the PC */
283 PC = newpc;
284 /* Make R0 consistent */
285 CPU.regs[0] = 0;
286 /* Check for imm instr */
287 if (op == imm)
288 IMM_ENABLE = 1;
289 else
290 IMM_ENABLE = 0;
291 }
292 else
cd09ab7c
MF
293 {
294 if (op == brki && IMM == 8)
295 {
296 RETREG = sim_syscall (cpu, CPU.regs[12], CPU.regs[5],
297 CPU.regs[6], CPU.regs[7],
298 CPU.regs[8]);
299 PC = RD + INST_SIZE;
300 }
301
302 /* no delay slot: increment cycle count */
303 bonus_cycles++;
304 }
bd30e45a
ME
305 }
306 }
307
308 if (tracing)
309 fprintf (stderr, "\n");
31557ecc
MF
310
311 if (sim_events_tick (sd))
312 sim_events_process (sd);
bd30e45a 313 }
bd30e45a
ME
314
315 /* Hide away the things we've cached while executing. */
316 /* CPU.pc = pc; */
317 CPU.insts += insts; /* instructions done ... */
318 CPU.cycles += insts; /* and each takes a cycle */
319 CPU.cycles += bonus_cycles; /* and extra cycles for branches */
320 CPU.cycles += memops; /* and memop cycle delays */
bd30e45a
ME
321}
322
e1211e55
MF
323static int
324microblaze_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
bd30e45a 325{
bd30e45a
ME
326 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
327 {
328 if (length == 4)
329 {
330 /* misalignment safe */
331 long ival = microblaze_extract_unsigned_integer (memory, 4);
332 if (rn < NUM_REGS)
333 CPU.regs[rn] = ival;
334 else
335 CPU.spregs[rn-NUM_REGS] = ival;
336 return 4;
337 }
338 else
339 return 0;
340 }
341 else
342 return 0;
343}
344
e1211e55
MF
345static int
346microblaze_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
bd30e45a
ME
347{
348 long ival;
2b4bc832 349
bd30e45a
ME
350 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
351 {
352 if (length == 4)
353 {
354 if (rn < NUM_REGS)
355 ival = CPU.regs[rn];
356 else
357 ival = CPU.spregs[rn-NUM_REGS];
358
359 /* misalignment-safe */
360 microblaze_store_unsigned_integer (memory, 4, ival);
361 return 4;
362 }
363 else
364 return 0;
365 }
366 else
367 return 0;
368}
369
bd30e45a
ME
370void
371sim_info (SIM_DESC sd, int verbose)
372{
2b4bc832
MF
373 SIM_CPU *cpu = STATE_CPU (sd, 0);
374 host_callback *callback = STATE_CALLBACK (sd);
375
bd30e45a
ME
376 callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
377 CPU.insts);
378 callback->printf_filtered (callback, "# cycles %10d\n",
379 (CPU.cycles) ? CPU.cycles+2 : 0);
bd30e45a
ME
380}
381
27b97b40
MF
382static sim_cia
383microblaze_pc_get (sim_cpu *cpu)
384{
385 return cpu->microblaze_cpu.spregs[0];
386}
387
388static void
389microblaze_pc_set (sim_cpu *cpu, sim_cia pc)
390{
391 cpu->microblaze_cpu.spregs[0] = pc;
392}
393
2b4bc832
MF
394static void
395free_state (SIM_DESC sd)
396{
397 if (STATE_MODULES (sd) != NULL)
398 sim_module_uninstall (sd);
399 sim_cpu_free_all (sd);
400 sim_state_free (sd);
401}
402
bd30e45a 403SIM_DESC
2e3d4f4d
MF
404sim_open (SIM_OPEN_KIND kind, host_callback *cb,
405 struct bfd *abfd, char * const *argv)
bd30e45a 406{
2b4bc832
MF
407 int i;
408 SIM_DESC sd = sim_state_alloc (kind, cb);
409 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
410
411 /* The cpu data is kept in a separately allocated chunk of memory. */
d5a71b11 412 if (sim_cpu_alloc_all (sd, 1) != SIM_RC_OK)
2b4bc832
MF
413 {
414 free_state (sd);
415 return 0;
416 }
417
418 if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
419 {
420 free_state (sd);
421 return 0;
422 }
bd30e45a 423
77cf2ef5 424 /* The parser will print an error message for us, so we silently return. */
2b4bc832
MF
425 if (sim_parse_args (sd, argv) != SIM_RC_OK)
426 {
427 free_state (sd);
428 return 0;
429 }
430
431 /* Check for/establish the a reference program image. */
432 if (sim_analyze_program (sd,
433 (STATE_PROG_ARGV (sd) != NULL
434 ? *STATE_PROG_ARGV (sd)
435 : NULL), abfd) != SIM_RC_OK)
436 {
437 free_state (sd);
438 return 0;
439 }
440
441 /* Configure/verify the target byte order and other runtime
442 configuration options. */
443 if (sim_config (sd) != SIM_RC_OK)
444 {
445 sim_module_uninstall (sd);
446 return 0;
447 }
448
449 if (sim_post_argv_init (sd) != SIM_RC_OK)
450 {
451 /* Uninstall the modules to avoid memory leaks,
452 file descriptor leaks, etc. */
453 sim_module_uninstall (sd);
454 return 0;
455 }
bd30e45a 456
2b4bc832
MF
457 /* CPU specific initialization. */
458 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
459 {
460 SIM_CPU *cpu = STATE_CPU (sd, i);
2b4bc832 461
e1211e55
MF
462 CPU_REG_FETCH (cpu) = microblaze_reg_fetch;
463 CPU_REG_STORE (cpu) = microblaze_reg_store;
27b97b40
MF
464 CPU_PC_FETCH (cpu) = microblaze_pc_get;
465 CPU_PC_STORE (cpu) = microblaze_pc_set;
466
2b4bc832 467 set_initial_gprs (cpu);
2b4bc832 468 }
bd30e45a 469
c85fc610
MF
470 /* Default to a 8 Mbyte (== 2^23) memory space. */
471 sim_do_commandf (sd, "memory-size 0x800000");
472
2b4bc832 473 return sd;
bd30e45a
ME
474}
475
bd30e45a 476SIM_RC
2e3d4f4d
MF
477sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
478 char * const *argv, char * const *env)
bd30e45a 479{
2b4bc832 480 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a 481
bd30e45a
ME
482 PC = bfd_get_start_address (prog_bfd);
483
bd30e45a
ME
484 return SIM_RC_OK;
485}