]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/microblaze/interp.c
Update copyright year range in all GDB files.
[thirdparty/binutils-gdb.git] / sim / microblaze / interp.c
CommitLineData
bd30e45a 1/* Simulator for Xilinx MicroBlaze processor
42a4f53d 2 Copyright 2009-2019 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
MF
30#include "sim-options.h"
31
419c2fda 32#include "microblaze-dis.h"
bd30e45a 33
e7cd2680 34#define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
bd30e45a 35
feb703b3 36static unsigned long
bd30e45a
ME
37microblaze_extract_unsigned_integer (unsigned char *addr, int len)
38{
39 unsigned long retval;
40 unsigned char *p;
41 unsigned char *startaddr = (unsigned char *)addr;
42 unsigned char *endaddr = startaddr + len;
43
44 if (len > (int) sizeof (unsigned long))
45 printf ("That operation is not available on integers of more than "
3e95021c 46 "%zu bytes.", sizeof (unsigned long));
bd30e45a
ME
47
48 /* Start at the most significant end of the integer, and work towards
49 the least significant. */
50 retval = 0;
51
52 if (!target_big_endian)
53 {
54 for (p = endaddr; p > startaddr;)
55 retval = (retval << 8) | * -- p;
56 }
57 else
58 {
59 for (p = startaddr; p < endaddr;)
60 retval = (retval << 8) | * p ++;
61 }
62
63 return retval;
64}
65
feb703b3 66static void
bd30e45a
ME
67microblaze_store_unsigned_integer (unsigned char *addr, int len,
68 unsigned long val)
69{
70 unsigned char *p;
71 unsigned char *startaddr = (unsigned char *)addr;
72 unsigned char *endaddr = startaddr + len;
73
74 if (!target_big_endian)
75 {
76 for (p = startaddr; p < endaddr;)
77 {
78 *p++ = val & 0xff;
79 val >>= 8;
80 }
81 }
82 else
83 {
84 for (p = endaddr; p > startaddr;)
85 {
86 *--p = val & 0xff;
87 val >>= 8;
88 }
89 }
90}
91
bd30e45a 92static void
2b4bc832 93set_initial_gprs (SIM_CPU *cpu)
bd30e45a
ME
94{
95 int i;
96 long space;
bd30e45a
ME
97
98 /* Set up machine just out of reset. */
99 PC = 0;
100 MSR = 0;
101
bd30e45a
ME
102 /* Clean out the GPRs */
103 for (i = 0; i < 32; i++)
104 CPU.regs[i] = 0;
105 CPU.insts = 0;
106 CPU.cycles = 0;
107 CPU.imm_enable = 0;
bd30e45a
ME
108}
109
bd30e45a
ME
110static int tracing = 0;
111
112void
31557ecc
MF
113sim_engine_run (SIM_DESC sd,
114 int next_cpu_nr, /* ignore */
115 int nr_cpus, /* ignore */
116 int siggnal) /* ignore */
bd30e45a 117{
2b4bc832 118 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a
ME
119 int needfetch;
120 word inst;
121 enum microblaze_instr op;
bd30e45a
ME
122 int memops;
123 int bonus_cycles;
124 int insts;
125 int w;
126 int cycs;
127 word WLhash;
128 ubyte carry;
129 int imm_unsigned;
130 short ra, rb, rd;
131 long immword;
132 uword oldpc, newpc;
133 short delay_slot_enable;
134 short branch_taken;
135 short num_delay_slot; /* UNUSED except as reqd parameter */
136 enum microblaze_instr_type insn_type;
137
bd30e45a
ME
138 memops = 0;
139 bonus_cycles = 0;
140 insts = 0;
ba14f941 141
31557ecc 142 while (1)
bd30e45a
ME
143 {
144 /* Fetch the initial instructions that we'll decode. */
c85fc610 145 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a 146
ba14f941 147 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
bd30e45a
ME
148 &num_delay_slot);
149
150 if (op == invalid_inst)
151 fprintf (stderr, "Unknown instruction 0x%04x", inst);
152
153 if (tracing)
154 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
155
156 rd = GET_RD;
157 rb = GET_RB;
158 ra = GET_RA;
159 /* immword = IMM_W; */
160
161 oldpc = PC;
162 delay_slot_enable = 0;
163 branch_taken = 0;
164 if (op == microblaze_brk)
31557ecc 165 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
bd30e45a
ME
166 else if (inst == MICROBLAZE_HALT_INST)
167 {
bd30e45a
ME
168 insts += 1;
169 bonus_cycles++;
31557ecc 170 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_exited, RETREG);
bd30e45a
ME
171 }
172 else
173 {
174 switch(op)
175 {
176#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
177 case NAME: \
178 ACTION; \
179 break;
180#include "microblaze.isa"
181#undef INSTRUCTION
182
183 default:
31557ecc
MF
184 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
185 SIM_SIGILL);
bd30e45a
ME
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)
ba14f941 211 && branch_taken)
bd30e45a
ME
212 {
213 /* Add an extra cycle for taken branches */
214 bonus_cycles++;
215 /* For branch instructions handle the instruction in the delay slot */
ba14f941 216 if (delay_slot_enable)
bd30e45a
ME
217 {
218 newpc = PC;
219 PC = oldpc + INST_SIZE;
c85fc610 220 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a
ME
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 {
c85fc610 233 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
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 {
c85fc610 240 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
241 fprintf (stderr, "Cannot have branch or return instructions "
242 "in delay slot (at address 0x%x)\n", PC);
31557ecc
MF
243 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
244 SIM_SIGILL);
bd30e45a
ME
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:
31557ecc
MF
258 sim_engine_halt (sd, NULL, NULL, NULL_CIA,
259 sim_signalled, SIM_SIGILL);
bd30e45a
ME
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
ba14f941 265 || insn_type == memory_load_inst)
bd30e45a
ME
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 /* no delay slot: increment cycle count */
288 bonus_cycles++;
289 }
290 }
291
292 if (tracing)
293 fprintf (stderr, "\n");
31557ecc
MF
294
295 if (sim_events_tick (sd))
296 sim_events_process (sd);
bd30e45a 297 }
bd30e45a
ME
298
299 /* Hide away the things we've cached while executing. */
300 /* CPU.pc = pc; */
301 CPU.insts += insts; /* instructions done ... */
302 CPU.cycles += insts; /* and each takes a cycle */
303 CPU.cycles += bonus_cycles; /* and extra cycles for branches */
304 CPU.cycles += memops; /* and memop cycle delays */
bd30e45a
ME
305}
306
e1211e55
MF
307static int
308microblaze_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
bd30e45a 309{
bd30e45a
ME
310 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
311 {
312 if (length == 4)
313 {
314 /* misalignment safe */
315 long ival = microblaze_extract_unsigned_integer (memory, 4);
316 if (rn < NUM_REGS)
317 CPU.regs[rn] = ival;
318 else
319 CPU.spregs[rn-NUM_REGS] = ival;
320 return 4;
321 }
322 else
323 return 0;
324 }
325 else
326 return 0;
327}
328
e1211e55
MF
329static int
330microblaze_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
bd30e45a
ME
331{
332 long ival;
2b4bc832 333
bd30e45a
ME
334 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
335 {
336 if (length == 4)
337 {
338 if (rn < NUM_REGS)
339 ival = CPU.regs[rn];
340 else
341 ival = CPU.spregs[rn-NUM_REGS];
342
343 /* misalignment-safe */
344 microblaze_store_unsigned_integer (memory, 4, ival);
345 return 4;
346 }
347 else
348 return 0;
349 }
350 else
351 return 0;
352}
353
bd30e45a
ME
354void
355sim_info (SIM_DESC sd, int verbose)
356{
2b4bc832
MF
357 SIM_CPU *cpu = STATE_CPU (sd, 0);
358 host_callback *callback = STATE_CALLBACK (sd);
359
bd30e45a
ME
360 callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
361 CPU.insts);
362 callback->printf_filtered (callback, "# cycles %10d\n",
363 (CPU.cycles) ? CPU.cycles+2 : 0);
bd30e45a
ME
364}
365
27b97b40
MF
366static sim_cia
367microblaze_pc_get (sim_cpu *cpu)
368{
369 return cpu->microblaze_cpu.spregs[0];
370}
371
372static void
373microblaze_pc_set (sim_cpu *cpu, sim_cia pc)
374{
375 cpu->microblaze_cpu.spregs[0] = pc;
376}
377
2b4bc832
MF
378static void
379free_state (SIM_DESC sd)
380{
381 if (STATE_MODULES (sd) != NULL)
382 sim_module_uninstall (sd);
383 sim_cpu_free_all (sd);
384 sim_state_free (sd);
385}
386
bd30e45a 387SIM_DESC
2e3d4f4d
MF
388sim_open (SIM_OPEN_KIND kind, host_callback *cb,
389 struct bfd *abfd, char * const *argv)
bd30e45a 390{
2b4bc832
MF
391 int i;
392 SIM_DESC sd = sim_state_alloc (kind, cb);
393 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
394
395 /* The cpu data is kept in a separately allocated chunk of memory. */
396 if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
397 {
398 free_state (sd);
399 return 0;
400 }
401
402 if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
403 {
404 free_state (sd);
405 return 0;
406 }
bd30e45a 407
77cf2ef5 408 /* The parser will print an error message for us, so we silently return. */
2b4bc832
MF
409 if (sim_parse_args (sd, argv) != SIM_RC_OK)
410 {
411 free_state (sd);
412 return 0;
413 }
414
415 /* Check for/establish the a reference program image. */
416 if (sim_analyze_program (sd,
417 (STATE_PROG_ARGV (sd) != NULL
418 ? *STATE_PROG_ARGV (sd)
419 : NULL), abfd) != SIM_RC_OK)
420 {
421 free_state (sd);
422 return 0;
423 }
424
425 /* Configure/verify the target byte order and other runtime
426 configuration options. */
427 if (sim_config (sd) != SIM_RC_OK)
428 {
429 sim_module_uninstall (sd);
430 return 0;
431 }
432
433 if (sim_post_argv_init (sd) != SIM_RC_OK)
434 {
435 /* Uninstall the modules to avoid memory leaks,
436 file descriptor leaks, etc. */
437 sim_module_uninstall (sd);
438 return 0;
439 }
bd30e45a 440
2b4bc832
MF
441 /* CPU specific initialization. */
442 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
443 {
444 SIM_CPU *cpu = STATE_CPU (sd, i);
2b4bc832 445
e1211e55
MF
446 CPU_REG_FETCH (cpu) = microblaze_reg_fetch;
447 CPU_REG_STORE (cpu) = microblaze_reg_store;
27b97b40
MF
448 CPU_PC_FETCH (cpu) = microblaze_pc_get;
449 CPU_PC_STORE (cpu) = microblaze_pc_set;
450
2b4bc832 451 set_initial_gprs (cpu);
2b4bc832 452 }
bd30e45a 453
c85fc610
MF
454 /* Default to a 8 Mbyte (== 2^23) memory space. */
455 sim_do_commandf (sd, "memory-size 0x800000");
456
2b4bc832 457 return sd;
bd30e45a
ME
458}
459
bd30e45a 460SIM_RC
2e3d4f4d
MF
461sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
462 char * const *argv, char * const *env)
bd30e45a 463{
2b4bc832 464 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a 465
bd30e45a
ME
466 PC = bfd_get_start_address (prog_bfd);
467
bd30e45a
ME
468 return SIM_RC_OK;
469}