]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/microblaze/interp.c
ld/PE: enable secrel testcases also for 64-bit Cygwin
[thirdparty/binutils-gdb.git] / sim / microblaze / interp.c
1 /* Simulator for Xilinx MicroBlaze processor
2 Copyright 2009-2024 Free Software Foundation, Inc.
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
8 the Free Software Foundation; either version 3 of the License, or
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
17 along with this program; if not, see <http://www.gnu.org/licenses/>. */
18
19 /* This must come before any other includes. */
20 #include "defs.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include "bfd.h"
26 #include "sim/callback.h"
27 #include "libiberty.h"
28 #include "sim/sim.h"
29
30 #include "sim-main.h"
31 #include "sim-options.h"
32 #include "sim-signal.h"
33 #include "sim-syscall.h"
34
35 #include "microblaze-sim.h"
36 #include "opcodes/microblaze-dis.h"
37
38 #define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
39
40 static unsigned long
41 microblaze_extract_unsigned_integer (const 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 "
50 "%zu bytes.", sizeof (unsigned long));
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
70 static void
71 microblaze_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
96 static void
97 set_initial_gprs (SIM_CPU *cpu)
98 {
99 int i;
100
101 /* Set up machine just out of reset. */
102 PC = 0;
103 MSR = 0;
104
105 /* Clean out the GPRs */
106 for (i = 0; i < 32; i++)
107 CPU.regs[i] = 0;
108 CPU.insts = 0;
109 CPU.cycles = 0;
110 CPU.imm_enable = 0;
111 }
112
113 static int tracing = 0;
114
115 void
116 sim_engine_run (SIM_DESC sd,
117 int next_cpu_nr, /* ignore */
118 int nr_cpus, /* ignore */
119 int siggnal) /* ignore */
120 {
121 SIM_CPU *cpu = STATE_CPU (sd, 0);
122 signed_4 inst;
123 enum microblaze_instr op;
124 int memops;
125 int bonus_cycles;
126 int insts;
127 unsigned_1 carry;
128 bool imm_unsigned;
129 short ra, rb, rd;
130 unsigned_4 oldpc, newpc;
131 short delay_slot_enable;
132 short branch_taken;
133 short num_delay_slot; /* UNUSED except as reqd parameter */
134 enum microblaze_instr_type insn_type;
135
136 memops = 0;
137 bonus_cycles = 0;
138 insts = 0;
139
140 while (1)
141 {
142 /* Fetch the initial instructions that we'll decode. */
143 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
144
145 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
146 &num_delay_slot);
147
148 if (op == invalid_inst)
149 fprintf (stderr, "Unknown instruction 0x%04x", inst);
150
151 if (tracing)
152 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
153
154 rd = GET_RD;
155 rb = GET_RB;
156 ra = GET_RA;
157 /* immword = IMM_W; */
158
159 oldpc = PC;
160 delay_slot_enable = 0;
161 branch_taken = 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)
165 {
166 insts += 1;
167 bonus_cycles++;
168 TRACE_INSN (cpu, "HALT (%i)", RETREG);
169 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_exited, RETREG);
170 }
171 else
172 {
173 switch(op)
174 {
175 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
176 case NAME: \
177 TRACE_INSN (cpu, #NAME); \
178 ACTION; \
179 break;
180 #include "microblaze.isa"
181 #undef INSTRUCTION
182
183 default:
184 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
185 SIM_SIGILL);
186 fprintf (stderr, "ERROR: Unknown opcode\n");
187 }
188 /* Make R0 consistent */
189 CPU.regs[0] = 0;
190
191 /* Check for imm instr */
192 if (op == imm)
193 IMM_ENABLE = 1;
194 else
195 IMM_ENABLE = 0;
196
197 /* Update cycle counts */
198 insts ++;
199 if (insn_type == memory_store_inst || insn_type == memory_load_inst)
200 memops++;
201 if (insn_type == mult_inst)
202 bonus_cycles++;
203 if (insn_type == barrel_shift_inst)
204 bonus_cycles++;
205 if (insn_type == anyware_inst)
206 bonus_cycles++;
207 if (insn_type == div_inst)
208 bonus_cycles += 33;
209
210 if ((insn_type == branch_inst || insn_type == return_inst)
211 && branch_taken)
212 {
213 /* Add an extra cycle for taken branches */
214 bonus_cycles++;
215 /* For branch instructions handle the instruction in the delay slot */
216 if (delay_slot_enable)
217 {
218 newpc = PC;
219 PC = oldpc + INST_SIZE;
220 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
221 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
222 &num_delay_slot);
223 if (op == invalid_inst)
224 fprintf (stderr, "Unknown instruction 0x%04x", inst);
225 if (tracing)
226 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
227 rd = GET_RD;
228 rb = GET_RB;
229 ra = GET_RA;
230 /* immword = IMM_W; */
231 if (op == microblaze_brk)
232 {
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 */
237 }
238 else if (insn_type == branch_inst || insn_type == return_inst)
239 {
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,
244 SIM_SIGILL);
245 }
246 else
247 {
248 switch(op)
249 {
250 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
251 case NAME: \
252 ACTION; \
253 break;
254 #include "microblaze.isa"
255 #undef INSTRUCTION
256
257 default:
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);
261 }
262 /* Update cycle counts */
263 insts++;
264 if (insn_type == memory_store_inst
265 || insn_type == memory_load_inst)
266 memops++;
267 if (insn_type == mult_inst)
268 bonus_cycles++;
269 if (insn_type == barrel_shift_inst)
270 bonus_cycles++;
271 if (insn_type == anyware_inst)
272 bonus_cycles++;
273 if (insn_type == div_inst)
274 bonus_cycles += 33;
275 }
276 /* Restore the PC */
277 PC = newpc;
278 /* Make R0 consistent */
279 CPU.regs[0] = 0;
280 /* Check for imm instr */
281 if (op == imm)
282 IMM_ENABLE = 1;
283 else
284 IMM_ENABLE = 0;
285 }
286 else
287 {
288 if (op == brki && IMM == 8)
289 {
290 RETREG = sim_syscall (cpu, CPU.regs[12], CPU.regs[5],
291 CPU.regs[6], CPU.regs[7],
292 CPU.regs[8]);
293 PC = RD + INST_SIZE;
294 }
295
296 /* no delay slot: increment cycle count */
297 bonus_cycles++;
298 }
299 }
300 }
301
302 if (tracing)
303 fprintf (stderr, "\n");
304
305 if (sim_events_tick (sd))
306 sim_events_process (sd);
307 }
308
309 /* Hide away the things we've cached while executing. */
310 /* CPU.pc = pc; */
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 */
315 }
316
317 static int
318 microblaze_reg_store (SIM_CPU *cpu, int rn, const void *memory, int length)
319 {
320 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
321 {
322 if (length == 4)
323 {
324 /* misalignment safe */
325 long ival = microblaze_extract_unsigned_integer (memory, 4);
326 if (rn < NUM_REGS)
327 CPU.regs[rn] = ival;
328 else
329 CPU.spregs[rn-NUM_REGS] = ival;
330 return 4;
331 }
332 else
333 return 0;
334 }
335 else
336 return 0;
337 }
338
339 static int
340 microblaze_reg_fetch (SIM_CPU *cpu, int rn, void *memory, int length)
341 {
342 long ival;
343
344 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
345 {
346 if (length == 4)
347 {
348 if (rn < NUM_REGS)
349 ival = CPU.regs[rn];
350 else
351 ival = CPU.spregs[rn-NUM_REGS];
352
353 /* misalignment-safe */
354 microblaze_store_unsigned_integer (memory, 4, ival);
355 return 4;
356 }
357 else
358 return 0;
359 }
360 else
361 return 0;
362 }
363
364 void
365 sim_info (SIM_DESC sd, bool verbose)
366 {
367 SIM_CPU *cpu = STATE_CPU (sd, 0);
368 host_callback *callback = STATE_CALLBACK (sd);
369
370 callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
371 CPU.insts);
372 callback->printf_filtered (callback, "# cycles %10d\n",
373 (CPU.cycles) ? CPU.cycles+2 : 0);
374 }
375
376 static sim_cia
377 microblaze_pc_get (sim_cpu *cpu)
378 {
379 return MICROBLAZE_SIM_CPU (cpu)->spregs[0];
380 }
381
382 static void
383 microblaze_pc_set (sim_cpu *cpu, sim_cia pc)
384 {
385 MICROBLAZE_SIM_CPU (cpu)->spregs[0] = pc;
386 }
387
388 static void
389 free_state (SIM_DESC sd)
390 {
391 if (STATE_MODULES (sd) != NULL)
392 sim_module_uninstall (sd);
393 sim_cpu_free_all (sd);
394 sim_state_free (sd);
395 }
396
397 SIM_DESC
398 sim_open (SIM_OPEN_KIND kind, host_callback *cb,
399 struct bfd *abfd, char * const *argv)
400 {
401 int i;
402 SIM_DESC sd = sim_state_alloc (kind, cb);
403 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
404
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))
407 != SIM_RC_OK)
408 {
409 free_state (sd);
410 return 0;
411 }
412
413 if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
414 {
415 free_state (sd);
416 return 0;
417 }
418
419 /* The parser will print an error message for us, so we silently return. */
420 if (sim_parse_args (sd, argv) != SIM_RC_OK)
421 {
422 free_state (sd);
423 return 0;
424 }
425
426 /* Check for/establish the a reference program image. */
427 if (sim_analyze_program (sd, STATE_PROG_FILE (sd), abfd) != SIM_RC_OK)
428 {
429 free_state (sd);
430 return 0;
431 }
432
433 /* Configure/verify the target byte order and other runtime
434 configuration options. */
435 if (sim_config (sd) != SIM_RC_OK)
436 {
437 sim_module_uninstall (sd);
438 return 0;
439 }
440
441 if (sim_post_argv_init (sd) != SIM_RC_OK)
442 {
443 /* Uninstall the modules to avoid memory leaks,
444 file descriptor leaks, etc. */
445 sim_module_uninstall (sd);
446 return 0;
447 }
448
449 /* CPU specific initialization. */
450 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
451 {
452 SIM_CPU *cpu = STATE_CPU (sd, i);
453
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;
458
459 set_initial_gprs (cpu);
460 }
461
462 /* Default to a 8 Mbyte (== 2^23) memory space. */
463 sim_do_commandf (sd, "memory-size 0x800000");
464
465 return sd;
466 }
467
468 SIM_RC
469 sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
470 char * const *argv, char * const *env)
471 {
472 SIM_CPU *cpu = STATE_CPU (sd, 0);
473
474 PC = bfd_get_start_address (prog_bfd);
475
476 return SIM_RC_OK;
477 }