]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/m68hc11_sim.c
* sim-main.h: Define cycle_to_string.
[thirdparty/binutils-gdb.git] / sim / m68hc11 / m68hc11_sim.c
CommitLineData
e0709f50
AC
1/* m6811_cpu.c -- 68HC11 CPU Emulation
2 Copyright 1999, 2000 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@worldnet.fr)
4
5This file is part of GDB, GAS, and the GNU binutils.
6
7GDB, GAS, and the GNU binutils are free software; you can redistribute
8them and/or modify them under the terms of the GNU General Public
9License as published by the Free Software Foundation; either version
101, or (at your option) any later version.
11
12GDB, GAS, and the GNU binutils are distributed in the hope that they
13will be useful, but WITHOUT ANY WARRANTY; without even the implied
14warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15the GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this file; see the file COPYING. If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21#include "sim-main.h"
22#include "sim-assert.h"
23#include "sim-module.h"
24#include "sim-options.h"
25
26void cpu_free_frame (sim_cpu* cpu, struct cpu_frame *frame);
27
28enum {
29 OPTION_CPU_RESET = OPTION_START,
30 OPTION_EMUL_OS,
31 OPTION_CPU_CONFIG,
32 OPTION_CPU_MODE
33};
34
35static DECLARE_OPTION_HANDLER (cpu_option_handler);
36
37static const OPTION cpu_options[] =
38{
39 { {"cpu-reset", no_argument, NULL, OPTION_CPU_RESET },
40 '\0', NULL, "Reset the CPU",
41 cpu_option_handler },
42
43 { {"emulos", no_argument, NULL, OPTION_EMUL_OS },
44 '\0', NULL, "Emulate some OS system calls (read, write, ...)",
45 cpu_option_handler },
46
47 { {"cpu-config", required_argument, NULL, OPTION_CPU_CONFIG },
48 '\0', NULL, "Specify the initial CPU configuration register",
49 cpu_option_handler },
50
51 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
52};
53
54
55static SIM_RC
56cpu_option_handler (SIM_DESC sd, sim_cpu *cpu,
57 int opt, char *arg, int is_command)
58{
59 sim_cpu *cpu;
60 int val;
61
62 cpu = STATE_CPU (sd, 0);
63 switch (opt)
64 {
65 case OPTION_CPU_RESET:
66 sim_board_reset (sd);
67 break;
68
69 case OPTION_EMUL_OS:
70 cpu->cpu_emul_syscall = 1;
71 break;
72
73 case OPTION_CPU_CONFIG:
74 if (sscanf(arg, "0x%x", &val) == 1
75 || sscanf(arg, "%d", &val) == 1)
76 {
77 cpu->cpu_config = val;
78 cpu->cpu_use_local_config = 1;
79 }
80 else
81 cpu->cpu_use_local_config = 0;
82 break;
83
84 case OPTION_CPU_MODE:
85 break;
86 }
87
88 return SIM_RC_OK;
89}
90
91/* Tentative to keep track of the cpu frame. */
92struct cpu_frame*
93cpu_find_frame (sim_cpu *cpu, uint16 sp)
94{
95 struct cpu_frame_list *flist;
96
97 flist = cpu->cpu_frames;
98 while (flist)
99 {
100 struct cpu_frame *frame;
101
102 frame = flist->frame;
103 while (frame)
104 {
105 if (frame->sp_low <= sp && frame->sp_high >= sp)
106 {
107 cpu->cpu_current_frame = flist;
108 return frame;
109 }
110
111 frame = frame->up;
112 }
113 flist = flist->next;
114 }
115 return 0;
116}
117
118struct cpu_frame_list*
119cpu_create_frame_list (sim_cpu *cpu)
120{
121 struct cpu_frame_list *flist;
122
123 flist = (struct cpu_frame_list*) malloc (sizeof (struct cpu_frame_list));
124 flist->frame = 0;
125 flist->next = cpu->cpu_frames;
126 flist->prev = 0;
127 if (flist->next)
128 flist->next->prev = flist;
129 cpu->cpu_frames = flist;
130 cpu->cpu_current_frame = flist;
131 return flist;
132}
133
134void
135cpu_remove_frame_list (sim_cpu *cpu, struct cpu_frame_list *flist)
136{
137 struct cpu_frame *frame;
138
139 if (flist->prev == 0)
140 cpu->cpu_frames = flist->next;
141 else
142 flist->prev->next = flist->next;
143 if (flist->next)
144 flist->next->prev = flist->prev;
145
146 frame = flist->frame;
147 while (frame)
148 {
149 struct cpu_frame* up = frame->up;
150 cpu_free_frame (cpu, frame);
151 frame = up;
152 }
153 free (flist);
154}
155
156
157struct cpu_frame*
158cpu_create_frame (sim_cpu *cpu, uint16 pc, uint16 sp)
159{
160 struct cpu_frame *frame;
161
162 frame = (struct cpu_frame*) malloc (sizeof(struct cpu_frame));
163 frame->up = 0;
164 frame->pc = pc;
165 frame->sp_low = sp;
166 frame->sp_high = sp;
167 return frame;
168}
169
170void
171cpu_free_frame (sim_cpu *cpu, struct cpu_frame *frame)
172{
173 free (frame);
174}
175
176uint16
177cpu_frame_reg (sim_cpu *cpu, uint16 rn)
178{
179 struct cpu_frame *frame;
180
181 if (cpu->cpu_current_frame == 0)
182 return 0;
183
184 frame = cpu->cpu_current_frame->frame;
185 while (frame)
186 {
187 if (rn == 0)
188 return frame->sp_high;
189 frame = frame->up;
190 rn--;
191 }
192 return 0;
193}
194
195void
196cpu_call (sim_cpu *cpu, uint16 addr)
197{
198#if HAVE_FRAME
199 uint16 pc = cpu->cpu_insn_pc;
200 uint16 sp;
201 struct cpu_frame_list *flist;
202 struct cpu_frame* frame;
203 struct cpu_frame* new_frame;
204#endif
205
206 cpu_set_pc (cpu, addr);
207#if HAVE_FRAME
208 sp = cpu_get_sp (cpu);
209
210 cpu->cpu_need_update_frame = 0;
211 flist = cpu->cpu_current_frame;
212 if (flist == 0)
213 flist = cpu_create_frame_list (cpu);
214
215 frame = flist->frame;
216 if (frame && frame->sp_low > sp)
217 frame->sp_low = sp;
218
219 new_frame = cpu_create_frame (cpu, pc, sp);
220 new_frame->up = frame;
221 flist->frame = new_frame;
222#endif
223}
224
225void
226cpu_update_frame (sim_cpu *cpu, int do_create)
227{
228#if HAVE_FRAME
229 struct cpu_frame *frame;
230
231 frame = cpu_find_frame (cpu, cpu_get_sp (cpu));
232 if (frame)
233 {
234 while (frame != cpu->cpu_current_frame->frame)
235 {
236 struct cpu_frame* up;
237
238 up = cpu->cpu_current_frame->frame->up;
239 cpu_free_frame (cpu, cpu->cpu_current_frame->frame);
240 cpu->cpu_current_frame->frame = up;
241 }
242 return;
243 }
244
245 if (do_create)
246 {
247 cpu_create_frame_list (cpu);
248 frame = cpu_create_frame (cpu, cpu_get_pc (cpu), cpu_get_sp (cpu));
249 cpu->cpu_current_frame->frame = frame;
250 }
251#endif
252}
253
254void
255cpu_return (sim_cpu *cpu)
256{
257#if HAVE_FRAME
258 uint16 sp = cpu_get_sp (cpu);
259 struct cpu_frame *frame;
260 struct cpu_frame_list *flist;
261
262 cpu->cpu_need_update_frame = 0;
263 flist = cpu->cpu_current_frame;
264 if (flist && flist->frame && flist->frame->up)
265 {
266 frame = flist->frame->up;
267 if (frame->sp_low <= sp && frame->sp_high >= sp)
268 {
269 cpu_free_frame (cpu, flist->frame);
270 flist->frame = frame;
271 return;
272 }
273 }
274 cpu_update_frame (cpu, 1);
275#endif
276}
277
278void
279cpu_print_frame (SIM_DESC sd, sim_cpu *cpu)
280{
281 struct cpu_frame* frame;
282 int level = 0;
283
284 if (cpu->cpu_current_frame == 0 || cpu->cpu_current_frame->frame == 0)
285 {
286 sim_io_printf (sd, "No frame.\n");
287 return;
288 }
289 sim_io_printf (sd, " # PC SP-L SP-H\n");
290 frame = cpu->cpu_current_frame->frame;
291 while (frame)
292 {
293 sim_io_printf (sd, "%3d 0x%04x 0x%04x 0x%04x\n",
294 level, frame->pc, frame->sp_low, frame->sp_high);
295 frame = frame->up;
296 level++;
297 }
298}
299
300/* Set the stack pointer and re-compute the current frame. */
301void
302cpu_set_sp (sim_cpu *cpu, uint16 val)
303{
304 cpu->cpu_regs.sp = val;
305 cpu_update_frame (cpu, 0);
306}
307
308int
309cpu_initialize (SIM_DESC sd, sim_cpu *cpu)
310{
311 int result;
312
313 sim_add_option_table (sd, 0, cpu_options);
314
315 memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
316
317 cpu->cpu_absolute_cycle = 0;
318 cpu->cpu_current_cycle = 0;
319 cpu->cpu_emul_syscall = 1;
320 cpu->cpu_running = 1;
321 cpu->cpu_stop_on_interrupt = 0;
322 cpu->cpu_frequency = 8 * 1000 * 1000;
323 cpu->cpu_frames = 0;
324 cpu->cpu_current_frame = 0;
325 cpu->cpu_use_elf_start = 0;
326 cpu->cpu_elf_start = 0;
327 cpu->cpu_use_local_config = 0;
328 cpu->cpu_config = M6811_NOSEC | M6811_NOCOP | M6811_ROMON |
329 M6811_EEON;
330 result = interrupts_initialize (cpu);
331
332 cpu->cpu_is_initialized = 1;
333 return result;
334}
335
336
337/* Reinitialize the processor after a reset. */
338int
339cpu_reset (sim_cpu *cpu)
340{
341 cpu->cpu_need_update_frame = 0;
342 cpu->cpu_current_frame = 0;
343 while (cpu->cpu_frames)
344 cpu_remove_frame_list (cpu, cpu->cpu_frames);
345
346 /* Initialize the config register.
347 It is only initialized at reset time. */
348 memset (cpu->ios, 0, sizeof (cpu->ios));
349 cpu->ios[M6811_INIT] = 0x1;
350
351 /* Output compare registers set to 0xFFFF. */
352 cpu->ios[M6811_TOC1_H] = 0xFF;
353 cpu->ios[M6811_TOC1_L] = 0xFF;
354 cpu->ios[M6811_TOC2_H] = 0xFF;
355 cpu->ios[M6811_TOC2_L] = 0xFF;
356 cpu->ios[M6811_TOC3_H] = 0xFF;
357 cpu->ios[M6811_TOC4_L] = 0xFF;
358 cpu->ios[M6811_TOC5_H] = 0xFF;
359 cpu->ios[M6811_TOC5_L] = 0xFF;
360
361 /* Setup the processor registers. */
362 memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
363 cpu->cpu_absolute_cycle = 0;
364 cpu->cpu_current_cycle = 0;
365 cpu->cpu_is_initialized = 0;
366
367 /* Reinitialize the CPU operating mode. */
368 cpu->ios[M6811_HPRIO] = cpu->cpu_mode;
369 return 0;
370}
371
372/* Reinitialize the processor after a reset. */
373int
374cpu_restart (sim_cpu *cpu)
375{
376 uint16 addr;
377
378 /* Get CPU starting address depending on the CPU mode. */
379 if (cpu->cpu_use_elf_start == 0)
380 {
381 switch ((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA))
382 {
383 /* Single Chip */
384 default:
385 case 0 :
386 addr = memory_read16 (cpu, 0xFFFE);
387 break;
388
389 /* Expanded Multiplexed */
390 case M6811_MDA:
391 addr = memory_read16 (cpu, 0xFFFE);
392 break;
393
394 /* Special Bootstrap */
395 case M6811_SMOD:
396 addr = 0;
397 break;
398
399 /* Factory Test */
400 case M6811_MDA | M6811_SMOD:
401 addr = memory_read16 (cpu, 0xFFFE);
402 break;
403 }
404 }
405 else
406 {
407 addr = cpu->cpu_elf_start;
408 }
409
410 /* Setup the processor registers. */
411 cpu->cpu_insn_pc = addr;
412 cpu->cpu_regs.pc = addr;
413 cpu->cpu_regs.ccr = M6811_X_BIT | M6811_I_BIT | M6811_S_BIT;
414 cpu->cpu_absolute_cycle = 0;
415 cpu->cpu_is_initialized = 1;
416 cpu->cpu_current_cycle = 0;
417
418 cpu_call (cpu, addr);
419
420 return 0;
421}
422
423void
424print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, int mode)
425{
426 while (desc->mask)
427 {
428 if (val & desc->mask)
429 sim_io_printf (sd, "%s",
430 mode == 0 ? desc->short_name : desc->long_name);
431 desc++;
432 }
433}
434
435void
436print_io_byte (SIM_DESC sd, const char *name, io_reg_desc *desc,
437 uint8 val, uint16 addr)
438{
439 sim_io_printf (sd, " %-9.9s @ 0x%04x 0x%02x ", name, addr, val);
440 if (desc)
441 print_io_reg_desc (sd, desc, val, 0);
442}
443
444void
445cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val)
446{
447 cpu_set_ccr_V (proc, 0);
448 cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0);
449 cpu_set_ccr_Z (proc, val == 0 ? 1 : 0);
450}
451
452
453uint16
454cpu_fetch_relbranch (sim_cpu *cpu)
455{
456 uint16 addr = (uint16) cpu_fetch8 (cpu);
457
458 if (addr & 0x0080)
459 {
460 addr |= 0xFF00;
461 }
462 addr += cpu->cpu_regs.pc;
463 return addr;
464}
465
466
467/* Push all the CPU registers (when an interruption occurs). */
468void
469cpu_push_all (sim_cpu *cpu)
470{
471 cpu_push_uint16 (cpu, cpu->cpu_regs.pc);
472 cpu_push_uint16 (cpu, cpu->cpu_regs.iy);
473 cpu_push_uint16 (cpu, cpu->cpu_regs.ix);
474 cpu_push_uint16 (cpu, cpu->cpu_regs.d);
475 cpu_push_uint8 (cpu, cpu->cpu_regs.ccr);
476}
477
478
479/* Handle special instructions. */
480void
481cpu_special (sim_cpu *cpu, enum M6811_Special special)
482{
483 switch (special)
484 {
485 case M6811_RTI:
486 {
487 uint8 ccr;
488
489 ccr = cpu_pop_uint8 (cpu);
490 cpu_set_ccr (cpu, ccr);
491 cpu_set_d (cpu, cpu_pop_uint16 (cpu));
492 cpu_set_x (cpu, cpu_pop_uint16 (cpu));
493 cpu_set_y (cpu, cpu_pop_uint16 (cpu));
494 cpu_set_pc (cpu, cpu_pop_uint16 (cpu));
495 cpu_return (cpu);
496 break;
497 }
498
499 case M6811_WAI:
500 /* In the ELF-start mode, we are in a special mode where
501 the WAI corresponds to an exit. */
502 if (cpu->cpu_use_elf_start)
503 {
504 cpu_set_pc (cpu, cpu->cpu_insn_pc);
505 sim_engine_halt (CPU_STATE (cpu), cpu,
506 NULL, NULL_CIA, sim_exited,
507 cpu_get_d (cpu));
508 return;
509 }
510 /* SCz: not correct... */
511 cpu_push_all (cpu);
512 break;
513
514 case M6811_SWI:
515 interrupts_raise (&cpu->cpu_interrupts, M6811_INT_SWI);
516 interrupts_process (&cpu->cpu_interrupts);
517 break;
518
519 case M6811_EMUL_SYSCALL:
520 case M6811_ILLEGAL:
521 if (cpu->cpu_emul_syscall)
522 {
523 uint8 op = memory_read8 (cpu,
524 cpu_get_pc (cpu) - 1);
525 if (op == 0x41)
526 {
527 cpu_set_pc (cpu, cpu->cpu_insn_pc);
528 sim_engine_halt (CPU_STATE (cpu), cpu,
529 NULL, NULL_CIA, sim_exited,
530 cpu_get_d (cpu));
531 return;
532 }
533 else
534 {
535 emul_os (op, cpu);
536 }
537 return;
538 }
539
540 interrupts_raise (&cpu->cpu_interrupts, M6811_INT_ILLEGAL);
541 interrupts_process (&cpu->cpu_interrupts);
542 break;
543
544 case M6811_TEST:
545 {
546 SIM_DESC sd;
547
548 sd = CPU_STATE (cpu);
549
550 /* Breakpoint instruction if we are under gdb. */
551 if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
552 {
553 cpu->cpu_regs.pc --;
554 sim_engine_halt (CPU_STATE (cpu), cpu,
555 0, cpu_get_pc (cpu), sim_stopped,
556 SIM_SIGTRAP);
557 }
558 /* else this is a nop but not in test factory mode. */
559 break;
560 }
561 }
562}
563
564
565void
566cpu_single_step (sim_cpu *cpu)
567{
568 cpu->cpu_current_cycle = 0;
569 cpu->cpu_insn_pc = cpu_get_pc (cpu);
570
571 /* Handle the pending interrupts. If an interrupt is handled,
572 treat this as an single step. */
573 if (interrupts_process (&cpu->cpu_interrupts))
574 {
575 cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
576 return;
577 }
578
579 /* printf("PC = 0x%04x\n", cpu_get_pc (cpu));*/
580 cpu_interp (cpu);
581 cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
582}
583
584/* VARARGS */
585void
586sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep,
587 uint16 addr, const char *message, ...)
588{
589 char buf[1024];
590 va_list args;
591
592 va_start (args, message);
593 vsprintf (buf, message, args);
594 va_end (args);
595
596 printf("%s\n", buf);
597 cpu_memory_exception (cpu, excep, addr, buf);
598}
599
600
601void
602cpu_memory_exception (sim_cpu *cpu, SIM_SIGNAL excep,
603 uint16 addr, const char *message)
604{
605 if (cpu->cpu_running == 0)
606 return;
607
608 cpu_set_pc (cpu, cpu->cpu_insn_pc);
609 sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
610 cpu_get_pc (cpu), sim_stopped, excep);
611
612#if 0
613 cpu->mem_exception = excep;
614 cpu->fault_addr = addr;
615 cpu->fault_msg = strdup (message);
616
617 if (cpu->cpu_use_handler)
618 {
619 longjmp (&cpu->cpu_exception_handler, 1);
620 }
621 (* cpu->callback->printf_filtered)
622 (cpu->callback, "Fault at 0x%04x: %s\n", addr, message);
623#endif
624}
625
626void
627cpu_info (SIM_DESC sd, sim_cpu *cpu)
628{
629 sim_io_printf (sd, "CPU info:\n");
2990a9f4
SC
630 sim_io_printf (sd, " Absolute cycle: %s\n",
631 cycle_to_string (cpu, cpu->cpu_absolute_cycle));
632
e0709f50
AC
633 sim_io_printf (sd, " Syscall emulation: %s\n",
634 cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");
635 sim_io_printf (sd, " Memory errors detection: %s\n",
636 cpu->cpu_check_memory ? "yes" : "no");
637 sim_io_printf (sd, " Stop on interrupt: %s\n",
638 cpu->cpu_stop_on_interrupt ? "yes" : "no");
639}
640