1 /* Simulator for Xilinx MicroBlaze processor
2 Copyright 2009-2024 Free Software Foundation, Inc.
4 This file is part of GDB, the GNU debugger.
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
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>. */
19 /* This must come before any other includes. */
26 #include "sim/callback.h"
27 #include "libiberty.h"
31 #include "sim-options.h"
32 #include "sim-signal.h"
33 #include "sim-syscall.h"
35 #include "microblaze-sim.h"
36 #include "opcodes/microblaze-dis.h"
38 #define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
41 microblaze_extract_unsigned_integer (const unsigned char *addr
, int len
)
45 unsigned char *startaddr
= (unsigned char *)addr
;
46 unsigned char *endaddr
= startaddr
+ len
;
48 if (len
> (int) sizeof (unsigned long))
49 printf ("That operation is not available on integers of more than "
50 "%zu bytes.", sizeof (unsigned long));
52 /* Start at the most significant end of the integer, and work towards
53 the least significant. */
56 if (!target_big_endian
)
58 for (p
= endaddr
; p
> startaddr
;)
59 retval
= (retval
<< 8) | * -- p
;
63 for (p
= startaddr
; p
< endaddr
;)
64 retval
= (retval
<< 8) | * p
++;
71 microblaze_store_unsigned_integer (unsigned char *addr
, int len
,
75 unsigned char *startaddr
= (unsigned char *)addr
;
76 unsigned char *endaddr
= startaddr
+ len
;
78 if (!target_big_endian
)
80 for (p
= startaddr
; p
< endaddr
;)
88 for (p
= endaddr
; p
> startaddr
;)
97 set_initial_gprs (SIM_CPU
*cpu
)
101 /* Set up machine just out of reset. */
105 /* Clean out the GPRs */
106 for (i
= 0; i
< 32; i
++)
113 static int tracing
= 0;
116 sim_engine_run (SIM_DESC sd
,
117 int next_cpu_nr
, /* ignore */
118 int nr_cpus
, /* ignore */
119 int siggnal
) /* ignore */
121 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
123 enum microblaze_instr op
;
130 unsigned_4 oldpc
, newpc
;
131 short delay_slot_enable
;
133 short num_delay_slot
; /* UNUSED except as reqd parameter */
134 enum microblaze_instr_type insn_type
;
142 /* Fetch the initial instructions that we'll decode. */
143 inst
= MEM_RD_WORD (PC
& 0xFFFFFFFC);
145 op
= get_insn_microblaze (inst
, &imm_unsigned
, &insn_type
,
148 if (op
== invalid_inst
)
149 fprintf (stderr
, "Unknown instruction 0x%04x", inst
);
152 fprintf (stderr
, "%.4x: inst = %.4x ", PC
, inst
);
157 /* immword = IMM_W; */
160 delay_slot_enable
= 0;
162 if (op
== microblaze_brk
)
163 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_stopped
, SIM_SIGTRAP
);
164 else if (inst
== MICROBLAZE_HALT_INST
)
168 TRACE_INSN (cpu
, "HALT (%i)", RETREG
);
169 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_exited
, RETREG
);
175 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
177 TRACE_INSN (cpu, #NAME); \
180 #include "microblaze.isa"
184 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_signalled
,
186 fprintf (stderr
, "ERROR: Unknown opcode\n");
188 /* Make R0 consistent */
191 /* Check for imm instr */
197 /* Update cycle counts */
199 if (insn_type
== memory_store_inst
|| insn_type
== memory_load_inst
)
201 if (insn_type
== mult_inst
)
203 if (insn_type
== barrel_shift_inst
)
205 if (insn_type
== anyware_inst
)
207 if (insn_type
== div_inst
)
210 if ((insn_type
== branch_inst
|| insn_type
== return_inst
)
213 /* Add an extra cycle for taken branches */
215 /* For branch instructions handle the instruction in the delay slot */
216 if (delay_slot_enable
)
219 PC
= oldpc
+ INST_SIZE
;
220 inst
= MEM_RD_WORD (PC
& 0xFFFFFFFC);
221 op
= get_insn_microblaze (inst
, &imm_unsigned
, &insn_type
,
223 if (op
== invalid_inst
)
224 fprintf (stderr
, "Unknown instruction 0x%04x", inst
);
226 fprintf (stderr
, "%.4x: inst = %.4x ", PC
, inst
);
230 /* immword = IMM_W; */
231 if (op
== microblaze_brk
)
233 if (STATE_VERBOSE_P (sd
))
234 fprintf (stderr
, "Breakpoint set in delay slot "
235 "(at address 0x%x) will not be honored\n", PC
);
236 /* ignore the breakpoint */
238 else if (insn_type
== branch_inst
|| insn_type
== return_inst
)
240 if (STATE_VERBOSE_P (sd
))
241 fprintf (stderr
, "Cannot have branch or return instructions "
242 "in delay slot (at address 0x%x)\n", PC
);
243 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_signalled
,
250 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
254 #include "microblaze.isa"
258 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
,
259 sim_signalled
, SIM_SIGILL
);
260 fprintf (stderr
, "ERROR: Unknown opcode at 0x%x\n", PC
);
262 /* Update cycle counts */
264 if (insn_type
== memory_store_inst
265 || insn_type
== memory_load_inst
)
267 if (insn_type
== mult_inst
)
269 if (insn_type
== barrel_shift_inst
)
271 if (insn_type
== anyware_inst
)
273 if (insn_type
== div_inst
)
278 /* Make R0 consistent */
280 /* Check for imm instr */
288 if (op
== brki
&& IMM
== 8)
290 RETREG
= sim_syscall (cpu
, CPU
.regs
[12], CPU
.regs
[5],
291 CPU
.regs
[6], CPU
.regs
[7],
296 /* no delay slot: increment cycle count */
303 fprintf (stderr
, "\n");
305 if (sim_events_tick (sd
))
306 sim_events_process (sd
);
309 /* Hide away the things we've cached while executing. */
311 CPU
.insts
+= insts
; /* instructions done ... */
312 CPU
.cycles
+= insts
; /* and each takes a cycle */
313 CPU
.cycles
+= bonus_cycles
; /* and extra cycles for branches */
314 CPU
.cycles
+= memops
; /* and memop cycle delays */
318 microblaze_reg_store (SIM_CPU
*cpu
, int rn
, const void *memory
, int length
)
320 if (rn
< NUM_REGS
+ NUM_SPECIAL
&& rn
>= 0)
324 /* misalignment safe */
325 long ival
= microblaze_extract_unsigned_integer (memory
, 4);
329 CPU
.spregs
[rn
-NUM_REGS
] = ival
;
340 microblaze_reg_fetch (SIM_CPU
*cpu
, int rn
, void *memory
, int length
)
344 if (rn
< NUM_REGS
+ NUM_SPECIAL
&& rn
>= 0)
351 ival
= CPU
.spregs
[rn
-NUM_REGS
];
353 /* misalignment-safe */
354 microblaze_store_unsigned_integer (memory
, 4, ival
);
365 sim_info (SIM_DESC sd
, bool verbose
)
367 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
368 host_callback
*callback
= STATE_CALLBACK (sd
);
370 callback
->printf_filtered (callback
, "\n\n# instructions executed %10d\n",
372 callback
->printf_filtered (callback
, "# cycles %10d\n",
373 (CPU
.cycles
) ? CPU
.cycles
+2 : 0);
377 microblaze_pc_get (sim_cpu
*cpu
)
379 return MICROBLAZE_SIM_CPU (cpu
)->spregs
[0];
383 microblaze_pc_set (sim_cpu
*cpu
, sim_cia pc
)
385 MICROBLAZE_SIM_CPU (cpu
)->spregs
[0] = pc
;
389 free_state (SIM_DESC sd
)
391 if (STATE_MODULES (sd
) != NULL
)
392 sim_module_uninstall (sd
);
393 sim_cpu_free_all (sd
);
398 sim_open (SIM_OPEN_KIND kind
, host_callback
*cb
,
399 struct bfd
*abfd
, char * const *argv
)
402 SIM_DESC sd
= sim_state_alloc (kind
, cb
);
403 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
405 /* The cpu data is kept in a separately allocated chunk of memory. */
406 if (sim_cpu_alloc_all_extra (sd
, 0, sizeof (struct microblaze_regset
))
413 if (sim_pre_argv_init (sd
, argv
[0]) != SIM_RC_OK
)
419 /* The parser will print an error message for us, so we silently return. */
420 if (sim_parse_args (sd
, argv
) != SIM_RC_OK
)
426 /* Check for/establish the a reference program image. */
427 if (sim_analyze_program (sd
, STATE_PROG_FILE (sd
), abfd
) != SIM_RC_OK
)
433 /* Configure/verify the target byte order and other runtime
434 configuration options. */
435 if (sim_config (sd
) != SIM_RC_OK
)
437 sim_module_uninstall (sd
);
441 if (sim_post_argv_init (sd
) != SIM_RC_OK
)
443 /* Uninstall the modules to avoid memory leaks,
444 file descriptor leaks, etc. */
445 sim_module_uninstall (sd
);
449 /* CPU specific initialization. */
450 for (i
= 0; i
< MAX_NR_PROCESSORS
; ++i
)
452 SIM_CPU
*cpu
= STATE_CPU (sd
, i
);
454 CPU_REG_FETCH (cpu
) = microblaze_reg_fetch
;
455 CPU_REG_STORE (cpu
) = microblaze_reg_store
;
456 CPU_PC_FETCH (cpu
) = microblaze_pc_get
;
457 CPU_PC_STORE (cpu
) = microblaze_pc_set
;
459 set_initial_gprs (cpu
);
462 /* Default to a 8 Mbyte (== 2^23) memory space. */
463 sim_do_commandf (sd
, "memory-size 0x800000");
469 sim_create_inferior (SIM_DESC sd
, struct bfd
*prog_bfd
,
470 char * const *argv
, char * const *env
)
472 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
474 PC
= bfd_get_start_address (prog_bfd
);