1 /* Simulator for Xilinx MicroBlaze processor
2 Copyright 2009-2021 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. */
27 #include "sim/callback.h"
28 #include "libiberty.h"
32 #include "sim-options.h"
33 #include "sim-syscall.h"
35 #include "microblaze-dis.h"
37 #define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
40 microblaze_extract_unsigned_integer (unsigned char *addr
, int len
)
44 unsigned char *startaddr
= (unsigned char *)addr
;
45 unsigned char *endaddr
= startaddr
+ len
;
47 if (len
> (int) sizeof (unsigned long))
48 printf ("That operation is not available on integers of more than "
49 "%zu bytes.", sizeof (unsigned long));
51 /* Start at the most significant end of the integer, and work towards
52 the least significant. */
55 if (!target_big_endian
)
57 for (p
= endaddr
; p
> startaddr
;)
58 retval
= (retval
<< 8) | * -- p
;
62 for (p
= startaddr
; p
< endaddr
;)
63 retval
= (retval
<< 8) | * p
++;
70 microblaze_store_unsigned_integer (unsigned char *addr
, int len
,
74 unsigned char *startaddr
= (unsigned char *)addr
;
75 unsigned char *endaddr
= startaddr
+ len
;
77 if (!target_big_endian
)
79 for (p
= startaddr
; p
< endaddr
;)
87 for (p
= endaddr
; p
> startaddr
;)
96 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);
124 enum microblaze_instr op
;
136 short delay_slot_enable
;
138 short num_delay_slot
; /* UNUSED except as reqd parameter */
139 enum microblaze_instr_type insn_type
;
147 /* Fetch the initial instructions that we'll decode. */
148 inst
= MEM_RD_WORD (PC
& 0xFFFFFFFC);
150 op
= get_insn_microblaze (inst
, &imm_unsigned
, &insn_type
,
153 if (op
== invalid_inst
)
154 fprintf (stderr
, "Unknown instruction 0x%04x", inst
);
157 fprintf (stderr
, "%.4x: inst = %.4x ", PC
, inst
);
162 /* immword = IMM_W; */
165 delay_slot_enable
= 0;
167 if (op
== microblaze_brk
)
168 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_stopped
, SIM_SIGTRAP
);
169 else if (inst
== MICROBLAZE_HALT_INST
)
173 TRACE_INSN (cpu
, "HALT (%i)", RETREG
);
174 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_exited
, RETREG
);
180 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
182 TRACE_INSN (cpu, #NAME); \
185 #include "microblaze.isa"
189 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_signalled
,
191 fprintf (stderr
, "ERROR: Unknown opcode\n");
193 /* Make R0 consistent */
196 /* Check for imm instr */
202 /* Update cycle counts */
204 if (insn_type
== memory_store_inst
|| insn_type
== memory_load_inst
)
206 if (insn_type
== mult_inst
)
208 if (insn_type
== barrel_shift_inst
)
210 if (insn_type
== anyware_inst
)
212 if (insn_type
== div_inst
)
215 if ((insn_type
== branch_inst
|| insn_type
== return_inst
)
218 /* Add an extra cycle for taken branches */
220 /* For branch instructions handle the instruction in the delay slot */
221 if (delay_slot_enable
)
224 PC
= oldpc
+ INST_SIZE
;
225 inst
= MEM_RD_WORD (PC
& 0xFFFFFFFC);
226 op
= get_insn_microblaze (inst
, &imm_unsigned
, &insn_type
,
228 if (op
== invalid_inst
)
229 fprintf (stderr
, "Unknown instruction 0x%04x", inst
);
231 fprintf (stderr
, "%.4x: inst = %.4x ", PC
, inst
);
235 /* immword = IMM_W; */
236 if (op
== microblaze_brk
)
238 if (STATE_VERBOSE_P (sd
))
239 fprintf (stderr
, "Breakpoint set in delay slot "
240 "(at address 0x%x) will not be honored\n", PC
);
241 /* ignore the breakpoint */
243 else if (insn_type
== branch_inst
|| insn_type
== return_inst
)
245 if (STATE_VERBOSE_P (sd
))
246 fprintf (stderr
, "Cannot have branch or return instructions "
247 "in delay slot (at address 0x%x)\n", PC
);
248 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
, sim_signalled
,
255 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
259 #include "microblaze.isa"
263 sim_engine_halt (sd
, NULL
, NULL
, NULL_CIA
,
264 sim_signalled
, SIM_SIGILL
);
265 fprintf (stderr
, "ERROR: Unknown opcode at 0x%x\n", PC
);
267 /* Update cycle counts */
269 if (insn_type
== memory_store_inst
270 || insn_type
== memory_load_inst
)
272 if (insn_type
== mult_inst
)
274 if (insn_type
== barrel_shift_inst
)
276 if (insn_type
== anyware_inst
)
278 if (insn_type
== div_inst
)
283 /* Make R0 consistent */
285 /* Check for imm instr */
293 if (op
== brki
&& IMM
== 8)
295 RETREG
= sim_syscall (cpu
, CPU
.regs
[12], CPU
.regs
[5],
296 CPU
.regs
[6], CPU
.regs
[7],
301 /* no delay slot: increment cycle count */
308 fprintf (stderr
, "\n");
310 if (sim_events_tick (sd
))
311 sim_events_process (sd
);
314 /* Hide away the things we've cached while executing. */
316 CPU
.insts
+= insts
; /* instructions done ... */
317 CPU
.cycles
+= insts
; /* and each takes a cycle */
318 CPU
.cycles
+= bonus_cycles
; /* and extra cycles for branches */
319 CPU
.cycles
+= memops
; /* and memop cycle delays */
323 microblaze_reg_store (SIM_CPU
*cpu
, int rn
, unsigned char *memory
, int length
)
325 if (rn
< NUM_REGS
+ NUM_SPECIAL
&& rn
>= 0)
329 /* misalignment safe */
330 long ival
= microblaze_extract_unsigned_integer (memory
, 4);
334 CPU
.spregs
[rn
-NUM_REGS
] = ival
;
345 microblaze_reg_fetch (SIM_CPU
*cpu
, int rn
, unsigned char *memory
, int length
)
349 if (rn
< NUM_REGS
+ NUM_SPECIAL
&& rn
>= 0)
356 ival
= CPU
.spregs
[rn
-NUM_REGS
];
358 /* misalignment-safe */
359 microblaze_store_unsigned_integer (memory
, 4, ival
);
370 sim_info (SIM_DESC sd
, int verbose
)
372 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
373 host_callback
*callback
= STATE_CALLBACK (sd
);
375 callback
->printf_filtered (callback
, "\n\n# instructions executed %10d\n",
377 callback
->printf_filtered (callback
, "# cycles %10d\n",
378 (CPU
.cycles
) ? CPU
.cycles
+2 : 0);
382 microblaze_pc_get (sim_cpu
*cpu
)
384 return cpu
->microblaze_cpu
.spregs
[0];
388 microblaze_pc_set (sim_cpu
*cpu
, sim_cia pc
)
390 cpu
->microblaze_cpu
.spregs
[0] = pc
;
394 free_state (SIM_DESC sd
)
396 if (STATE_MODULES (sd
) != NULL
)
397 sim_module_uninstall (sd
);
398 sim_cpu_free_all (sd
);
403 sim_open (SIM_OPEN_KIND kind
, host_callback
*cb
,
404 struct bfd
*abfd
, char * const *argv
)
407 SIM_DESC sd
= sim_state_alloc (kind
, cb
);
408 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
410 /* The cpu data is kept in a separately allocated chunk of memory. */
411 if (sim_cpu_alloc_all (sd
, 1) != SIM_RC_OK
)
417 if (sim_pre_argv_init (sd
, argv
[0]) != SIM_RC_OK
)
423 /* The parser will print an error message for us, so we silently return. */
424 if (sim_parse_args (sd
, argv
) != SIM_RC_OK
)
430 /* Check for/establish the a reference program image. */
431 if (sim_analyze_program (sd
,
432 (STATE_PROG_ARGV (sd
) != NULL
433 ? *STATE_PROG_ARGV (sd
)
434 : NULL
), abfd
) != SIM_RC_OK
)
440 /* Configure/verify the target byte order and other runtime
441 configuration options. */
442 if (sim_config (sd
) != SIM_RC_OK
)
444 sim_module_uninstall (sd
);
448 if (sim_post_argv_init (sd
) != SIM_RC_OK
)
450 /* Uninstall the modules to avoid memory leaks,
451 file descriptor leaks, etc. */
452 sim_module_uninstall (sd
);
456 /* CPU specific initialization. */
457 for (i
= 0; i
< MAX_NR_PROCESSORS
; ++i
)
459 SIM_CPU
*cpu
= STATE_CPU (sd
, i
);
461 CPU_REG_FETCH (cpu
) = microblaze_reg_fetch
;
462 CPU_REG_STORE (cpu
) = microblaze_reg_store
;
463 CPU_PC_FETCH (cpu
) = microblaze_pc_get
;
464 CPU_PC_STORE (cpu
) = microblaze_pc_set
;
466 set_initial_gprs (cpu
);
469 /* Default to a 8 Mbyte (== 2^23) memory space. */
470 sim_do_commandf (sd
, "memory-size 0x800000");
476 sim_create_inferior (SIM_DESC sd
, struct bfd
*prog_bfd
,
477 char * const *argv
, char * const *env
)
479 SIM_CPU
*cpu
= STATE_CPU (sd
, 0);
481 PC
= bfd_get_start_address (prog_bfd
);