New simulator.
[external/binutils.git] / sim / m68hc11 / m68hc11_sim.c
1 /* m6811_cpu.c -- 68HC11 CPU Emulation
2    Copyright 1999, 2000 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 int
309 cpu_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.  */
338 int
339 cpu_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.  */
373 int
374 cpu_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
423 void
424 print_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
435 void
436 print_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
444 void
445 cpu_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
453 uint16
454 cpu_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).  */
468 void
469 cpu_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.  */
480 void
481 cpu_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
565 void
566 cpu_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 */
585 void
586 sim_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
601 void
602 cpu_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
626 void
627 cpu_info (SIM_DESC sd, sim_cpu *cpu)
628 {
629   sim_io_printf (sd, "CPU info:\n");
630   sim_io_printf (sd, "  Absolute cycle: %llu\n",
631                  cpu->cpu_absolute_cycle);
632   sim_io_printf (sd, "  Syscall emulation: %s\n",
633                  cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");
634   sim_io_printf (sd, "  Memory errors detection: %s\n",
635                  cpu->cpu_check_memory ? "yes" : "no");
636   sim_io_printf (sd, "  Stop on interrupt: %s\n",
637                  cpu->cpu_stop_on_interrupt ? "yes" : "no");
638 }
639