This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.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@nerim.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 enum {
27   OPTION_CPU_RESET = OPTION_START,
28   OPTION_EMUL_OS,
29   OPTION_CPU_CONFIG,
30   OPTION_CPU_MODE
31 };
32
33 static DECLARE_OPTION_HANDLER (cpu_option_handler);
34
35 static const OPTION cpu_options[] =
36 {
37   { {"cpu-reset", no_argument, NULL, OPTION_CPU_RESET },
38       '\0', NULL, "Reset the CPU",
39       cpu_option_handler },
40
41   { {"emulos",    no_argument, NULL, OPTION_EMUL_OS },
42       '\0', NULL, "Emulate some OS system calls (read, write, ...)",
43       cpu_option_handler },
44
45   { {"cpu-config", required_argument, NULL, OPTION_CPU_CONFIG },
46       '\0', NULL, "Specify the initial CPU configuration register",
47       cpu_option_handler },
48
49   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
50 };
51
52
53 static SIM_RC
54 cpu_option_handler (SIM_DESC sd, sim_cpu *cpu,
55                     int opt, char *arg, int is_command)
56 {
57   int val;
58   
59   cpu = STATE_CPU (sd, 0);
60   switch (opt)
61     {
62     case OPTION_CPU_RESET:
63       sim_board_reset (sd);
64       break;
65
66     case OPTION_EMUL_OS:
67       cpu->cpu_emul_syscall = 1;
68       break;
69
70     case OPTION_CPU_CONFIG:
71       if (sscanf(arg, "0x%x", &val) == 1
72           || sscanf(arg, "%d", &val) == 1)
73         {
74           cpu->cpu_config = val;
75           cpu->cpu_use_local_config = 1;
76         }
77       else
78         cpu->cpu_use_local_config = 0;
79       break;
80       
81     case OPTION_CPU_MODE:
82       break;
83     }
84
85   return SIM_RC_OK;
86 }
87
88     
89 void
90 cpu_call (sim_cpu *cpu, uint16 addr)
91 {
92
93   cpu_set_pc (cpu, addr);
94 }
95
96 void
97 cpu_return (sim_cpu *cpu)
98 {
99 }
100
101 /* Set the stack pointer and re-compute the current frame.  */
102 void
103 cpu_set_sp (sim_cpu *cpu, uint16 val)
104 {
105   cpu->cpu_regs.sp = val;
106 }
107
108 uint16
109 cpu_get_reg (sim_cpu* cpu, uint8 reg)
110 {
111   switch (reg)
112     {
113     case 0:
114       return cpu_get_x (cpu);
115
116     case 1:
117       return cpu_get_y (cpu);
118
119     case 2:
120       return cpu_get_sp (cpu);
121
122     case 3:
123       return cpu_get_pc (cpu);
124
125     default:
126       return 0;
127     }
128 }
129
130 uint16
131 cpu_get_src_reg (sim_cpu* cpu, uint8 reg)
132 {
133   switch (reg)
134     {
135     case 0:
136       return cpu_get_a (cpu);
137
138     case 1:
139       return cpu_get_b (cpu);
140
141     case 2:
142       return cpu_get_ccr (cpu);
143
144     case 3:
145       return cpu_get_tmp3 (cpu);
146
147     case 4:
148       return cpu_get_d (cpu);
149
150     case 5:
151       return cpu_get_x (cpu);
152
153     case 6:
154       return cpu_get_y (cpu);
155
156     case 7:
157       return cpu_get_sp (cpu);
158
159     default:
160       return 0;
161     }
162 }
163
164 void
165 cpu_set_dst_reg (sim_cpu* cpu, uint8 reg, uint16 val)
166 {
167   switch (reg)
168     {
169     case 0:
170       cpu_set_a (cpu, val);
171       break;
172
173     case 1:
174       cpu_set_b (cpu, val);
175       break;
176
177     case 2:
178       cpu_set_ccr (cpu, val);
179       break;
180
181     case 3:
182       cpu_set_tmp2 (cpu, val);
183       break;
184
185     case 4:
186       cpu_set_d (cpu, val);
187       break;
188
189     case 5:
190       cpu_set_x (cpu, val);
191       break;
192
193     case 6:
194       cpu_set_y (cpu, val);
195       break;
196
197     case 7:
198       cpu_set_sp (cpu, val);
199       break;
200
201     default:
202       break;
203     }
204 }
205
206 void
207 cpu_set_reg (sim_cpu* cpu, uint8 reg, uint16 val)
208 {
209   switch (reg)
210     {
211     case 0:
212       cpu_set_x (cpu, val);
213       break;
214       
215     case 1:
216       cpu_set_y (cpu, val);
217       break;
218       
219     case 2:
220       cpu_set_sp (cpu, val);
221       break;
222       
223     case 3:
224       cpu_set_pc (cpu, val);
225       break;
226       
227     default:
228       break;
229     }
230 }
231
232 /* Returns the address of a 68HC12 indexed operand.
233    Pre and post modifications are handled on the source register.  */
234 uint16
235 cpu_get_indexed_operand_addr (sim_cpu* cpu, int restrict)
236 {
237   uint8 reg;
238   uint16 sval;
239   uint16 addr;
240   uint8 code;
241
242   code = cpu_fetch8 (cpu);
243
244   /* n,r with 5-bit signed constant.  */
245   if ((code & 0x20) == 0)
246     {
247       reg = (code >> 6) & 3;
248       sval = (code & 0x1f);
249       if (code & 0x10)
250         sval |= 0xfff0;
251
252       addr = cpu_get_reg (cpu, reg);
253       addr += sval;
254     }
255
256   /* Auto pre/post increment/decrement.  */
257   else if ((code & 0xc0) != 0xc0)
258     {
259       reg = (code >> 6) & 3;
260       sval = (code & 0x0f);
261       if (sval & 0x8)
262         {
263           sval |= 0xfff0;
264         }
265       else
266         {
267           sval = sval + 1;
268         }
269       addr = cpu_get_reg (cpu, reg);
270       cpu_set_reg (cpu, reg, addr + sval);
271       if ((code & 0x10) == 0)
272         {
273           addr += sval;
274         }
275     }
276
277   /* [n,r] 16-bits offset indexed indirect.  */
278   else if ((code & 0x07) == 3)
279     {
280       if (restrict)
281         {
282           return 0;
283         }
284       reg = (code >> 3) & 0x03;
285       addr = cpu_get_reg (cpu, reg);
286       addr += cpu_fetch16 (cpu);
287       addr = memory_read16 (cpu, addr);
288       cpu_add_cycles (cpu, 1);
289     }
290   else if ((code & 0x4) == 0)
291     {
292       if (restrict)
293         {
294           return 0;
295         }
296       reg = (code >> 3) & 0x03;
297       addr = cpu_get_reg (cpu, reg);
298       if (code & 0x2)
299         {
300           sval = cpu_fetch16 (cpu);
301           cpu_add_cycles (cpu, 1);
302         }
303       else
304         {
305           sval = cpu_fetch8 (cpu);
306           if (code & 0x1)
307             sval |= 0xff00;
308           cpu_add_cycles (cpu, 1);
309         }
310       addr += sval;
311     }
312   else
313     {
314       reg = (code >> 3) & 0x03;
315       addr = cpu_get_reg (cpu, reg);
316       switch (code & 3)
317         {
318         case 0:
319           addr += cpu_get_a (cpu);
320           break;
321         case 1:
322           addr += cpu_get_b (cpu);
323           break;
324         case 2:
325           addr += cpu_get_d (cpu);
326           break;
327         case 3:
328         default:
329           addr += cpu_get_d (cpu);
330           addr = memory_read16 (cpu, addr);
331           cpu_add_cycles (cpu, 1);
332           break;
333         }
334     }
335
336   return addr;
337 }
338
339 uint8
340 cpu_get_indexed_operand8 (sim_cpu* cpu, int restrict)
341 {
342   uint16 addr;
343
344   addr = cpu_get_indexed_operand_addr (cpu, restrict);
345   return memory_read8 (cpu, addr);
346 }
347
348 uint16
349 cpu_get_indexed_operand16 (sim_cpu* cpu, int restrict)
350 {
351   uint16 addr;
352
353   addr = cpu_get_indexed_operand_addr (cpu, restrict);
354   return memory_read16 (cpu, addr);
355 }
356
357 void
358 cpu_move8 (sim_cpu *cpu, uint8 code)
359 {
360   uint8 src;
361   uint16 addr;
362
363   switch (code)
364     {
365     case 0x0b:
366       src = cpu_fetch8 (cpu);
367       addr = cpu_fetch16 (cpu);
368       break;
369
370     case 0x08:
371       addr = cpu_get_indexed_operand_addr (cpu, 1);
372       src = cpu_fetch8 (cpu);
373       break;
374
375     case 0x0c:
376       addr = cpu_fetch16 (cpu);
377       src = memory_read8 (cpu, addr);
378       addr = cpu_fetch16 (cpu);
379       break;
380
381     case 0x09:
382       addr = cpu_get_indexed_operand_addr (cpu, 1);
383       src = memory_read8 (cpu, cpu_fetch16 (cpu));
384       break;
385
386     case 0x0d:
387       src = cpu_get_indexed_operand8 (cpu, 1);
388       addr = cpu_fetch16 (cpu);
389       break;
390
391     case 0x0a:
392       src = cpu_get_indexed_operand8 (cpu, 1);
393       addr = cpu_get_indexed_operand_addr (cpu, 1);
394       break;
395
396     default:
397       sim_engine_abort (CPU_STATE (cpu), cpu, 0,
398                         "Invalid code 0x%0x -- internal error?", code);
399       return;
400     }
401   memory_write8 (cpu, addr, src);
402 }
403
404 void
405 cpu_move16 (sim_cpu *cpu, uint8 code)
406 {
407   uint16 src;
408   uint16 addr;
409
410   switch (code)
411     {
412     case 0x03:
413       src = cpu_fetch16 (cpu);
414       addr = cpu_fetch16 (cpu);
415       break;
416
417     case 0x00:
418       addr = cpu_get_indexed_operand_addr (cpu, 1);
419       src = cpu_fetch16 (cpu);
420       break;
421
422     case 0x04:
423       addr = cpu_fetch16 (cpu);
424       src = memory_read16 (cpu, addr);
425       addr = cpu_fetch16 (cpu);
426       break;
427
428     case 0x01:
429       addr = cpu_get_indexed_operand_addr (cpu, 1);
430       src = memory_read16 (cpu, cpu_fetch16 (cpu));
431       break;
432
433     case 0x05:
434       src = cpu_get_indexed_operand16 (cpu, 1);
435       addr = cpu_fetch16 (cpu);
436       break;
437
438     case 0x02:
439       src = cpu_get_indexed_operand16 (cpu, 1);
440       addr = cpu_get_indexed_operand_addr (cpu, 1);
441       break;
442
443     default:
444       sim_engine_abort (CPU_STATE (cpu), cpu, 0,
445                         "Invalid code 0x%0x -- internal error?", code);
446       return;
447     }
448   memory_write16 (cpu, addr, src);
449 }
450
451 int
452 cpu_initialize (SIM_DESC sd, sim_cpu *cpu)
453 {
454   sim_add_option_table (sd, 0, cpu_options);
455
456   memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
457
458   cpu->cpu_absolute_cycle = 0;
459   cpu->cpu_current_cycle  = 0;
460   cpu->cpu_emul_syscall   = 1;
461   cpu->cpu_running        = 1;
462   cpu->cpu_stop_on_interrupt = 0;
463   cpu->cpu_frequency = 8 * 1000 * 1000;
464   cpu->cpu_use_elf_start = 0;
465   cpu->cpu_elf_start     = 0;
466   cpu->cpu_use_local_config = 0;
467   cpu->cpu_config        = M6811_NOSEC | M6811_NOCOP | M6811_ROMON |
468     M6811_EEON;
469   interrupts_initialize (sd, cpu);
470
471   cpu->cpu_is_initialized = 1;
472   return 0;
473 }
474
475
476 /* Reinitialize the processor after a reset.  */
477 int
478 cpu_reset (sim_cpu *cpu)
479 {
480   /* Initialize the config register.
481      It is only initialized at reset time.  */
482   memset (cpu->ios, 0, sizeof (cpu->ios));
483   if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11)
484     cpu->ios[M6811_INIT] = 0x1;
485   else
486     cpu->ios[M6811_INIT] = 0;
487
488   /* Output compare registers set to 0xFFFF.  */
489   cpu->ios[M6811_TOC1_H] = 0xFF;
490   cpu->ios[M6811_TOC1_L] = 0xFF;
491   cpu->ios[M6811_TOC2_H] = 0xFF;
492   cpu->ios[M6811_TOC2_L] = 0xFF;
493   cpu->ios[M6811_TOC3_H] = 0xFF;
494   cpu->ios[M6811_TOC4_L] = 0xFF;
495   cpu->ios[M6811_TOC5_H] = 0xFF;
496   cpu->ios[M6811_TOC5_L] = 0xFF;
497
498   /* Setup the processor registers.  */
499   memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
500   cpu->cpu_absolute_cycle = 0;
501   cpu->cpu_current_cycle  = 0;
502   cpu->cpu_is_initialized = 0;
503
504   /* Reset interrupts.  */
505   interrupts_reset (&cpu->cpu_interrupts);
506
507   /* Reinitialize the CPU operating mode.  */
508   cpu->ios[M6811_HPRIO] = cpu->cpu_mode;
509   return 0;
510 }
511
512 /* Reinitialize the processor after a reset.  */
513 int
514 cpu_restart (sim_cpu *cpu)
515 {
516   uint16 addr;
517
518   /* Get CPU starting address depending on the CPU mode.  */
519   if (cpu->cpu_use_elf_start == 0)
520     {
521       switch ((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA))
522         {
523           /* Single Chip  */
524         default:
525         case 0 :
526           addr = memory_read16 (cpu, 0xFFFE);
527           break;
528
529           /* Expanded Multiplexed  */
530         case M6811_MDA:
531           addr = memory_read16 (cpu, 0xFFFE);
532           break;
533
534           /* Special Bootstrap  */
535         case M6811_SMOD:
536           addr = 0;
537           break;
538
539           /* Factory Test  */
540         case M6811_MDA | M6811_SMOD:
541           addr = memory_read16 (cpu, 0xFFFE);
542           break;
543         }
544     }
545   else
546     {
547       addr = cpu->cpu_elf_start;
548     }
549   
550   /* Setup the processor registers.  */
551   cpu->cpu_insn_pc  = addr;
552   cpu->cpu_regs.pc  = addr;
553   cpu->cpu_regs.ccr = M6811_X_BIT | M6811_I_BIT | M6811_S_BIT;
554   cpu->cpu_absolute_cycle = 0;
555   cpu->cpu_is_initialized = 1;
556   cpu->cpu_current_cycle  = 0;
557
558   cpu_call (cpu, addr);
559   
560   return 0;
561 }
562
563 void
564 print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, int mode)
565 {
566   while (desc->mask)
567     {
568       if (val & desc->mask)
569         sim_io_printf (sd, "%s",
570                        mode == 0 ? desc->short_name : desc->long_name);
571       desc++;
572     }
573 }
574
575 void
576 print_io_byte (SIM_DESC sd, const char *name, io_reg_desc *desc,
577                uint8 val, uint16 addr)
578 {
579   sim_io_printf (sd, "  %-9.9s @ 0x%04x 0x%02x ", name, addr, val);
580   if (desc)
581     print_io_reg_desc (sd, desc, val, 0);
582 }
583
584 void
585 cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val)
586 {
587   cpu_set_ccr_V (proc, 0);
588   cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0);
589   cpu_set_ccr_Z (proc, val == 0 ? 1 : 0);
590 }
591
592
593 uint16
594 cpu_fetch_relbranch (sim_cpu *cpu)
595 {
596   uint16 addr = (uint16) cpu_fetch8 (cpu);
597
598   if (addr & 0x0080)
599     {
600       addr |= 0xFF00;
601     }
602   addr += cpu->cpu_regs.pc;
603   return addr;
604 }
605
606 uint16
607 cpu_fetch_relbranch16 (sim_cpu *cpu)
608 {
609   uint16 addr = cpu_fetch16 (cpu);
610
611   addr += cpu->cpu_regs.pc;
612   return addr;
613 }
614
615 /* Push all the CPU registers (when an interruption occurs).  */
616 void
617 cpu_push_all (sim_cpu *cpu)
618 {
619   if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11)
620     {
621       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.pc);
622       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.iy);
623       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.ix);
624       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.d);
625       cpu_m68hc11_push_uint8 (cpu, cpu->cpu_regs.ccr);
626     }
627   else
628     {
629       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.pc);
630       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.iy);
631       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.ix);
632       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.d);
633       cpu_m68hc12_push_uint8 (cpu, cpu->cpu_regs.ccr);
634     }
635 }
636
637 /* Simulation of the dbcc/ibcc/tbcc 68HC12 conditional branch operations.  */
638 void
639 cpu_dbcc (sim_cpu* cpu)
640 {
641   uint8 code;
642   uint16 addr;
643   uint16 inc;
644   uint16 reg;
645   
646   code = cpu_fetch8 (cpu);
647   switch (code & 0xc0)
648     {
649     case 0x80: /* ibcc */
650       inc = 1;
651       break;
652     case 0x40: /* tbcc */
653       inc = 0;
654       break;
655     case 0:    /* dbcc */
656       inc = -1;
657       break;
658     default:
659       abort ();
660       break;
661     }
662
663   addr = cpu_fetch8 (cpu);
664   if (code & 0x10)
665     addr |= 0xff00;
666
667   addr += cpu_get_pc (cpu);
668   reg = cpu_get_src_reg (cpu, code & 0x07);
669   reg += inc;
670
671   /* Branch according to register value.  */
672   if ((reg != 0 && (code & 0x20)) || (reg == 0 && !(code & 0x20)))
673     {
674       cpu_set_pc (cpu, addr);
675     }
676   cpu_set_dst_reg (cpu, code & 0x07, reg);
677 }
678
679 void
680 cpu_exg (sim_cpu* cpu, uint8 code)
681 {
682   uint8 r1, r2;
683   uint16 src1;
684   uint16 src2;
685
686   r1 = (code >> 4) & 0x07;
687   r2 = code & 0x07;
688   if (code & 0x80)
689     {
690       src1 = cpu_get_src_reg (cpu, r1);
691       src2 = cpu_get_src_reg (cpu, r2);
692       if (r2 == 1 || r2 == 2)
693         src2 |= 0xff00;
694       
695       cpu_set_dst_reg (cpu, r2, src1);
696       cpu_set_dst_reg (cpu, r1, src2);
697     }
698   else
699     {
700       src1 = cpu_get_src_reg (cpu, r1);
701
702       /* Sign extend the 8-bit registers (A, B, CCR).  */
703       if ((r1 == 0 || r1 == 1 || r1 == 2) && (src1 & 0x80))
704         src1 |= 0xff00;
705
706       cpu_set_dst_reg (cpu, r2, src1);
707     }
708 }
709
710 /* Handle special instructions.  */
711 void
712 cpu_special (sim_cpu *cpu, enum M6811_Special special)
713 {
714   switch (special)
715     {
716     case M6811_RTI:
717       {
718         uint8 ccr;
719
720         ccr = cpu_m68hc11_pop_uint8 (cpu);
721         cpu_set_ccr (cpu, ccr);
722         cpu_set_d (cpu, cpu_m68hc11_pop_uint16 (cpu));
723         cpu_set_x (cpu, cpu_m68hc11_pop_uint16 (cpu));
724         cpu_set_y (cpu, cpu_m68hc11_pop_uint16 (cpu));
725         cpu_set_pc (cpu, cpu_m68hc11_pop_uint16 (cpu));
726         cpu_return (cpu);
727         break;
728       }
729
730     case M6812_RTI:
731       {
732         uint8 ccr;
733
734         ccr = cpu_m68hc12_pop_uint8 (cpu);
735         cpu_set_ccr (cpu, ccr);
736         cpu_set_d (cpu, cpu_m68hc12_pop_uint16 (cpu));
737         cpu_set_x (cpu, cpu_m68hc12_pop_uint16 (cpu));
738         cpu_set_y (cpu, cpu_m68hc12_pop_uint16 (cpu));
739         cpu_set_pc (cpu, cpu_m68hc12_pop_uint16 (cpu));
740         cpu_return (cpu);
741         break;
742       }
743       
744     case M6811_WAI:
745       /* In the ELF-start mode, we are in a special mode where
746          the WAI corresponds to an exit.  */
747       if (cpu->cpu_use_elf_start)
748         {
749           cpu_set_pc (cpu, cpu->cpu_insn_pc);
750           sim_engine_halt (CPU_STATE (cpu), cpu,
751                            NULL, NULL_CIA, sim_exited,
752                            cpu_get_d (cpu));
753           return;
754         }
755       /* SCz: not correct... */
756       cpu_push_all (cpu);
757       break;
758       
759     case M6811_SWI:
760       interrupts_raise (&cpu->cpu_interrupts, M6811_INT_SWI);
761       interrupts_process (&cpu->cpu_interrupts);
762       break;
763       
764     case M6811_EMUL_SYSCALL:
765     case M6811_ILLEGAL:
766       if (cpu->cpu_emul_syscall)
767         {
768           uint8 op = memory_read8 (cpu,
769                                    cpu_get_pc (cpu) - 1);
770           if (op == 0x41)
771             {
772               cpu_set_pc (cpu, cpu->cpu_insn_pc);
773               sim_engine_halt (CPU_STATE (cpu), cpu,
774                                NULL, NULL_CIA, sim_exited,
775                                cpu_get_d (cpu));
776               return;
777             }
778           else
779             {
780               emul_os (op, cpu);
781             }
782           return;
783         }
784       
785       interrupts_raise (&cpu->cpu_interrupts, M6811_INT_ILLEGAL);
786       interrupts_process (&cpu->cpu_interrupts);
787       break;
788
789     case M6811_TEST:
790     case M6812_BGND:
791       {
792         SIM_DESC sd;
793
794         sd = CPU_STATE (cpu);
795
796         /* Breakpoint instruction if we are under gdb.  */
797         if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
798           {
799             cpu->cpu_regs.pc --;
800             sim_engine_halt (CPU_STATE (cpu), cpu,
801                              0, cpu_get_pc (cpu), sim_stopped,
802                              SIM_SIGTRAP);
803           }
804         /* else this is a nop but not in test factory mode.  */
805         break;
806       }
807
808     case M6812_IDIVS:
809       {
810         int32 src1 = (int16) cpu_get_d (cpu);
811         int32 src2 = (int16) cpu_get_x (cpu);
812
813         if (src2 == 0)
814           {
815             cpu_set_ccr_C (cpu, 1);
816           }
817         else
818           {
819             cpu_set_d (cpu, src1 % src2);
820             src1 = src1 / src2;
821             cpu_set_x (cpu, src1);
822             cpu_set_ccr_C (cpu, 0);
823             cpu_set_ccr_Z (cpu, src1 == 0);
824             cpu_set_ccr_N (cpu, src1 & 0x8000);
825             cpu_set_ccr_V (cpu, src1 >= 32768 || src1 < -32768);
826           }
827       }
828       break;
829       
830     case M6812_EDIV:
831       {
832         uint32 src1 = (uint32) cpu_get_x (cpu);
833         uint32 src2 = (uint32) (cpu_get_y (cpu) << 16)
834           | (uint32) (cpu_get_d (cpu));
835
836         if (src1 == 0)
837           {
838             cpu_set_ccr_C (cpu, 1);
839           }
840         else
841           {
842             cpu_set_ccr_C (cpu, 0);
843             cpu_set_d (cpu, src2 % src1);
844             src2 = src2 / src1;
845             cpu_set_y (cpu, src2);
846             cpu_set_ccr_Z (cpu, src2 == 0);
847             cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0);
848             cpu_set_ccr_V (cpu, (src2 & 0xffff0000) != 0);
849           }
850       }
851       break;
852       
853     case M6812_EDIVS:
854       {
855         int32 src1 = (int16) cpu_get_x (cpu);
856         int32 src2 = (uint32) (cpu_get_y (cpu) << 16)
857           | (uint32) (cpu_get_d (cpu));
858
859         if (src1 == 0)
860           {
861             cpu_set_ccr_C (cpu, 1);
862           }
863         else
864           {
865             cpu_set_ccr_C (cpu, 0);
866             cpu_set_d (cpu, src2 % src1);
867             src2 = src2 / src1;
868             cpu_set_y (cpu, src2);
869             cpu_set_ccr_Z (cpu, src2 == 0);
870             cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0);
871             cpu_set_ccr_V (cpu, src2 > 32767 || src2 < -32768);
872           }
873       }
874       break;      
875
876     case M6812_EMULS:
877       {
878         int32 src1, src2;
879
880         src1 = (int16) cpu_get_d (cpu);
881         src2 = (int16) cpu_get_y (cpu);
882         src1 = src1 * src2;
883         cpu_set_d (cpu, src1 & 0x0ffff);
884         cpu_set_y (cpu, src1 >> 16);
885         cpu_set_ccr_Z (cpu, src1 == 0);
886         cpu_set_ccr_N (cpu, (src1 & 0x80000000) != 0);
887         cpu_set_ccr_C (cpu, (src1 & 0x00008000) != 0);
888       }
889       break;
890       
891     case M6812_EMACS:
892       {
893         int32 src1, src2;
894         uint16 addr;
895         
896         addr = cpu_fetch16 (cpu);
897         src1 = (int16) memory_read16 (cpu, cpu_get_x (cpu));
898         src2 = (int16) memory_read16 (cpu, cpu_get_y (cpu));
899         src1 = src1 * src2;
900         src2 = (((uint32) memory_read16 (cpu, addr)) << 16)
901           | (uint32) memory_read16 (cpu, addr + 2);
902
903         memory_write16 (cpu, addr, (src1 + src2) >> 16);
904         memory_write16 (cpu, addr + 2, (src1 + src2));
905
906         
907       }
908       break;
909
910     case M6812_CALL:
911       {
912         uint8 page;
913         uint16 addr;
914
915         addr = cpu_fetch16 (cpu);
916         page = cpu_fetch8 (cpu);
917
918         cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu));
919         cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu));
920
921         cpu_set_page (cpu, page);
922         cpu_set_pc (cpu, addr);
923       }
924       break;
925
926     case M6812_CALL_INDIRECT:
927       {
928         uint8 code;
929         uint16 addr;
930         uint8 page;
931
932         code = memory_read8 (cpu, cpu_get_pc (cpu));
933         /* Indirect addressing call has the page specified in the
934            memory location pointed to by the address.  */
935         if ((code & 0xE3) == 0xE3)
936           {
937             addr = cpu_get_indexed_operand_addr (cpu, 0);
938             page = memory_read8 (cpu, addr + 2);
939             addr = memory_read16 (cpu, addr);
940           }
941         else
942           {
943             /* Otherwise, page is in the opcode.  */
944             addr = cpu_get_indexed_operand16 (cpu, 0);
945             page = cpu_fetch8 (cpu);
946           }
947         cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu));
948         cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu));
949         cpu_set_page (cpu, page);
950         cpu_set_pc (cpu, addr);
951       }
952       break;
953
954     case M6812_RTC:
955       {
956         uint8 page = cpu_m68hc12_pop_uint8 (cpu);
957         uint16 addr = cpu_m68hc12_pop_uint16 (cpu);
958
959         cpu_set_page (cpu, page);
960         cpu_set_pc (cpu, addr);
961       }
962       break;
963       
964     case M6812_ETBL:
965     default:
966       sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
967                        cpu_get_pc (cpu), sim_stopped,
968                        SIM_SIGILL);
969       break;
970     }
971 }
972
973
974 void
975 cpu_single_step (sim_cpu *cpu)
976 {
977   cpu->cpu_current_cycle = 0;
978   cpu->cpu_insn_pc = cpu_get_pc (cpu);
979
980   /* Handle the pending interrupts.  If an interrupt is handled,
981      treat this as an single step.  */
982   if (interrupts_process (&cpu->cpu_interrupts))
983     {
984       cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
985       return;
986     }
987   
988   /*  printf("PC = 0x%04x\n", cpu_get_pc (cpu));*/
989   cpu->cpu_interpretor (cpu);
990   cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
991 }
992
993 /* VARARGS */
994 void
995 sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep,
996                   uint16 addr, const char *message, ...)
997 {
998   char buf[1024];
999   va_list args;
1000
1001   va_start (args, message);
1002   vsprintf (buf, message, args);
1003   va_end (args);
1004
1005   sim_io_printf (CPU_STATE (cpu), "%s\n", buf);
1006   cpu_memory_exception (cpu, excep, addr, buf);
1007 }
1008
1009
1010 void
1011 cpu_memory_exception (sim_cpu *cpu, SIM_SIGNAL excep,
1012                       uint16 addr, const char *message)
1013 {
1014   if (cpu->cpu_running == 0)
1015     return;
1016
1017   cpu_set_pc (cpu, cpu->cpu_insn_pc);
1018   sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
1019                    cpu_get_pc (cpu), sim_stopped, excep);
1020   
1021 #if 0
1022   cpu->mem_exception = excep;
1023   cpu->fault_addr    = addr;
1024   cpu->fault_msg     = strdup (message);
1025
1026   if (cpu->cpu_use_handler)
1027     {
1028       longjmp (&cpu->cpu_exception_handler, 1);
1029     }
1030   (* cpu->callback->printf_filtered)
1031     (cpu->callback, "Fault at 0x%04x: %s\n", addr, message);
1032 #endif
1033 }
1034
1035 void
1036 cpu_info (SIM_DESC sd, sim_cpu *cpu)
1037 {
1038   sim_io_printf (sd, "CPU info:\n");
1039   sim_io_printf (sd, "  Absolute cycle: %s\n",
1040                  cycle_to_string (cpu, cpu->cpu_absolute_cycle));
1041   
1042   sim_io_printf (sd, "  Syscall emulation: %s\n",
1043                  cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");
1044   sim_io_printf (sd, "  Memory errors detection: %s\n",
1045                  cpu->cpu_check_memory ? "yes" : "no");
1046   sim_io_printf (sd, "  Stop on interrupt: %s\n",
1047                  cpu->cpu_stop_on_interrupt ? "yes" : "no");
1048 }
1049