]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/m68hc11/m68hc11_sim.c
* interrupts.c (interrupts_reset): New function, setup interrupt
[thirdparty/binutils-gdb.git] / sim / m68hc11 / m68hc11_sim.c
1 /* m6811_cpu.c -- 68HC11&68HC12 CPU Emulation
2 Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@worldnet.fr)
4
5 This file is part of GDB, GAS, and the GNU binutils.
6
7 GDB, GAS, and the GNU binutils are free software; you can redistribute
8 them and/or modify them under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either version
10 1, or (at your option) any later version.
11
12 GDB, GAS, and the GNU binutils are distributed in the hope that they
13 will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING. If not, write to the Free
19 Software 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
26 void cpu_free_frame (sim_cpu* cpu, struct cpu_frame *frame);
27
28 enum {
29 OPTION_CPU_RESET = OPTION_START,
30 OPTION_EMUL_OS,
31 OPTION_CPU_CONFIG,
32 OPTION_CPU_MODE
33 };
34
35 static DECLARE_OPTION_HANDLER (cpu_option_handler);
36
37 static 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
55 static SIM_RC
56 cpu_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. */
92 struct cpu_frame*
93 cpu_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
118 struct cpu_frame_list*
119 cpu_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
134 void
135 cpu_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
157 struct cpu_frame*
158 cpu_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
170 void
171 cpu_free_frame (sim_cpu *cpu, struct cpu_frame *frame)
172 {
173 free (frame);
174 }
175
176 uint16
177 cpu_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
195 void
196 cpu_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
225 void
226 cpu_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
254 void
255 cpu_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
278 void
279 cpu_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. */
301 void
302 cpu_set_sp (sim_cpu *cpu, uint16 val)
303 {
304 cpu->cpu_regs.sp = val;
305 cpu_update_frame (cpu, 0);
306 }
307
308 uint16
309 cpu_get_reg (sim_cpu* cpu, uint8 reg)
310 {
311 switch (reg)
312 {
313 case 0:
314 return cpu_get_x (cpu);
315
316 case 1:
317 return cpu_get_y (cpu);
318
319 case 2:
320 return cpu_get_sp (cpu);
321
322 case 3:
323 return cpu_get_pc (cpu);
324
325 default:
326 return 0;
327 }
328 }
329
330 uint16
331 cpu_get_src_reg (sim_cpu* cpu, uint8 reg)
332 {
333 switch (reg)
334 {
335 case 0:
336 return cpu_get_a (cpu);
337
338 case 1:
339 return cpu_get_b (cpu);
340
341 case 2:
342 return cpu_get_ccr (cpu);
343
344 case 3:
345 return cpu_get_tmp3 (cpu);
346
347 case 4:
348 return cpu_get_d (cpu);
349
350 case 5:
351 return cpu_get_x (cpu);
352
353 case 6:
354 return cpu_get_y (cpu);
355
356 case 7:
357 return cpu_get_sp (cpu);
358
359 default:
360 return 0;
361 }
362 }
363
364 void
365 cpu_set_dst_reg (sim_cpu* cpu, uint8 reg, uint16 val)
366 {
367 switch (reg)
368 {
369 case 0:
370 cpu_set_a (cpu, val);
371 break;
372
373 case 1:
374 cpu_set_b (cpu, val);
375 break;
376
377 case 2:
378 cpu_set_ccr (cpu, val);
379 break;
380
381 case 3:
382 cpu_set_tmp2 (cpu, val);
383 break;
384
385 case 4:
386 cpu_set_d (cpu, val);
387 break;
388
389 case 5:
390 cpu_set_x (cpu, val);
391 break;
392
393 case 6:
394 cpu_set_y (cpu, val);
395 break;
396
397 case 7:
398 cpu_set_sp (cpu, val);
399 break;
400
401 default:
402 break;
403 }
404 }
405
406 void
407 cpu_set_reg (sim_cpu* cpu, uint8 reg, uint16 val)
408 {
409 switch (reg)
410 {
411 case 0:
412 cpu_set_x (cpu, val);
413 break;
414
415 case 1:
416 cpu_set_y (cpu, val);
417 break;
418
419 case 2:
420 cpu_set_sp (cpu, val);
421 break;
422
423 case 3:
424 cpu_set_pc (cpu, val);
425 break;
426
427 default:
428 break;
429 }
430 }
431
432 /* Returns the address of a 68HC12 indexed operand.
433 Pre and post modifications are handled on the source register. */
434 uint16
435 cpu_get_indexed_operand_addr (sim_cpu* cpu, int restrict)
436 {
437 uint8 reg;
438 uint16 sval;
439 uint16 addr;
440 uint8 code;
441
442 code = cpu_fetch8 (cpu);
443
444 /* n,r with 5-bit signed constant. */
445 if ((code & 0x20) == 0)
446 {
447 reg = (code >> 6) & 3;
448 sval = (code & 0x1f);
449 if (code & 0x10)
450 sval |= 0xfff0;
451
452 addr = cpu_get_reg (cpu, reg);
453 addr += sval;
454 }
455
456 /* Auto pre/post increment/decrement. */
457 else if ((code & 0xc0) != 0xc0)
458 {
459 reg = (code >> 6) & 3;
460 sval = (code & 0x0f);
461 if (sval & 0x8)
462 {
463 sval |= 0xfff0;
464 }
465 else
466 {
467 sval = sval + 1;
468 }
469 addr = cpu_get_reg (cpu, reg);
470 cpu_set_reg (cpu, reg, addr + sval);
471 if ((code & 0x10) == 0)
472 {
473 addr += sval;
474 }
475 }
476
477 /* [n,r] 16-bits offset indexed indirect. */
478 else if ((code & 0x07) == 3)
479 {
480 if (restrict)
481 {
482 return 0;
483 }
484 reg = (code >> 3) & 0x03;
485 addr = cpu_get_reg (cpu, reg);
486 addr += cpu_fetch16 (cpu);
487 addr = memory_read16 (cpu, addr);
488 cpu_add_cycles (cpu, 1);
489 }
490 else if ((code & 0x4) == 0)
491 {
492 if (restrict)
493 {
494 return 0;
495 }
496 reg = (code >> 3) & 0x03;
497 addr = cpu_get_reg (cpu, reg);
498 if (code & 0x2)
499 {
500 sval = cpu_fetch16 (cpu);
501 cpu_add_cycles (cpu, 1);
502 }
503 else
504 {
505 sval = cpu_fetch8 (cpu);
506 if (code & 0x1)
507 sval |= 0xff00;
508 cpu_add_cycles (cpu, 1);
509 }
510 addr += sval;
511 }
512 else
513 {
514 reg = (code >> 3) & 0x03;
515 addr = cpu_get_reg (cpu, reg);
516 switch (code & 3)
517 {
518 case 0:
519 addr += cpu_get_a (cpu);
520 break;
521 case 1:
522 addr += cpu_get_b (cpu);
523 break;
524 case 2:
525 addr += cpu_get_d (cpu);
526 break;
527 case 3:
528 default:
529 addr += cpu_get_d (cpu);
530 addr = memory_read16 (cpu, addr);
531 cpu_add_cycles (cpu, 1);
532 break;
533 }
534 }
535
536 return addr;
537 }
538
539 uint8
540 cpu_get_indexed_operand8 (sim_cpu* cpu, int restrict)
541 {
542 uint16 addr;
543
544 addr = cpu_get_indexed_operand_addr (cpu, restrict);
545 return memory_read8 (cpu, addr);
546 }
547
548 uint16
549 cpu_get_indexed_operand16 (sim_cpu* cpu, int restrict)
550 {
551 uint16 addr;
552
553 addr = cpu_get_indexed_operand_addr (cpu, restrict);
554 return memory_read16 (cpu, addr);
555 }
556
557 void
558 cpu_move8 (sim_cpu *cpu, uint8 code)
559 {
560 uint8 src;
561 uint16 addr;
562
563 switch (code)
564 {
565 case 0x0b:
566 src = cpu_fetch8 (cpu);
567 addr = cpu_fetch16 (cpu);
568 break;
569
570 case 0x08:
571 addr = cpu_get_indexed_operand_addr (cpu, 1);
572 src = cpu_fetch8 (cpu);
573 break;
574
575 case 0x0c:
576 addr = cpu_fetch16 (cpu);
577 src = memory_read8 (cpu, addr);
578 addr = cpu_fetch16 (cpu);
579 break;
580
581 case 0x09:
582 addr = cpu_get_indexed_operand_addr (cpu, 1);
583 src = memory_read8 (cpu, cpu_fetch16 (cpu));
584 break;
585
586 case 0x0d:
587 src = cpu_get_indexed_operand8 (cpu, 1);
588 addr = cpu_fetch16 (cpu);
589 break;
590
591 case 0x0a:
592 src = cpu_get_indexed_operand8 (cpu, 1);
593 addr = cpu_get_indexed_operand_addr (cpu, 1);
594 break;
595
596 }
597 memory_write8 (cpu, addr, src);
598 }
599
600 void
601 cpu_move16 (sim_cpu *cpu, uint8 code)
602 {
603 uint16 src;
604 uint16 addr;
605
606 switch (code)
607 {
608 case 0x03:
609 src = cpu_fetch16 (cpu);
610 addr = cpu_fetch16 (cpu);
611 break;
612
613 case 0x00:
614 addr = cpu_get_indexed_operand_addr (cpu, 1);
615 src = cpu_fetch16 (cpu);
616 break;
617
618 case 0x04:
619 addr = cpu_fetch16 (cpu);
620 src = memory_read16 (cpu, addr);
621 addr = cpu_fetch16 (cpu);
622 break;
623
624 case 0x01:
625 addr = cpu_get_indexed_operand_addr (cpu, 1);
626 src = memory_read16 (cpu, cpu_fetch16 (cpu));
627 break;
628
629 case 0x05:
630 src = cpu_get_indexed_operand16 (cpu, 1);
631 addr = cpu_fetch16 (cpu);
632 break;
633
634 case 0x02:
635 src = cpu_get_indexed_operand16 (cpu, 1);
636 addr = cpu_get_indexed_operand_addr (cpu, 1);
637 break;
638
639 }
640 memory_write16 (cpu, addr, src);
641 }
642
643 int
644 cpu_initialize (SIM_DESC sd, sim_cpu *cpu)
645 {
646 sim_add_option_table (sd, 0, cpu_options);
647
648 memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
649
650 cpu->cpu_absolute_cycle = 0;
651 cpu->cpu_current_cycle = 0;
652 cpu->cpu_emul_syscall = 1;
653 cpu->cpu_running = 1;
654 cpu->cpu_stop_on_interrupt = 0;
655 cpu->cpu_frequency = 8 * 1000 * 1000;
656 cpu->cpu_frames = 0;
657 cpu->cpu_current_frame = 0;
658 cpu->cpu_use_elf_start = 0;
659 cpu->cpu_elf_start = 0;
660 cpu->cpu_use_local_config = 0;
661 cpu->cpu_config = M6811_NOSEC | M6811_NOCOP | M6811_ROMON |
662 M6811_EEON;
663 interrupts_initialize (sd, cpu);
664
665 cpu->cpu_is_initialized = 1;
666 return 0;
667 }
668
669
670 /* Reinitialize the processor after a reset. */
671 int
672 cpu_reset (sim_cpu *cpu)
673 {
674 cpu->cpu_need_update_frame = 0;
675 cpu->cpu_current_frame = 0;
676 while (cpu->cpu_frames)
677 cpu_remove_frame_list (cpu, cpu->cpu_frames);
678
679 /* Initialize the config register.
680 It is only initialized at reset time. */
681 memset (cpu->ios, 0, sizeof (cpu->ios));
682 if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11)
683 cpu->ios[M6811_INIT] = 0x1;
684 else
685 cpu->ios[M6811_INIT] = 0;
686
687 /* Output compare registers set to 0xFFFF. */
688 cpu->ios[M6811_TOC1_H] = 0xFF;
689 cpu->ios[M6811_TOC1_L] = 0xFF;
690 cpu->ios[M6811_TOC2_H] = 0xFF;
691 cpu->ios[M6811_TOC2_L] = 0xFF;
692 cpu->ios[M6811_TOC3_H] = 0xFF;
693 cpu->ios[M6811_TOC4_L] = 0xFF;
694 cpu->ios[M6811_TOC5_H] = 0xFF;
695 cpu->ios[M6811_TOC5_L] = 0xFF;
696
697 /* Setup the processor registers. */
698 memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
699 cpu->cpu_absolute_cycle = 0;
700 cpu->cpu_current_cycle = 0;
701 cpu->cpu_is_initialized = 0;
702
703 /* Reset interrupts. */
704 interrupts_reset (&cpu->cpu_interrupts);
705
706 /* Reinitialize the CPU operating mode. */
707 cpu->ios[M6811_HPRIO] = cpu->cpu_mode;
708 return 0;
709 }
710
711 /* Reinitialize the processor after a reset. */
712 int
713 cpu_restart (sim_cpu *cpu)
714 {
715 uint16 addr;
716
717 /* Get CPU starting address depending on the CPU mode. */
718 if (cpu->cpu_use_elf_start == 0)
719 {
720 switch ((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA))
721 {
722 /* Single Chip */
723 default:
724 case 0 :
725 addr = memory_read16 (cpu, 0xFFFE);
726 break;
727
728 /* Expanded Multiplexed */
729 case M6811_MDA:
730 addr = memory_read16 (cpu, 0xFFFE);
731 break;
732
733 /* Special Bootstrap */
734 case M6811_SMOD:
735 addr = 0;
736 break;
737
738 /* Factory Test */
739 case M6811_MDA | M6811_SMOD:
740 addr = memory_read16 (cpu, 0xFFFE);
741 break;
742 }
743 }
744 else
745 {
746 addr = cpu->cpu_elf_start;
747 }
748
749 /* Setup the processor registers. */
750 cpu->cpu_insn_pc = addr;
751 cpu->cpu_regs.pc = addr;
752 cpu->cpu_regs.ccr = M6811_X_BIT | M6811_I_BIT | M6811_S_BIT;
753 cpu->cpu_absolute_cycle = 0;
754 cpu->cpu_is_initialized = 1;
755 cpu->cpu_current_cycle = 0;
756
757 cpu_call (cpu, addr);
758
759 return 0;
760 }
761
762 void
763 print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, int mode)
764 {
765 while (desc->mask)
766 {
767 if (val & desc->mask)
768 sim_io_printf (sd, "%s",
769 mode == 0 ? desc->short_name : desc->long_name);
770 desc++;
771 }
772 }
773
774 void
775 print_io_byte (SIM_DESC sd, const char *name, io_reg_desc *desc,
776 uint8 val, uint16 addr)
777 {
778 sim_io_printf (sd, " %-9.9s @ 0x%04x 0x%02x ", name, addr, val);
779 if (desc)
780 print_io_reg_desc (sd, desc, val, 0);
781 }
782
783 void
784 cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val)
785 {
786 cpu_set_ccr_V (proc, 0);
787 cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0);
788 cpu_set_ccr_Z (proc, val == 0 ? 1 : 0);
789 }
790
791
792 uint16
793 cpu_fetch_relbranch (sim_cpu *cpu)
794 {
795 uint16 addr = (uint16) cpu_fetch8 (cpu);
796
797 if (addr & 0x0080)
798 {
799 addr |= 0xFF00;
800 }
801 addr += cpu->cpu_regs.pc;
802 return addr;
803 }
804
805 uint16
806 cpu_fetch_relbranch16 (sim_cpu *cpu)
807 {
808 uint16 addr = cpu_fetch16 (cpu);
809
810 addr += cpu->cpu_regs.pc;
811 return addr;
812 }
813
814 /* Push all the CPU registers (when an interruption occurs). */
815 void
816 cpu_push_all (sim_cpu *cpu)
817 {
818 if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11)
819 {
820 cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.pc);
821 cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.iy);
822 cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.ix);
823 cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.d);
824 cpu_m68hc11_push_uint8 (cpu, cpu->cpu_regs.ccr);
825 }
826 else
827 {
828 cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.pc);
829 cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.iy);
830 cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.ix);
831 cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.d);
832 cpu_m68hc12_push_uint8 (cpu, cpu->cpu_regs.ccr);
833 }
834 }
835
836 /* Simulation of the dbcc/ibcc/tbcc 68HC12 conditional branch operations. */
837 void
838 cpu_dbcc (sim_cpu* cpu)
839 {
840 uint8 code;
841 uint16 addr;
842 uint16 inc;
843 uint16 reg;
844
845 code = cpu_fetch8 (cpu);
846 switch (code & 0xc0)
847 {
848 case 0x80: /* ibcc */
849 inc = 1;
850 break;
851 case 0x40: /* tbcc */
852 inc = 0;
853 break;
854 case 0: /* dbcc */
855 inc = -1;
856 break;
857 default:
858 abort ();
859 break;
860 }
861
862 addr = cpu_fetch8 (cpu);
863 if (code & 0x10)
864 addr |= 0xff00;
865
866 addr += cpu_get_pc (cpu);
867 reg = cpu_get_src_reg (cpu, code & 0x07);
868 reg += inc;
869
870 /* Branch according to register value. */
871 if ((reg != 0 && (code & 0x20)) || (reg == 0 && !(code & 0x20)))
872 {
873 cpu_set_pc (cpu, addr);
874 }
875 cpu_set_dst_reg (cpu, code & 0x07, reg);
876 }
877
878 void
879 cpu_exg (sim_cpu* cpu, uint8 code)
880 {
881 uint8 r1, r2;
882 uint16 src1;
883 uint16 src2;
884
885 r1 = (code >> 4) & 0x07;
886 r2 = code & 0x07;
887 if (code & 0x80)
888 {
889 src1 = cpu_get_src_reg (cpu, r1);
890 src2 = cpu_get_src_reg (cpu, r2);
891 if (r2 == 1 || r2 == 2)
892 src2 |= 0xff00;
893
894 cpu_set_dst_reg (cpu, r2, src1);
895 cpu_set_dst_reg (cpu, r1, src2);
896 }
897 else
898 {
899 src1 = cpu_get_src_reg (cpu, r1);
900
901 /* Sign extend the 8-bit registers (A, B, CCR). */
902 if ((r1 == 0 || r1 == 1 || r1 == 2) && (src1 & 0x80))
903 src1 |= 0xff00;
904
905 cpu_set_dst_reg (cpu, r2, src1);
906 }
907 }
908
909 /* Handle special instructions. */
910 void
911 cpu_special (sim_cpu *cpu, enum M6811_Special special)
912 {
913 switch (special)
914 {
915 case M6811_RTI:
916 {
917 uint8 ccr;
918
919 ccr = cpu_m68hc11_pop_uint8 (cpu);
920 cpu_set_ccr (cpu, ccr);
921 cpu_set_d (cpu, cpu_m68hc11_pop_uint16 (cpu));
922 cpu_set_x (cpu, cpu_m68hc11_pop_uint16 (cpu));
923 cpu_set_y (cpu, cpu_m68hc11_pop_uint16 (cpu));
924 cpu_set_pc (cpu, cpu_m68hc11_pop_uint16 (cpu));
925 cpu_return (cpu);
926 break;
927 }
928
929 case M6812_RTI:
930 {
931 uint8 ccr;
932
933 ccr = cpu_m68hc12_pop_uint8 (cpu);
934 cpu_set_ccr (cpu, ccr);
935 cpu_set_d (cpu, cpu_m68hc12_pop_uint16 (cpu));
936 cpu_set_x (cpu, cpu_m68hc12_pop_uint16 (cpu));
937 cpu_set_y (cpu, cpu_m68hc12_pop_uint16 (cpu));
938 cpu_set_pc (cpu, cpu_m68hc12_pop_uint16 (cpu));
939 cpu_return (cpu);
940 break;
941 }
942
943 case M6811_WAI:
944 /* In the ELF-start mode, we are in a special mode where
945 the WAI corresponds to an exit. */
946 if (cpu->cpu_use_elf_start)
947 {
948 cpu_set_pc (cpu, cpu->cpu_insn_pc);
949 sim_engine_halt (CPU_STATE (cpu), cpu,
950 NULL, NULL_CIA, sim_exited,
951 cpu_get_d (cpu));
952 return;
953 }
954 /* SCz: not correct... */
955 cpu_push_all (cpu);
956 break;
957
958 case M6811_SWI:
959 interrupts_raise (&cpu->cpu_interrupts, M6811_INT_SWI);
960 interrupts_process (&cpu->cpu_interrupts);
961 break;
962
963 case M6811_EMUL_SYSCALL:
964 case M6811_ILLEGAL:
965 if (cpu->cpu_emul_syscall)
966 {
967 uint8 op = memory_read8 (cpu,
968 cpu_get_pc (cpu) - 1);
969 if (op == 0x41)
970 {
971 cpu_set_pc (cpu, cpu->cpu_insn_pc);
972 sim_engine_halt (CPU_STATE (cpu), cpu,
973 NULL, NULL_CIA, sim_exited,
974 cpu_get_d (cpu));
975 return;
976 }
977 else
978 {
979 emul_os (op, cpu);
980 }
981 return;
982 }
983
984 interrupts_raise (&cpu->cpu_interrupts, M6811_INT_ILLEGAL);
985 interrupts_process (&cpu->cpu_interrupts);
986 break;
987
988 case M6811_TEST:
989 case M6812_BGND:
990 {
991 SIM_DESC sd;
992
993 sd = CPU_STATE (cpu);
994
995 /* Breakpoint instruction if we are under gdb. */
996 if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
997 {
998 cpu->cpu_regs.pc --;
999 sim_engine_halt (CPU_STATE (cpu), cpu,
1000 0, cpu_get_pc (cpu), sim_stopped,
1001 SIM_SIGTRAP);
1002 }
1003 /* else this is a nop but not in test factory mode. */
1004 break;
1005 }
1006
1007 case M6812_IDIVS:
1008 {
1009 int32 src1 = (int16) cpu_get_d (cpu);
1010 int32 src2 = (int16) cpu_get_x (cpu);
1011
1012 if (src2 == 0)
1013 {
1014 cpu_set_ccr_C (cpu, 1);
1015 }
1016 else
1017 {
1018 cpu_set_d (cpu, src1 % src2);
1019 src1 = src1 / src2;
1020 cpu_set_x (cpu, src1);
1021 cpu_set_ccr_C (cpu, 0);
1022 cpu_set_ccr_Z (cpu, src1 == 0);
1023 cpu_set_ccr_N (cpu, src1 & 0x8000);
1024 cpu_set_ccr_V (cpu, src1 >= 32768 || src1 < -32768);
1025 }
1026 }
1027 break;
1028
1029 case M6812_EDIV:
1030 {
1031 uint32 src1 = (uint32) cpu_get_x (cpu);
1032 uint32 src2 = (uint32) (cpu_get_y (cpu) << 16)
1033 | (uint32) (cpu_get_d (cpu));
1034
1035 if (src1 == 0)
1036 {
1037 cpu_set_ccr_C (cpu, 1);
1038 }
1039 else
1040 {
1041 cpu_set_ccr_C (cpu, 0);
1042 cpu_set_d (cpu, src2 % src1);
1043 src2 = src2 / src1;
1044 cpu_set_y (cpu, src2);
1045 cpu_set_ccr_Z (cpu, src2 == 0);
1046 cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0);
1047 cpu_set_ccr_V (cpu, (src2 & 0xffff0000) != 0);
1048 }
1049 }
1050 break;
1051
1052 case M6812_EDIVS:
1053 {
1054 int32 src1 = (int16) cpu_get_x (cpu);
1055 int32 src2 = (uint32) (cpu_get_y (cpu) << 16)
1056 | (uint32) (cpu_get_d (cpu));
1057
1058 if (src1 == 0)
1059 {
1060 cpu_set_ccr_C (cpu, 1);
1061 }
1062 else
1063 {
1064 cpu_set_ccr_C (cpu, 0);
1065 cpu_set_d (cpu, src2 % src1);
1066 src2 = src2 / src1;
1067 cpu_set_y (cpu, src2);
1068 cpu_set_ccr_Z (cpu, src2 == 0);
1069 cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0);
1070 cpu_set_ccr_V (cpu, src2 > 32767 || src2 < -32768);
1071 }
1072 }
1073 break;
1074
1075 case M6812_EMULS:
1076 {
1077 int32 src1, src2;
1078
1079 src1 = (int16) cpu_get_d (cpu);
1080 src2 = (int16) cpu_get_y (cpu);
1081 src1 = src1 * src2;
1082 cpu_set_d (cpu, src1 & 0x0ffff);
1083 cpu_set_y (cpu, src1 >> 16);
1084 cpu_set_ccr_Z (cpu, src1 == 0);
1085 cpu_set_ccr_N (cpu, (src1 & 0x80000000) != 0);
1086 cpu_set_ccr_C (cpu, (src1 & 0x00008000) != 0);
1087 }
1088 break;
1089
1090 case M6812_EMACS:
1091 {
1092 int32 src1, src2;
1093 uint16 addr;
1094
1095 addr = cpu_fetch16 (cpu);
1096 src1 = (int16) memory_read16 (cpu, cpu_get_x (cpu));
1097 src2 = (int16) memory_read16 (cpu, cpu_get_y (cpu));
1098 src1 = src1 * src2;
1099 src2 = (((uint32) memory_read16 (cpu, addr)) << 16)
1100 | (uint32) memory_read16 (cpu, addr + 2);
1101
1102 memory_write16 (cpu, addr, (src1 + src2) >> 16);
1103 memory_write16 (cpu, addr + 2, (src1 + src2));
1104
1105
1106 }
1107 break;
1108
1109 case M6812_ETBL:
1110 default:
1111 sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
1112 cpu_get_pc (cpu), sim_stopped,
1113 SIM_SIGILL);
1114 break;
1115 }
1116 }
1117
1118
1119 void
1120 cpu_single_step (sim_cpu *cpu)
1121 {
1122 cpu->cpu_current_cycle = 0;
1123 cpu->cpu_insn_pc = cpu_get_pc (cpu);
1124
1125 /* Handle the pending interrupts. If an interrupt is handled,
1126 treat this as an single step. */
1127 if (interrupts_process (&cpu->cpu_interrupts))
1128 {
1129 cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
1130 return;
1131 }
1132
1133 /* printf("PC = 0x%04x\n", cpu_get_pc (cpu));*/
1134 cpu->cpu_interpretor (cpu);
1135 cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
1136 }
1137
1138 /* VARARGS */
1139 void
1140 sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep,
1141 uint16 addr, const char *message, ...)
1142 {
1143 char buf[1024];
1144 va_list args;
1145
1146 va_start (args, message);
1147 vsprintf (buf, message, args);
1148 va_end (args);
1149
1150 printf("%s\n", buf);
1151 cpu_memory_exception (cpu, excep, addr, buf);
1152 }
1153
1154
1155 void
1156 cpu_memory_exception (sim_cpu *cpu, SIM_SIGNAL excep,
1157 uint16 addr, const char *message)
1158 {
1159 if (cpu->cpu_running == 0)
1160 return;
1161
1162 cpu_set_pc (cpu, cpu->cpu_insn_pc);
1163 sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
1164 cpu_get_pc (cpu), sim_stopped, excep);
1165
1166 #if 0
1167 cpu->mem_exception = excep;
1168 cpu->fault_addr = addr;
1169 cpu->fault_msg = strdup (message);
1170
1171 if (cpu->cpu_use_handler)
1172 {
1173 longjmp (&cpu->cpu_exception_handler, 1);
1174 }
1175 (* cpu->callback->printf_filtered)
1176 (cpu->callback, "Fault at 0x%04x: %s\n", addr, message);
1177 #endif
1178 }
1179
1180 void
1181 cpu_info (SIM_DESC sd, sim_cpu *cpu)
1182 {
1183 sim_io_printf (sd, "CPU info:\n");
1184 sim_io_printf (sd, " Absolute cycle: %s\n",
1185 cycle_to_string (cpu, cpu->cpu_absolute_cycle));
1186
1187 sim_io_printf (sd, " Syscall emulation: %s\n",
1188 cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");
1189 sim_io_printf (sd, " Memory errors detection: %s\n",
1190 cpu->cpu_check_memory ? "yes" : "no");
1191 sim_io_printf (sd, " Stop on interrupt: %s\n",
1192 cpu->cpu_stop_on_interrupt ? "yes" : "no");
1193 }
1194