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