Commit | Line | Data |
---|---|---|
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 | 36 | static unsigned long |
bd30e45a ME |
37 | microblaze_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 | 66 | static void |
bd30e45a ME |
67 | microblaze_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 | ||
2b4bc832 | 92 | /* TODO: Convert to common tracing framework. */ |
bd30e45a ME |
93 | static int issue_messages = 0; |
94 | ||
bd30e45a | 95 | static void /* INLINE */ |
2b4bc832 | 96 | wbat (SIM_CPU *cpu, word x, word v) |
bd30e45a ME |
97 | { |
98 | if (((uword)x) >= CPU.msize) | |
99 | { | |
100 | if (issue_messages) | |
101 | fprintf (stderr, "byte write to 0x%x outside memory range\n", x); | |
102 | ||
103 | CPU.exception = SIGSEGV; | |
104 | } | |
105 | else | |
106 | { | |
107 | unsigned char *p = CPU.memory + x; | |
108 | p[0] = v; | |
109 | } | |
110 | } | |
111 | ||
112 | static void /* INLINE */ | |
2b4bc832 | 113 | wlat (SIM_CPU *cpu, word x, word v) |
bd30e45a ME |
114 | { |
115 | if (((uword)x) >= CPU.msize) | |
116 | { | |
117 | if (issue_messages) | |
118 | fprintf (stderr, "word write to 0x%x outside memory range\n", x); | |
119 | ||
120 | CPU.exception = SIGSEGV; | |
121 | } | |
122 | else | |
123 | { | |
124 | if ((x & 3) != 0) | |
125 | { | |
126 | if (issue_messages) | |
127 | fprintf (stderr, "word write to unaligned memory address: 0x%x\n", x); | |
128 | ||
129 | CPU.exception = SIGBUS; | |
130 | } | |
131 | else if (!target_big_endian) | |
132 | { | |
133 | unsigned char *p = CPU.memory + x; | |
134 | p[3] = v >> 24; | |
135 | p[2] = v >> 16; | |
136 | p[1] = v >> 8; | |
137 | p[0] = v; | |
138 | } | |
139 | else | |
140 | { | |
141 | unsigned char *p = CPU.memory + x; | |
142 | p[0] = v >> 24; | |
143 | p[1] = v >> 16; | |
144 | p[2] = v >> 8; | |
145 | p[3] = v; | |
146 | } | |
147 | } | |
148 | } | |
149 | ||
150 | static void /* INLINE */ | |
2b4bc832 | 151 | what (SIM_CPU *cpu, word x, word v) |
bd30e45a ME |
152 | { |
153 | if (((uword)x) >= CPU.msize) | |
154 | { | |
155 | if (issue_messages) | |
156 | fprintf (stderr, "short write to 0x%x outside memory range\n", x); | |
157 | ||
158 | CPU.exception = SIGSEGV; | |
159 | } | |
160 | else | |
161 | { | |
162 | if ((x & 1) != 0) | |
163 | { | |
164 | if (issue_messages) | |
165 | fprintf (stderr, "short write to unaligned memory address: 0x%x\n", | |
166 | x); | |
167 | ||
168 | CPU.exception = SIGBUS; | |
169 | } | |
170 | else if (!target_big_endian) | |
171 | { | |
172 | unsigned char *p = CPU.memory + x; | |
173 | p[1] = v >> 8; | |
174 | p[0] = v; | |
175 | } | |
176 | else | |
177 | { | |
178 | unsigned char *p = CPU.memory + x; | |
179 | p[0] = v >> 8; | |
180 | p[1] = v; | |
181 | } | |
182 | } | |
183 | } | |
184 | ||
185 | /* Read functions. */ | |
186 | static int /* INLINE */ | |
2b4bc832 | 187 | rbat (SIM_CPU *cpu, word x) |
bd30e45a ME |
188 | { |
189 | if (((uword)x) >= CPU.msize) | |
190 | { | |
191 | if (issue_messages) | |
192 | fprintf (stderr, "byte read from 0x%x outside memory range\n", x); | |
193 | ||
194 | CPU.exception = SIGSEGV; | |
195 | return 0; | |
196 | } | |
197 | else | |
198 | { | |
199 | unsigned char *p = CPU.memory + x; | |
200 | return p[0]; | |
201 | } | |
202 | } | |
203 | ||
204 | static int /* INLINE */ | |
2b4bc832 | 205 | rlat (SIM_CPU *cpu, word x) |
bd30e45a ME |
206 | { |
207 | if (((uword) x) >= CPU.msize) | |
208 | { | |
209 | if (issue_messages) | |
210 | fprintf (stderr, "word read from 0x%x outside memory range\n", x); | |
211 | ||
212 | CPU.exception = SIGSEGV; | |
213 | return 0; | |
214 | } | |
215 | else | |
216 | { | |
217 | if ((x & 3) != 0) | |
218 | { | |
219 | if (issue_messages) | |
220 | fprintf (stderr, "word read from unaligned address: 0x%x\n", x); | |
221 | ||
222 | CPU.exception = SIGBUS; | |
223 | return 0; | |
224 | } | |
225 | else if (! target_big_endian) | |
226 | { | |
227 | unsigned char *p = CPU.memory + x; | |
228 | return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; | |
229 | } | |
230 | else | |
231 | { | |
232 | unsigned char *p = CPU.memory + x; | |
233 | return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; | |
234 | } | |
235 | } | |
236 | } | |
237 | ||
238 | static int /* INLINE */ | |
2b4bc832 | 239 | rhat (SIM_CPU *cpu, word x) |
bd30e45a ME |
240 | { |
241 | if (((uword)x) >= CPU.msize) | |
242 | { | |
243 | if (issue_messages) | |
244 | fprintf (stderr, "short read from 0x%x outside memory range\n", x); | |
245 | ||
246 | CPU.exception = SIGSEGV; | |
247 | return 0; | |
248 | } | |
249 | else | |
250 | { | |
251 | if ((x & 1) != 0) | |
252 | { | |
253 | if (issue_messages) | |
254 | fprintf (stderr, "short read from unaligned address: 0x%x\n", x); | |
255 | ||
256 | CPU.exception = SIGBUS; | |
257 | return 0; | |
258 | } | |
259 | else if (!target_big_endian) | |
260 | { | |
261 | unsigned char *p = CPU.memory + x; | |
262 | return (p[1] << 8) | p[0]; | |
263 | } | |
264 | else | |
265 | { | |
266 | unsigned char *p = CPU.memory + x; | |
267 | return (p[0] << 8) | p[1]; | |
268 | } | |
269 | } | |
270 | } | |
271 | ||
2b4bc832 | 272 | /* TODO: Delete all sim_size and use common memory functions. */ |
bd30e45a ME |
273 | /* Default to a 8 Mbyte (== 2^23) memory space. */ |
274 | static int sim_memory_size = 1 << 23; | |
275 | ||
276 | #define MEM_SIZE_FLOOR 64 | |
2b4bc832 MF |
277 | static void |
278 | sim_size (SIM_CPU *cpu, int size) | |
bd30e45a ME |
279 | { |
280 | sim_memory_size = size; | |
281 | CPU.msize = sim_memory_size; | |
282 | ||
283 | if (CPU.memory) | |
284 | free (CPU.memory); | |
285 | ||
286 | CPU.memory = (unsigned char *) calloc (1, CPU.msize); | |
287 | ||
288 | if (!CPU.memory) | |
289 | { | |
290 | if (issue_messages) | |
291 | fprintf (stderr, | |
ba8e7d1e | 292 | "Not enough VM for simulation of %ld bytes of RAM\n", |
bd30e45a ME |
293 | CPU.msize); |
294 | ||
295 | CPU.msize = 1; | |
296 | CPU.memory = (unsigned char *) calloc (1, 1); | |
297 | } | |
298 | } | |
299 | ||
300 | static void | |
2b4bc832 | 301 | init_pointers (SIM_CPU *cpu) |
bd30e45a ME |
302 | { |
303 | if (CPU.msize != (sim_memory_size)) | |
2b4bc832 | 304 | sim_size (cpu, sim_memory_size); |
bd30e45a ME |
305 | } |
306 | ||
307 | static void | |
2b4bc832 | 308 | set_initial_gprs (SIM_CPU *cpu) |
bd30e45a ME |
309 | { |
310 | int i; | |
311 | long space; | |
312 | unsigned long memsize; | |
313 | ||
2b4bc832 | 314 | init_pointers (cpu); |
bd30e45a ME |
315 | |
316 | /* Set up machine just out of reset. */ | |
317 | PC = 0; | |
318 | MSR = 0; | |
319 | ||
320 | memsize = CPU.msize / (1024 * 1024); | |
321 | ||
322 | if (issue_messages > 1) | |
ba8e7d1e | 323 | fprintf (stderr, "Simulated memory of %ld Mbytes (0x0 .. 0x%08lx)\n", |
bd30e45a ME |
324 | memsize, CPU.msize - 1); |
325 | ||
326 | /* Clean out the GPRs */ | |
327 | for (i = 0; i < 32; i++) | |
328 | CPU.regs[i] = 0; | |
329 | CPU.insts = 0; | |
330 | CPU.cycles = 0; | |
331 | CPU.imm_enable = 0; | |
bd30e45a ME |
332 | } |
333 | ||
bd30e45a ME |
334 | static int tracing = 0; |
335 | ||
336 | void | |
337 | sim_resume (SIM_DESC sd, int step, int siggnal) | |
338 | { | |
2b4bc832 | 339 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
bd30e45a ME |
340 | int needfetch; |
341 | word inst; | |
342 | enum microblaze_instr op; | |
bd30e45a ME |
343 | int memops; |
344 | int bonus_cycles; | |
345 | int insts; | |
346 | int w; | |
347 | int cycs; | |
348 | word WLhash; | |
349 | ubyte carry; | |
350 | int imm_unsigned; | |
351 | short ra, rb, rd; | |
352 | long immword; | |
353 | uword oldpc, newpc; | |
354 | short delay_slot_enable; | |
355 | short branch_taken; | |
356 | short num_delay_slot; /* UNUSED except as reqd parameter */ | |
357 | enum microblaze_instr_type insn_type; | |
358 | ||
bd30e45a ME |
359 | CPU.exception = step ? SIGTRAP : 0; |
360 | ||
361 | memops = 0; | |
362 | bonus_cycles = 0; | |
363 | insts = 0; | |
ba14f941 | 364 | |
bd30e45a ME |
365 | do |
366 | { | |
367 | /* Fetch the initial instructions that we'll decode. */ | |
2b4bc832 | 368 | inst = rlat (cpu, PC & 0xFFFFFFFC); |
bd30e45a | 369 | |
ba14f941 | 370 | op = get_insn_microblaze (inst, &imm_unsigned, &insn_type, |
bd30e45a ME |
371 | &num_delay_slot); |
372 | ||
373 | if (op == invalid_inst) | |
374 | fprintf (stderr, "Unknown instruction 0x%04x", inst); | |
375 | ||
376 | if (tracing) | |
377 | fprintf (stderr, "%.4x: inst = %.4x ", PC, inst); | |
378 | ||
379 | rd = GET_RD; | |
380 | rb = GET_RB; | |
381 | ra = GET_RA; | |
382 | /* immword = IMM_W; */ | |
383 | ||
384 | oldpc = PC; | |
385 | delay_slot_enable = 0; | |
386 | branch_taken = 0; | |
387 | if (op == microblaze_brk) | |
388 | CPU.exception = SIGTRAP; | |
389 | else if (inst == MICROBLAZE_HALT_INST) | |
390 | { | |
391 | CPU.exception = SIGQUIT; | |
392 | insts += 1; | |
393 | bonus_cycles++; | |
394 | } | |
395 | else | |
396 | { | |
397 | switch(op) | |
398 | { | |
399 | #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \ | |
400 | case NAME: \ | |
401 | ACTION; \ | |
402 | break; | |
403 | #include "microblaze.isa" | |
404 | #undef INSTRUCTION | |
405 | ||
406 | default: | |
407 | CPU.exception = SIGILL; | |
408 | fprintf (stderr, "ERROR: Unknown opcode\n"); | |
409 | } | |
410 | /* Make R0 consistent */ | |
411 | CPU.regs[0] = 0; | |
412 | ||
413 | /* Check for imm instr */ | |
414 | if (op == imm) | |
415 | IMM_ENABLE = 1; | |
416 | else | |
417 | IMM_ENABLE = 0; | |
418 | ||
419 | /* Update cycle counts */ | |
420 | insts ++; | |
421 | if (insn_type == memory_store_inst || insn_type == memory_load_inst) | |
422 | memops++; | |
423 | if (insn_type == mult_inst) | |
424 | bonus_cycles++; | |
425 | if (insn_type == barrel_shift_inst) | |
426 | bonus_cycles++; | |
427 | if (insn_type == anyware_inst) | |
428 | bonus_cycles++; | |
429 | if (insn_type == div_inst) | |
430 | bonus_cycles += 33; | |
431 | ||
432 | if ((insn_type == branch_inst || insn_type == return_inst) | |
ba14f941 | 433 | && branch_taken) |
bd30e45a ME |
434 | { |
435 | /* Add an extra cycle for taken branches */ | |
436 | bonus_cycles++; | |
437 | /* For branch instructions handle the instruction in the delay slot */ | |
ba14f941 | 438 | if (delay_slot_enable) |
bd30e45a ME |
439 | { |
440 | newpc = PC; | |
441 | PC = oldpc + INST_SIZE; | |
2b4bc832 | 442 | inst = rlat (cpu, PC & 0xFFFFFFFC); |
bd30e45a ME |
443 | op = get_insn_microblaze (inst, &imm_unsigned, &insn_type, |
444 | &num_delay_slot); | |
445 | if (op == invalid_inst) | |
446 | fprintf (stderr, "Unknown instruction 0x%04x", inst); | |
447 | if (tracing) | |
448 | fprintf (stderr, "%.4x: inst = %.4x ", PC, inst); | |
449 | rd = GET_RD; | |
450 | rb = GET_RB; | |
451 | ra = GET_RA; | |
452 | /* immword = IMM_W; */ | |
453 | if (op == microblaze_brk) | |
454 | { | |
455 | if (issue_messages) | |
456 | fprintf (stderr, "Breakpoint set in delay slot " | |
457 | "(at address 0x%x) will not be honored\n", PC); | |
458 | /* ignore the breakpoint */ | |
459 | } | |
460 | else if (insn_type == branch_inst || insn_type == return_inst) | |
461 | { | |
462 | if (issue_messages) | |
463 | fprintf (stderr, "Cannot have branch or return instructions " | |
464 | "in delay slot (at address 0x%x)\n", PC); | |
465 | CPU.exception = SIGILL; | |
466 | } | |
467 | else | |
468 | { | |
469 | switch(op) | |
470 | { | |
471 | #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION) \ | |
472 | case NAME: \ | |
473 | ACTION; \ | |
474 | break; | |
475 | #include "microblaze.isa" | |
476 | #undef INSTRUCTION | |
477 | ||
478 | default: | |
479 | CPU.exception = SIGILL; | |
480 | fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC); | |
481 | } | |
482 | /* Update cycle counts */ | |
483 | insts++; | |
484 | if (insn_type == memory_store_inst | |
ba14f941 | 485 | || insn_type == memory_load_inst) |
bd30e45a ME |
486 | memops++; |
487 | if (insn_type == mult_inst) | |
488 | bonus_cycles++; | |
489 | if (insn_type == barrel_shift_inst) | |
490 | bonus_cycles++; | |
491 | if (insn_type == anyware_inst) | |
492 | bonus_cycles++; | |
493 | if (insn_type == div_inst) | |
494 | bonus_cycles += 33; | |
495 | } | |
496 | /* Restore the PC */ | |
497 | PC = newpc; | |
498 | /* Make R0 consistent */ | |
499 | CPU.regs[0] = 0; | |
500 | /* Check for imm instr */ | |
501 | if (op == imm) | |
502 | IMM_ENABLE = 1; | |
503 | else | |
504 | IMM_ENABLE = 0; | |
505 | } | |
506 | else | |
507 | /* no delay slot: increment cycle count */ | |
508 | bonus_cycles++; | |
509 | } | |
510 | } | |
511 | ||
512 | if (tracing) | |
513 | fprintf (stderr, "\n"); | |
514 | } | |
515 | while (!CPU.exception); | |
516 | ||
517 | /* Hide away the things we've cached while executing. */ | |
518 | /* CPU.pc = pc; */ | |
519 | CPU.insts += insts; /* instructions done ... */ | |
520 | CPU.cycles += insts; /* and each takes a cycle */ | |
521 | CPU.cycles += bonus_cycles; /* and extra cycles for branches */ | |
522 | CPU.cycles += memops; /* and memop cycle delays */ | |
bd30e45a ME |
523 | } |
524 | ||
525 | ||
526 | int | |
5558e7e6 | 527 | sim_write (SIM_DESC sd, SIM_ADDR addr, const unsigned char *buffer, int size) |
bd30e45a | 528 | { |
2b4bc832 | 529 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
bd30e45a | 530 | int i; |
2b4bc832 MF |
531 | |
532 | init_pointers (cpu); | |
bd30e45a ME |
533 | |
534 | memcpy (&CPU.memory[addr], buffer, size); | |
535 | ||
536 | return size; | |
537 | } | |
538 | ||
539 | int | |
540 | sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size) | |
541 | { | |
2b4bc832 | 542 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
bd30e45a | 543 | int i; |
2b4bc832 MF |
544 | |
545 | init_pointers (cpu); | |
bd30e45a ME |
546 | |
547 | memcpy (buffer, &CPU.memory[addr], size); | |
548 | ||
549 | return size; | |
550 | } | |
551 | ||
552 | ||
553 | int | |
554 | sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length) | |
555 | { | |
2b4bc832 MF |
556 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
557 | ||
558 | init_pointers (cpu); | |
bd30e45a ME |
559 | |
560 | if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0) | |
561 | { | |
562 | if (length == 4) | |
563 | { | |
564 | /* misalignment safe */ | |
565 | long ival = microblaze_extract_unsigned_integer (memory, 4); | |
566 | if (rn < NUM_REGS) | |
567 | CPU.regs[rn] = ival; | |
568 | else | |
569 | CPU.spregs[rn-NUM_REGS] = ival; | |
570 | return 4; | |
571 | } | |
572 | else | |
573 | return 0; | |
574 | } | |
575 | else | |
576 | return 0; | |
577 | } | |
578 | ||
579 | int | |
580 | sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length) | |
581 | { | |
2b4bc832 | 582 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
bd30e45a | 583 | long ival; |
2b4bc832 MF |
584 | |
585 | init_pointers (cpu); | |
bd30e45a ME |
586 | |
587 | if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0) | |
588 | { | |
589 | if (length == 4) | |
590 | { | |
591 | if (rn < NUM_REGS) | |
592 | ival = CPU.regs[rn]; | |
593 | else | |
594 | ival = CPU.spregs[rn-NUM_REGS]; | |
595 | ||
596 | /* misalignment-safe */ | |
597 | microblaze_store_unsigned_integer (memory, 4, ival); | |
598 | return 4; | |
599 | } | |
600 | else | |
601 | return 0; | |
602 | } | |
603 | else | |
604 | return 0; | |
605 | } | |
606 | ||
bd30e45a ME |
607 | void |
608 | sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc) | |
609 | { | |
2b4bc832 MF |
610 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
611 | ||
bd30e45a ME |
612 | if (CPU.exception == SIGQUIT) |
613 | { | |
614 | *reason = sim_exited; | |
615 | *sigrc = RETREG; | |
616 | } | |
617 | else | |
618 | { | |
619 | *reason = sim_stopped; | |
620 | *sigrc = CPU.exception; | |
621 | } | |
622 | } | |
623 | ||
bd30e45a ME |
624 | void |
625 | sim_info (SIM_DESC sd, int verbose) | |
626 | { | |
2b4bc832 MF |
627 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
628 | host_callback *callback = STATE_CALLBACK (sd); | |
629 | ||
bd30e45a ME |
630 | callback->printf_filtered (callback, "\n\n# instructions executed %10d\n", |
631 | CPU.insts); | |
632 | callback->printf_filtered (callback, "# cycles %10d\n", | |
633 | (CPU.cycles) ? CPU.cycles+2 : 0); | |
bd30e45a ME |
634 | } |
635 | ||
2b4bc832 MF |
636 | static void |
637 | free_state (SIM_DESC sd) | |
638 | { | |
639 | if (STATE_MODULES (sd) != NULL) | |
640 | sim_module_uninstall (sd); | |
641 | sim_cpu_free_all (sd); | |
642 | sim_state_free (sd); | |
643 | } | |
644 | ||
bd30e45a ME |
645 | SIM_DESC |
646 | sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv) | |
647 | { | |
2b4bc832 MF |
648 | int i; |
649 | SIM_DESC sd = sim_state_alloc (kind, cb); | |
650 | SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); | |
651 | ||
652 | /* The cpu data is kept in a separately allocated chunk of memory. */ | |
653 | if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK) | |
654 | { | |
655 | free_state (sd); | |
656 | return 0; | |
657 | } | |
658 | ||
659 | if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) | |
660 | { | |
661 | free_state (sd); | |
662 | return 0; | |
663 | } | |
bd30e45a | 664 | |
2b4bc832 MF |
665 | /* getopt will print the error message so we just have to exit if this fails. |
666 | FIXME: Hmmm... in the case of gdb we need getopt to call | |
667 | print_filtered. */ | |
668 | if (sim_parse_args (sd, argv) != SIM_RC_OK) | |
669 | { | |
670 | free_state (sd); | |
671 | return 0; | |
672 | } | |
673 | ||
674 | /* Check for/establish the a reference program image. */ | |
675 | if (sim_analyze_program (sd, | |
676 | (STATE_PROG_ARGV (sd) != NULL | |
677 | ? *STATE_PROG_ARGV (sd) | |
678 | : NULL), abfd) != SIM_RC_OK) | |
679 | { | |
680 | free_state (sd); | |
681 | return 0; | |
682 | } | |
683 | ||
684 | /* Configure/verify the target byte order and other runtime | |
685 | configuration options. */ | |
686 | if (sim_config (sd) != SIM_RC_OK) | |
687 | { | |
688 | sim_module_uninstall (sd); | |
689 | return 0; | |
690 | } | |
691 | ||
692 | if (sim_post_argv_init (sd) != SIM_RC_OK) | |
693 | { | |
694 | /* Uninstall the modules to avoid memory leaks, | |
695 | file descriptor leaks, etc. */ | |
696 | sim_module_uninstall (sd); | |
697 | return 0; | |
698 | } | |
bd30e45a ME |
699 | |
700 | if (kind == SIM_OPEN_STANDALONE) | |
701 | issue_messages = 1; | |
702 | ||
2b4bc832 MF |
703 | /* CPU specific initialization. */ |
704 | for (i = 0; i < MAX_NR_PROCESSORS; ++i) | |
705 | { | |
706 | SIM_CPU *cpu = STATE_CPU (sd, i); | |
707 | int osize = sim_memory_size; | |
708 | ||
709 | set_initial_gprs (cpu); | |
bd30e45a | 710 | |
2b4bc832 MF |
711 | /* Discard and reacquire memory -- start with a clean slate. */ |
712 | sim_size (cpu, 1); /* small */ | |
713 | sim_size (cpu, osize); /* and back again */ | |
714 | } | |
bd30e45a | 715 | |
2b4bc832 | 716 | return sd; |
bd30e45a ME |
717 | } |
718 | ||
719 | void | |
720 | sim_close (SIM_DESC sd, int quitting) | |
721 | { | |
2b4bc832 | 722 | /* Do nothing. */ |
bd30e45a ME |
723 | } |
724 | ||
725 | SIM_RC | |
726 | sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env) | |
727 | { | |
2b4bc832 | 728 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
bd30e45a | 729 | |
bd30e45a ME |
730 | PC = bfd_get_start_address (prog_bfd); |
731 | ||
bd30e45a ME |
732 | return SIM_RC_OK; |
733 | } | |
734 | ||
bd30e45a | 735 | void |
60d847df | 736 | sim_do_command (SIM_DESC sd, const char *cmd) |
bd30e45a | 737 | { |
2b4bc832 MF |
738 | SIM_CPU *cpu = STATE_CPU (sd, 0); |
739 | ||
bd30e45a ME |
740 | /* Nothing there yet; it's all an error. */ |
741 | ||
742 | if (cmd != NULL) | |
743 | { | |
744 | char ** simargv = buildargv (cmd); | |
745 | ||
97eca187 | 746 | if (strcmp (simargv[0], "dumpmem") == 0) |
bd30e45a ME |
747 | { |
748 | unsigned char * p; | |
749 | FILE * dumpfile; | |
750 | ||
751 | if (simargv[1] == NULL) | |
752 | fprintf (stderr, "Error: missing argument to dumpmem cmd.\n"); | |
753 | ||
754 | fprintf (stderr, "Writing dumpfile %s...",simargv[1]); | |
755 | ||
756 | dumpfile = fopen (simargv[1], "w"); | |
757 | p = CPU.memory; | |
758 | fwrite (p, CPU.msize-1, 1, dumpfile); | |
759 | fclose (dumpfile); | |
760 | ||
761 | fprintf (stderr, "done.\n"); | |
762 | } | |
763 | else if (strcmp (simargv[0], "clearstats") == 0) | |
764 | { | |
765 | CPU.cycles = 0; | |
766 | CPU.insts = 0; | |
bd30e45a ME |
767 | } |
768 | else if (strcmp (simargv[0], "verbose") == 0) | |
769 | { | |
770 | issue_messages = 2; | |
771 | } | |
772 | else | |
773 | { | |
774 | fprintf (stderr,"Error: \"%s\" is not a valid M.CORE simulator command.\n", | |
775 | cmd); | |
776 | } | |
907c4910 CG |
777 | |
778 | freeargv (simargv); | |
bd30e45a ME |
779 | } |
780 | else | |
781 | { | |
782 | fprintf (stderr, "M.CORE sim commands: \n"); | |
bd30e45a ME |
783 | fprintf (stderr, " dumpmem <filename>\n"); |
784 | fprintf (stderr, " clearstats\n"); | |
785 | fprintf (stderr, " verbose\n"); | |
786 | } | |
787 | } |