Remove i386_elf_emit_arch_note
[deliverable/binutils-gdb.git] / sim / microblaze / interp.c
CommitLineData
bd30e45a 1/* Simulator for Xilinx MicroBlaze processor
32d0add0 2 Copyright 2009-2015 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
2b4bc832 34#define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
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
113sim_resume (SIM_DESC sd, int step, int siggnal)
114{
2b4bc832 115 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a
ME
116 int needfetch;
117 word inst;
118 enum microblaze_instr op;
bd30e45a
ME
119 int memops;
120 int bonus_cycles;
121 int insts;
122 int w;
123 int cycs;
124 word WLhash;
125 ubyte carry;
126 int imm_unsigned;
127 short ra, rb, rd;
128 long immword;
129 uword oldpc, newpc;
130 short delay_slot_enable;
131 short branch_taken;
132 short num_delay_slot; /* UNUSED except as reqd parameter */
133 enum microblaze_instr_type insn_type;
134
bd30e45a
ME
135 CPU.exception = step ? SIGTRAP : 0;
136
137 memops = 0;
138 bonus_cycles = 0;
139 insts = 0;
ba14f941 140
bd30e45a
ME
141 do
142 {
143 /* Fetch the initial instructions that we'll decode. */
c85fc610 144 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a 145
ba14f941 146 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
bd30e45a
ME
147 &num_delay_slot);
148
149 if (op == invalid_inst)
150 fprintf (stderr, "Unknown instruction 0x%04x", inst);
151
152 if (tracing)
153 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
154
155 rd = GET_RD;
156 rb = GET_RB;
157 ra = GET_RA;
158 /* immword = IMM_W; */
159
160 oldpc = PC;
161 delay_slot_enable = 0;
162 branch_taken = 0;
163 if (op == microblaze_brk)
164 CPU.exception = SIGTRAP;
165 else if (inst == MICROBLAZE_HALT_INST)
166 {
167 CPU.exception = SIGQUIT;
168 insts += 1;
169 bonus_cycles++;
170 }
171 else
172 {
173 switch(op)
174 {
175#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
176 case NAME: \
177 ACTION; \
178 break;
179#include "microblaze.isa"
180#undef INSTRUCTION
181
182 default:
183 CPU.exception = SIGILL;
184 fprintf (stderr, "ERROR: Unknown opcode\n");
185 }
186 /* Make R0 consistent */
187 CPU.regs[0] = 0;
188
189 /* Check for imm instr */
190 if (op == imm)
191 IMM_ENABLE = 1;
192 else
193 IMM_ENABLE = 0;
194
195 /* Update cycle counts */
196 insts ++;
197 if (insn_type == memory_store_inst || insn_type == memory_load_inst)
198 memops++;
199 if (insn_type == mult_inst)
200 bonus_cycles++;
201 if (insn_type == barrel_shift_inst)
202 bonus_cycles++;
203 if (insn_type == anyware_inst)
204 bonus_cycles++;
205 if (insn_type == div_inst)
206 bonus_cycles += 33;
207
208 if ((insn_type == branch_inst || insn_type == return_inst)
ba14f941 209 && branch_taken)
bd30e45a
ME
210 {
211 /* Add an extra cycle for taken branches */
212 bonus_cycles++;
213 /* For branch instructions handle the instruction in the delay slot */
ba14f941 214 if (delay_slot_enable)
bd30e45a
ME
215 {
216 newpc = PC;
217 PC = oldpc + INST_SIZE;
c85fc610 218 inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
bd30e45a
ME
219 op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
220 &num_delay_slot);
221 if (op == invalid_inst)
222 fprintf (stderr, "Unknown instruction 0x%04x", inst);
223 if (tracing)
224 fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
225 rd = GET_RD;
226 rb = GET_RB;
227 ra = GET_RA;
228 /* immword = IMM_W; */
229 if (op == microblaze_brk)
230 {
c85fc610 231 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
232 fprintf (stderr, "Breakpoint set in delay slot "
233 "(at address 0x%x) will not be honored\n", PC);
234 /* ignore the breakpoint */
235 }
236 else if (insn_type == branch_inst || insn_type == return_inst)
237 {
c85fc610 238 if (STATE_VERBOSE_P (sd))
bd30e45a
ME
239 fprintf (stderr, "Cannot have branch or return instructions "
240 "in delay slot (at address 0x%x)\n", PC);
241 CPU.exception = SIGILL;
242 }
243 else
244 {
245 switch(op)
246 {
247#define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \
248 case NAME: \
249 ACTION; \
250 break;
251#include "microblaze.isa"
252#undef INSTRUCTION
253
254 default:
255 CPU.exception = SIGILL;
256 fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC);
257 }
258 /* Update cycle counts */
259 insts++;
260 if (insn_type == memory_store_inst
ba14f941 261 || insn_type == memory_load_inst)
bd30e45a
ME
262 memops++;
263 if (insn_type == mult_inst)
264 bonus_cycles++;
265 if (insn_type == barrel_shift_inst)
266 bonus_cycles++;
267 if (insn_type == anyware_inst)
268 bonus_cycles++;
269 if (insn_type == div_inst)
270 bonus_cycles += 33;
271 }
272 /* Restore the PC */
273 PC = newpc;
274 /* Make R0 consistent */
275 CPU.regs[0] = 0;
276 /* Check for imm instr */
277 if (op == imm)
278 IMM_ENABLE = 1;
279 else
280 IMM_ENABLE = 0;
281 }
282 else
283 /* no delay slot: increment cycle count */
284 bonus_cycles++;
285 }
286 }
287
288 if (tracing)
289 fprintf (stderr, "\n");
290 }
291 while (!CPU.exception);
292
293 /* Hide away the things we've cached while executing. */
294 /* CPU.pc = pc; */
295 CPU.insts += insts; /* instructions done ... */
296 CPU.cycles += insts; /* and each takes a cycle */
297 CPU.cycles += bonus_cycles; /* and extra cycles for branches */
298 CPU.cycles += memops; /* and memop cycle delays */
bd30e45a
ME
299}
300
bd30e45a
ME
301int
302sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
303{
2b4bc832
MF
304 SIM_CPU *cpu = STATE_CPU (sd, 0);
305
bd30e45a
ME
306 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
307 {
308 if (length == 4)
309 {
310 /* misalignment safe */
311 long ival = microblaze_extract_unsigned_integer (memory, 4);
312 if (rn < NUM_REGS)
313 CPU.regs[rn] = ival;
314 else
315 CPU.spregs[rn-NUM_REGS] = ival;
316 return 4;
317 }
318 else
319 return 0;
320 }
321 else
322 return 0;
323}
324
325int
326sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
327{
2b4bc832 328 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a 329 long ival;
2b4bc832 330
bd30e45a
ME
331 if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
332 {
333 if (length == 4)
334 {
335 if (rn < NUM_REGS)
336 ival = CPU.regs[rn];
337 else
338 ival = CPU.spregs[rn-NUM_REGS];
339
340 /* misalignment-safe */
341 microblaze_store_unsigned_integer (memory, 4, ival);
342 return 4;
343 }
344 else
345 return 0;
346 }
347 else
348 return 0;
349}
350
bd30e45a
ME
351void
352sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc)
353{
2b4bc832
MF
354 SIM_CPU *cpu = STATE_CPU (sd, 0);
355
bd30e45a
ME
356 if (CPU.exception == SIGQUIT)
357 {
358 *reason = sim_exited;
359 *sigrc = RETREG;
360 }
361 else
362 {
363 *reason = sim_stopped;
364 *sigrc = CPU.exception;
365 }
366}
367
bd30e45a
ME
368void
369sim_info (SIM_DESC sd, int verbose)
370{
2b4bc832
MF
371 SIM_CPU *cpu = STATE_CPU (sd, 0);
372 host_callback *callback = STATE_CALLBACK (sd);
373
bd30e45a
ME
374 callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
375 CPU.insts);
376 callback->printf_filtered (callback, "# cycles %10d\n",
377 (CPU.cycles) ? CPU.cycles+2 : 0);
bd30e45a
ME
378}
379
27b97b40
MF
380static sim_cia
381microblaze_pc_get (sim_cpu *cpu)
382{
383 return cpu->microblaze_cpu.spregs[0];
384}
385
386static void
387microblaze_pc_set (sim_cpu *cpu, sim_cia pc)
388{
389 cpu->microblaze_cpu.spregs[0] = pc;
390}
391
2b4bc832
MF
392static void
393free_state (SIM_DESC sd)
394{
395 if (STATE_MODULES (sd) != NULL)
396 sim_module_uninstall (sd);
397 sim_cpu_free_all (sd);
398 sim_state_free (sd);
399}
400
bd30e45a
ME
401SIM_DESC
402sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
403{
2b4bc832
MF
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, /*cgen_cpu_max_extra_bytes ()*/0) != 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 }
bd30e45a 420
2b4bc832
MF
421 /* getopt will print the error message so we just have to exit if this fails.
422 FIXME: Hmmm... in the case of gdb we need getopt to call
423 print_filtered. */
424 if (sim_parse_args (sd, argv) != SIM_RC_OK)
425 {
426 free_state (sd);
427 return 0;
428 }
429
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)
435 {
436 free_state (sd);
437 return 0;
438 }
439
440 /* Configure/verify the target byte order and other runtime
441 configuration options. */
442 if (sim_config (sd) != SIM_RC_OK)
443 {
444 sim_module_uninstall (sd);
445 return 0;
446 }
447
448 if (sim_post_argv_init (sd) != SIM_RC_OK)
449 {
450 /* Uninstall the modules to avoid memory leaks,
451 file descriptor leaks, etc. */
452 sim_module_uninstall (sd);
453 return 0;
454 }
bd30e45a 455
2b4bc832
MF
456 /* CPU specific initialization. */
457 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
458 {
459 SIM_CPU *cpu = STATE_CPU (sd, i);
2b4bc832 460
27b97b40
MF
461 CPU_PC_FETCH (cpu) = microblaze_pc_get;
462 CPU_PC_STORE (cpu) = microblaze_pc_set;
463
2b4bc832 464 set_initial_gprs (cpu);
2b4bc832 465 }
bd30e45a 466
c85fc610
MF
467 /* Default to a 8 Mbyte (== 2^23) memory space. */
468 sim_do_commandf (sd, "memory-size 0x800000");
469
2b4bc832 470 return sd;
bd30e45a
ME
471}
472
473void
474sim_close (SIM_DESC sd, int quitting)
475{
2b4bc832 476 /* Do nothing. */
bd30e45a
ME
477}
478
479SIM_RC
480sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env)
481{
2b4bc832 482 SIM_CPU *cpu = STATE_CPU (sd, 0);
bd30e45a 483
bd30e45a
ME
484 PC = bfd_get_start_address (prog_bfd);
485
bd30e45a
ME
486 return SIM_RC_OK;
487}
This page took 0.279391 seconds and 4 git commands to generate.