]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/microblaze/interp.c
sim: microblaze: hook up libgloss syscalls
[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
8fe6640e 19#include "config.h"
bd30e45a 20#include <signal.h>
dc049bf4
MF
21#include <stdlib.h>
22#include <string.h>
dc049bf4 23#include <unistd.h>
bd30e45a
ME
24#include "bfd.h"
25#include "gdb/callback.h"
26#include "libiberty.h"
27#include "gdb/remote-sim.h"
2b4bc832 28
bd30e45a 29#include "sim-main.h"
2b4bc832 30#include "sim-options.h"
cd09ab7c 31#include "sim-syscall.h"
2b4bc832 32
419c2fda 33#include "microblaze-dis.h"
bd30e45a 34
e7cd2680 35#define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
bd30e45a 36
feb703b3 37static unsigned long
bd30e45a
ME
38microblaze_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 "
3e95021c 47 "%zu bytes.", sizeof (unsigned long));
bd30e45a
ME
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
feb703b3 67static void
bd30e45a
ME
68microblaze_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
bd30e45a 93static void
2b4bc832 94set_initial_gprs (SIM_CPU *cpu)
bd30e45a
ME
95{
96 int i;
97 long space;
bd30e45a
ME
98
99 /* Set up machine just out of reset. */
100 PC = 0;
101 MSR = 0;
102
bd30e45a
ME
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;
bd30e45a
ME
109}
110
bd30e45a
ME
111static int tracing = 0;
112
113void
31557ecc
MF
114sim_engine_run (SIM_DESC sd,
115 int next_cpu_nr, /* ignore */
116 int nr_cpus, /* ignore */
117 int siggnal) /* ignore */
bd30e45a 118{
2b4bc832 119 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a
ME
120 int needfetch;
121 word inst;
122 enum microblaze_instr op;
bd30e45a
ME
123 int memops;
124 int bonus_cycles;
125 int insts;
126 int w;
127 int cycs;
128 word WLhash;
129 ubyte carry;
caaf412e 130 bool imm_unsigned;
bd30e45a
ME
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
bd30e45a
ME
139 memops = 0;
140 bonus_cycles = 0;
141 insts = 0;
ba14f941 142
31557ecc 143 while (1)
bd30e45a
ME
144 {
145 /* Fetch the initial instructions that we'll decode. */
c85fc610 146 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a 147
ba14f941 148 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
bd30e45a
ME
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)
31557ecc 166 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
bd30e45a
ME
167 else if (inst == MICROBLAZE_HALT_INST)
168 {
bd30e45a
ME
169 insts += 1;
170 bonus_cycles++;
31557ecc 171 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_exited, RETREG);
bd30e45a
ME
172 }
173 else
174 {
175 switch(op)
176 {
177#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
178 case NAME: \
179 ACTION; \
180 break;
181#include "microblaze.isa"
182#undef INSTRUCTION
183
184 default:
31557ecc
MF
185 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
186 SIM_SIGILL);
bd30e45a
ME
187 fprintf (stderr, "ERROR: Unknown opcode\n");
188 }
189 /* Make R0 consistent */
190 CPU.regs[0] = 0;
191
192 /* Check for imm instr */
193 if (op == imm)
194 IMM_ENABLE = 1;
195 else
196 IMM_ENABLE = 0;
197
198 /* Update cycle counts */
199 insts ++;
200 if (insn_type == memory_store_inst || insn_type == memory_load_inst)
201 memops++;
202 if (insn_type == mult_inst)
203 bonus_cycles++;
204 if (insn_type == barrel_shift_inst)
205 bonus_cycles++;
206 if (insn_type == anyware_inst)
207 bonus_cycles++;
208 if (insn_type == div_inst)
209 bonus_cycles += 33;
210
211 if ((insn_type == branch_inst || insn_type == return_inst)
ba14f941 212 && branch_taken)
bd30e45a
ME
213 {
214 /* Add an extra cycle for taken branches */
215 bonus_cycles++;
216 /* For branch instructions handle the instruction in the delay slot */
ba14f941 217 if (delay_slot_enable)
bd30e45a
ME
218 {
219 newpc = PC;
220 PC = oldpc + INST_SIZE;
c85fc610 221 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a
ME
222 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
223 &num_delay_slot);
224 if (op == invalid_inst)
225 fprintf (stderr, "Unknown instruction 0x%04x", inst);
226 if (tracing)
227 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
228 rd = GET_RD;
229 rb = GET_RB;
230 ra = GET_RA;
231 /* immword = IMM_W; */
232 if (op == microblaze_brk)
233 {
c85fc610 234 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
235 fprintf (stderr, "Breakpoint set in delay slot "
236 "(at address 0x%x) will not be honored\n", PC);
237 /* ignore the breakpoint */
238 }
239 else if (insn_type == branch_inst || insn_type == return_inst)
240 {
c85fc610 241 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
242 fprintf (stderr, "Cannot have branch or return instructions "
243 "in delay slot (at address 0x%x)\n", PC);
31557ecc
MF
244 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
245 SIM_SIGILL);
bd30e45a
ME
246 }
247 else
248 {
249 switch(op)
250 {
251#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
252 case NAME: \
253 ACTION; \
254 break;
255#include "microblaze.isa"
256#undef INSTRUCTION
257
258 default:
31557ecc
MF
259 sim_engine_halt (sd, NULL, NULL, NULL_CIA,
260 sim_signalled, SIM_SIGILL);
bd30e45a
ME
261 fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC);
262 }
263 /* Update cycle counts */
264 insts++;
265 if (insn_type == memory_store_inst
ba14f941 266 || insn_type == memory_load_inst)
bd30e45a
ME
267 memops++;
268 if (insn_type == mult_inst)
269 bonus_cycles++;
270 if (insn_type == barrel_shift_inst)
271 bonus_cycles++;
272 if (insn_type == anyware_inst)
273 bonus_cycles++;
274 if (insn_type == div_inst)
275 bonus_cycles += 33;
276 }
277 /* Restore the PC */
278 PC = newpc;
279 /* Make R0 consistent */
280 CPU.regs[0] = 0;
281 /* Check for imm instr */
282 if (op == imm)
283 IMM_ENABLE = 1;
284 else
285 IMM_ENABLE = 0;
286 }
287 else
cd09ab7c
MF
288 {
289 if (op == brki && IMM == 8)
290 {
291 RETREG = sim_syscall (cpu, CPU.regs[12], CPU.regs[5],
292 CPU.regs[6], CPU.regs[7],
293 CPU.regs[8]);
294 PC = RD + INST_SIZE;
295 }
296
297 /* no delay slot: increment cycle count */
298 bonus_cycles++;
299 }
bd30e45a
ME
300 }
301 }
302
303 if (tracing)
304 fprintf (stderr, "\n");
31557ecc
MF
305
306 if (sim_events_tick (sd))
307 sim_events_process (sd);
bd30e45a 308 }
bd30e45a
ME
309
310 /* Hide away the things we've cached while executing. */
311 /* CPU.pc = pc; */
312 CPU.insts += insts; /* instructions done ... */
313 CPU.cycles += insts; /* and each takes a cycle */
314 CPU.cycles += bonus_cycles; /* and extra cycles for branches */
315 CPU.cycles += memops; /* and memop cycle delays */
bd30e45a
ME
316}
317
e1211e55
MF
318static int
319microblaze_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
bd30e45a 320{
bd30e45a
ME
321 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
322 {
323 if (length == 4)
324 {
325 /* misalignment safe */
326 long ival = microblaze_extract_unsigned_integer (memory, 4);
327 if (rn < NUM_REGS)
328 CPU.regs[rn] = ival;
329 else
330 CPU.spregs[rn-NUM_REGS] = ival;
331 return 4;
332 }
333 else
334 return 0;
335 }
336 else
337 return 0;
338}
339
e1211e55
MF
340static int
341microblaze_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
bd30e45a
ME
342{
343 long ival;
2b4bc832 344
bd30e45a
ME
345 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
346 {
347 if (length == 4)
348 {
349 if (rn < NUM_REGS)
350 ival = CPU.regs[rn];
351 else
352 ival = CPU.spregs[rn-NUM_REGS];
353
354 /* misalignment-safe */
355 microblaze_store_unsigned_integer (memory, 4, ival);
356 return 4;
357 }
358 else
359 return 0;
360 }
361 else
362 return 0;
363}
364
bd30e45a
ME
365void
366sim_info (SIM_DESC sd, int verbose)
367{
2b4bc832
MF
368 SIM_CPU *cpu = STATE_CPU (sd, 0);
369 host_callback *callback = STATE_CALLBACK (sd);
370
bd30e45a
ME
371 callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
372 CPU.insts);
373 callback->printf_filtered (callback, "# cycles %10d\n",
374 (CPU.cycles) ? CPU.cycles+2 : 0);
bd30e45a
ME
375}
376
27b97b40
MF
377static sim_cia
378microblaze_pc_get (sim_cpu *cpu)
379{
380 return cpu->microblaze_cpu.spregs[0];
381}
382
383static void
384microblaze_pc_set (sim_cpu *cpu, sim_cia pc)
385{
386 cpu->microblaze_cpu.spregs[0] = pc;
387}
388
2b4bc832
MF
389static void
390free_state (SIM_DESC sd)
391{
392 if (STATE_MODULES (sd) != NULL)
393 sim_module_uninstall (sd);
394 sim_cpu_free_all (sd);
395 sim_state_free (sd);
396}
397
bd30e45a 398SIM_DESC
2e3d4f4d
MF
399sim_open (SIM_OPEN_KIND kind, host_callback *cb,
400 struct bfd *abfd, char * const *argv)
bd30e45a 401{
2b4bc832
MF
402 int i;
403 SIM_DESC sd = sim_state_alloc (kind, cb);
404 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
405
406 /* The cpu data is kept in a separately allocated chunk of memory. */
d5a71b11 407 if (sim_cpu_alloc_all (sd, 1) != SIM_RC_OK)
2b4bc832
MF
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 }
bd30e45a 418
77cf2ef5 419 /* The parser will print an error message for us, so we silently return. */
2b4bc832
MF
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,
428 (STATE_PROG_ARGV (sd) != NULL
429 ? *STATE_PROG_ARGV (sd)
430 : NULL), abfd) != SIM_RC_OK)
431 {
432 free_state (sd);
433 return 0;
434 }
435
436 /* Configure/verify the target byte order and other runtime
437 configuration options. */
438 if (sim_config (sd) != SIM_RC_OK)
439 {
440 sim_module_uninstall (sd);
441 return 0;
442 }
443
444 if (sim_post_argv_init (sd) != SIM_RC_OK)
445 {
446 /* Uninstall the modules to avoid memory leaks,
447 file descriptor leaks, etc. */
448 sim_module_uninstall (sd);
449 return 0;
450 }
bd30e45a 451
2b4bc832
MF
452 /* CPU specific initialization. */
453 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
454 {
455 SIM_CPU *cpu = STATE_CPU (sd, i);
2b4bc832 456
e1211e55
MF
457 CPU_REG_FETCH (cpu) = microblaze_reg_fetch;
458 CPU_REG_STORE (cpu) = microblaze_reg_store;
27b97b40
MF
459 CPU_PC_FETCH (cpu) = microblaze_pc_get;
460 CPU_PC_STORE (cpu) = microblaze_pc_set;
461
2b4bc832 462 set_initial_gprs (cpu);
2b4bc832 463 }
bd30e45a 464
c85fc610
MF
465 /* Default to a 8 Mbyte (== 2^23) memory space. */
466 sim_do_commandf (sd, "memory-size 0x800000");
467
2b4bc832 468 return sd;
bd30e45a
ME
469}
470
bd30e45a 471SIM_RC
2e3d4f4d
MF
472sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
473 char * const *argv, char * const *env)
bd30e45a 474{
2b4bc832 475 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a 476
bd30e45a
ME
477 PC = bfd_get_start_address (prog_bfd);
478
bd30e45a
ME
479 return SIM_RC_OK;
480}