Upload Tizen:Base source
[external/gdb.git] / sim / m68hc11 / dv-m68hc11.c
1 /*  dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2     Copyright (C) 1999, 2000, 2001, 2002, 2003, 2007, 2008, 2009, 2010
3     Free Software Foundation, Inc.
4     Written by Stephane Carrez (stcarrez@nerim.fr)
5     (From a driver model Contributed by Cygnus Solutions.)
6     
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 3 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     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 program.  If not, see <http://www.gnu.org/licenses/>.
19     
20     */
21
22
23 #include "sim-main.h"
24 #include "sim-hw.h"
25 #include "hw-main.h"
26 #include "sim-options.h"
27 #include "hw-base.h"
28 #include <limits.h>
29
30 /* DEVICE
31
32         m68hc11cpu - m68hc11 cpu virtual device
33         m68hc12cpu - m68hc12 cpu virtual device
34    
35    DESCRIPTION
36
37         Implements the external m68hc11/68hc12 functionality.  This includes
38         the delivery of of interrupts generated from other devices and the
39         handling of device specific registers.
40
41
42    PROPERTIES
43
44    reg <base> <size>
45
46         Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
47
48    clock <hz>
49
50         Frequency of the quartz used by the processor.
51
52    mode [single | expanded | bootstrap | test]
53
54         Cpu operating mode (the MODA and MODB external pins).
55
56
57    PORTS
58
59    reset (input)
60
61         Reset the cpu and generates a cpu-reset event (used to reset
62         other devices).
63
64    nmi (input)
65
66         Deliver a non-maskable interrupt to the processor.
67
68
69    set-port-a (input)
70    set-port-c (input)
71    set-pord-d (input)
72
73         Allow an external device to set the value of port A, C or D inputs.
74
75
76    cpu-reset (output)
77
78         Event generated after the CPU performs a reset.
79
80
81    port-a (output)
82    port-b (output)
83    port-c (output)
84    port-d (output)
85
86         Event generated when the value of the output port A, B, C or D
87         changes.
88
89
90    BUGS
91
92         When delivering an interrupt, this code assumes that there is only
93         one processor (number 0).
94
95    */
96
97 enum
98 {
99   OPTION_OSC_SET = OPTION_START,
100   OPTION_OSC_CLEAR,
101   OPTION_OSC_INFO
102 };
103
104 static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
105
106 static const OPTION m68hc11_options[] =
107 {
108   { {"osc-set", required_argument, NULL, OPTION_OSC_SET },
109       '\0', "BIT,FREQ", "Set the oscillator on input port BIT",
110       m68hc11_option_handler },
111   { {"osc-clear", required_argument, NULL, OPTION_OSC_CLEAR },
112       '\0', "BIT", "Clear oscillator on input port BIT",
113       m68hc11_option_handler },
114   { {"osc-info", no_argument, NULL, OPTION_OSC_INFO },
115       '\0', NULL, "Print information about current input oscillators",
116       m68hc11_option_handler },
117   
118   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
119 };
120
121 struct input_osc
122 {
123   signed64         on_time;
124   signed64         off_time;
125   signed64         repeat;
126   struct hw_event *event;
127   const char      *name;
128   uint8            mask;
129   uint8            value;
130   uint16           addr;
131 };
132
133 #define NR_PORT_A_OSC (4)
134 #define NR_PORT_B_OSC (0)
135 #define NR_PORT_C_OSC (8)
136 #define NR_PORT_D_OSC (6)
137 #define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC)
138 struct m68hc11cpu {
139   /* Pending interrupts for delivery by event handler.  */
140   int              pending_reset;
141   int              pending_nmi;
142   int              pending_level;
143   struct hw_event  *event;
144   unsigned_word    attach_address;
145   int              attach_size;
146   int              attach_space;
147   int              last_oscillator;
148   struct input_osc oscillators[NR_OSC];
149 };
150
151
152
153 /* input port ID's */ 
154
155 enum {
156   RESET_PORT,
157   NMI_PORT,
158   IRQ_PORT,
159   CPU_RESET_PORT,
160   SET_PORT_A,
161   SET_PORT_C,
162   SET_PORT_D,
163   CPU_WRITE_PORT,
164   PORT_A,
165   PORT_B,
166   PORT_C,
167   PORT_D,
168   CAPTURE
169 };
170
171
172 static const struct hw_port_descriptor m68hc11cpu_ports[] = {
173
174   /* Interrupt inputs.  */
175   { "reset",     RESET_PORT,     0, input_port, },
176   { "nmi",       NMI_PORT,       0, input_port, },
177   { "irq",       IRQ_PORT,       0, input_port, },
178
179   { "set-port-a", SET_PORT_A,    0, input_port, },
180   { "set-port-c", SET_PORT_C,    0, input_port, },
181   { "set-port-d", SET_PORT_D,    0, input_port, },
182
183   { "cpu-write-port", CPU_WRITE_PORT,    0, input_port, },
184
185   /* Events generated for connection to other devices.  */
186   { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
187
188   /* Events generated when the corresponding port is
189      changed by the program.  */
190   { "port-a",    PORT_A,         0, output_port, },
191   { "port-b",    PORT_B,         0, output_port, },
192   { "port-c",    PORT_C,         0, output_port, },
193   { "port-d",    PORT_D,         0, output_port, },
194
195   { "capture",   CAPTURE,        0, output_port, },
196
197   { NULL, },
198 };
199
200 static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
201 static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
202 static hw_ioctl_method m68hc11_ioctl;
203
204 /* Finish off the partially created hw device.  Attach our local
205    callbacks.  Wire up our port names etc.  */
206
207 static hw_port_event_method m68hc11cpu_port_event;
208
209 static void make_oscillator (struct m68hc11cpu *controller,
210                              const char *id, uint16 addr, uint8 mask);
211 static struct input_osc *find_oscillator (struct m68hc11cpu *controller,
212                                           const char *id);
213 static void reset_oscillators (struct hw *me);
214
215 static void
216 dv_m6811_attach_address_callback (struct hw *me,
217                                   int level,
218                                   int space,
219                                   address_word addr,
220                                   address_word nr_bytes,
221                                   struct hw *client)
222 {
223   HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
224              level, space, (unsigned long) addr, (unsigned long) nr_bytes,
225              hw_path (client)));
226
227   if (space != io_map)
228     {
229       sim_core_attach (hw_system (me),
230                        NULL, /*cpu*/
231                        level,
232                        access_read_write_exec,
233                        space, addr,
234                        nr_bytes,
235                        0, /* modulo */
236                        client,
237                        NULL);
238     }
239   else
240     {
241       /*printf("Attach from sub device: %d\n", (long) addr);*/
242       sim_core_attach (hw_system (me),
243                        NULL, /*cpu*/
244                        level,
245                        access_io,
246                        space, addr,
247                        nr_bytes,
248                        0, /* modulo */
249                        client,
250                        NULL);
251     }
252 }
253
254 static void
255 dv_m6811_detach_address_callback (struct hw *me,
256                                   int level,
257                                   int space,
258                                   address_word addr,
259                                   address_word nr_bytes,
260                                   struct hw *client)
261 {
262   sim_core_detach (hw_system (me), NULL, /*cpu*/
263                    level, space, addr);
264 }
265
266 static void
267 m68hc11_delete (struct hw* me)
268 {
269   struct m68hc11cpu *controller;
270   
271   controller = hw_data (me);
272
273   reset_oscillators (me);
274   hw_detach_address (me, M6811_IO_LEVEL,
275                      controller->attach_space,
276                      controller->attach_address,
277                      controller->attach_size, me);
278 }
279
280
281 static void
282 attach_m68hc11_regs (struct hw *me,
283                      struct m68hc11cpu *controller)
284 {
285   SIM_DESC sd;
286   sim_cpu *cpu;
287   reg_property_spec reg;
288   const char *cpu_mode;
289   
290   if (hw_find_property (me, "reg") == NULL)
291     hw_abort (me, "Missing \"reg\" property");
292
293   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
294     hw_abort (me, "\"reg\" property must contain one addr/size entry");
295
296   hw_unit_address_to_attach_address (hw_parent (me),
297                                      &reg.address,
298                                      &controller->attach_space,
299                                      &controller->attach_address,
300                                      me);
301   hw_unit_size_to_attach_size (hw_parent (me),
302                                &reg.size,
303                                &controller->attach_size, me);
304
305   hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
306                      controller->attach_space,
307                      controller->attach_address,
308                      controller->attach_size,
309                      me);
310   set_hw_delete (me, m68hc11_delete);
311
312   /* Get cpu frequency.  */
313   sd = hw_system (me);
314   cpu = STATE_CPU (sd, 0);
315   if (hw_find_property (me, "clock") != NULL)
316     {
317       cpu->cpu_frequency = hw_find_integer_property (me, "clock");
318     }
319   else
320     {
321       cpu->cpu_frequency = 8*1000*1000;
322     }
323
324   if (hw_find_property (me, "use_bank") != NULL)
325     hw_attach_address (hw_parent (me), 0,
326                        exec_map,
327                        cpu->bank_start,
328                        cpu->bank_end - cpu->bank_start,
329                        me);
330
331   cpu_mode = "expanded";
332   if (hw_find_property (me, "mode") != NULL)
333     cpu_mode = hw_find_string_property (me, "mode");
334
335   if (strcmp (cpu_mode, "test") == 0)
336     cpu->cpu_mode = M6811_MDA | M6811_SMOD;
337   else if (strcmp (cpu_mode, "bootstrap") == 0)
338     cpu->cpu_mode = M6811_SMOD;
339   else if (strcmp (cpu_mode, "single") == 0)
340     cpu->cpu_mode = 0;
341   else
342     cpu->cpu_mode = M6811_MDA;
343
344   controller->last_oscillator = 0;
345
346   /* Create oscillators for input port A.  */
347   make_oscillator (controller, "A7", M6811_PORTA, 0x80);
348   make_oscillator (controller, "A2", M6811_PORTA, 0x04);
349   make_oscillator (controller, "A1", M6811_PORTA, 0x02);
350   make_oscillator (controller, "A0", M6811_PORTA, 0x01);
351
352   /* port B is output only.  */
353
354   /* Create oscillators for input port C.  */
355   make_oscillator (controller, "C0", M6811_PORTC, 0x01);
356   make_oscillator (controller, "C1", M6811_PORTC, 0x02);
357   make_oscillator (controller, "C2", M6811_PORTC, 0x04);
358   make_oscillator (controller, "C3", M6811_PORTC, 0x08);
359   make_oscillator (controller, "C4", M6811_PORTC, 0x10);
360   make_oscillator (controller, "C5", M6811_PORTC, 0x20);
361   make_oscillator (controller, "C6", M6811_PORTC, 0x40);
362   make_oscillator (controller, "C7", M6811_PORTC, 0x80);
363
364   /* Create oscillators for input port D.  */
365   make_oscillator (controller, "D0", M6811_PORTD, 0x01);
366   make_oscillator (controller, "D1", M6811_PORTD, 0x02);
367   make_oscillator (controller, "D2", M6811_PORTD, 0x04);
368   make_oscillator (controller, "D3", M6811_PORTD, 0x08);
369   make_oscillator (controller, "D4", M6811_PORTD, 0x10);
370   make_oscillator (controller, "D5", M6811_PORTD, 0x20);
371
372   /* Add oscillator commands.  */
373   sim_add_option_table (sd, 0, m68hc11_options);
374 }
375
376 static void
377 m68hc11cpu_finish (struct hw *me)
378 {
379   struct m68hc11cpu *controller;
380
381   controller = HW_ZALLOC (me, struct m68hc11cpu);
382   set_hw_data (me, controller);
383   set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
384   set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
385   set_hw_ports (me, m68hc11cpu_ports);
386   set_hw_port_event (me, m68hc11cpu_port_event);
387   set_hw_attach_address (me, dv_m6811_attach_address_callback);
388   set_hw_detach_address (me, dv_m6811_detach_address_callback);
389 #ifdef set_hw_ioctl
390   set_hw_ioctl (me, m68hc11_ioctl);
391 #else
392   me->to_ioctl = m68hc11_ioctl;
393 #endif
394
395   /* Initialize the pending interrupt flags.  */
396   controller->pending_level = 0;
397   controller->pending_reset = 0;
398   controller->pending_nmi = 0;
399   controller->event = NULL;
400
401   attach_m68hc11_regs (me, controller);
402 }
403
404 /* An event arrives on an interrupt port.  */
405
406 static void
407 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
408 {
409 }
410
411 static void
412 make_oscillator (struct m68hc11cpu *controller, const char *name,
413                  uint16 addr, uint8 mask)
414 {
415   struct input_osc *osc;
416
417   if (controller->last_oscillator >= NR_OSC)
418     hw_abort (0, "Too many oscillators");
419
420   osc = &controller->oscillators[controller->last_oscillator];
421   osc->name = name;
422   osc->addr = addr;
423   osc->mask = mask;
424   controller->last_oscillator++;
425 }
426
427 /* Find the oscillator given the input port name.  */
428 static struct input_osc *
429 find_oscillator (struct m68hc11cpu *controller, const char *name)
430 {
431   int i;
432
433   for (i = 0; i < controller->last_oscillator; i++)
434     if (strcasecmp (controller->oscillators[i].name, name) == 0)
435       return &controller->oscillators[i];
436
437   return 0;
438 }
439
440 static void
441 oscillator_handler (struct hw *me, void *data)
442 {
443   struct input_osc *osc = (struct input_osc*) data;
444   SIM_DESC sd;
445   sim_cpu *cpu;
446   signed64 dt;
447   uint8 val;
448
449   sd = hw_system (me);
450   cpu = STATE_CPU (sd, 0);
451
452   /* Change the input bit.  */
453   osc->value ^= osc->mask;
454   val = cpu->ios[osc->addr] & ~osc->mask;
455   val |= osc->value;
456   m68hc11cpu_set_port (me, cpu, osc->addr, val);
457
458   /* Setup event to toggle the bit.  */
459   if (osc->value)
460     dt = osc->on_time;
461   else
462     dt = osc->off_time;
463
464   if (dt && --osc->repeat >= 0)
465     {
466       sim_events *events = STATE_EVENTS (sd);
467
468       dt += events->nr_ticks_to_process;
469       osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc);
470     }
471   else
472     osc->event = 0;
473 }
474
475 static void
476 reset_oscillators (struct hw *me)
477 {
478   struct m68hc11cpu *controller = hw_data (me);
479   int i;
480
481   for (i = 0; i < controller->last_oscillator; i++)
482     {
483       if (controller->oscillators[i].event)
484         {
485           hw_event_queue_deschedule (me, controller->oscillators[i].event);
486           controller->oscillators[i].event = 0;
487         }
488     }
489 }
490       
491 static void
492 m68hc11cpu_port_event (struct hw *me,
493                        int my_port,
494                        struct hw *source,
495                        int source_port,
496                        int level)
497 {
498   struct m68hc11cpu *controller = hw_data (me);
499   SIM_DESC sd;
500   sim_cpu* cpu;
501   
502   sd  = hw_system (me);
503   cpu = STATE_CPU (sd, 0);
504   switch (my_port)
505     {
506     case RESET_PORT:
507       HW_TRACE ((me, "port-in reset"));
508
509       /* The reset is made in 3 steps:
510          - First, cleanup the current sim_cpu struct.
511          - Reset the devices.
512          - Restart the cpu for the reset (get the CPU mode from the
513            CONFIG register that gets initialized by EEPROM device).  */
514       cpu_reset (cpu);
515       reset_oscillators (me);
516       hw_port_event (me, CPU_RESET_PORT, 1);
517       cpu_restart (cpu);
518       break;
519       
520     case NMI_PORT:
521       controller->pending_nmi = 1;
522       HW_TRACE ((me, "port-in nmi"));
523       break;
524       
525     case IRQ_PORT:
526       /* level == 0 means that the interrupt was cleared.  */
527       if(level == 0)
528         controller->pending_level = -1; /* signal end of interrupt */
529       else
530         controller->pending_level = level;
531       HW_TRACE ((me, "port-in level=%d", level));
532       break;
533
534     case SET_PORT_A:
535       m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
536       break;
537       
538     case SET_PORT_C:
539       m68hc11cpu_set_port (me, cpu, M6811_PORTC, level);
540       break;
541
542     case SET_PORT_D:
543       m68hc11cpu_set_port (me, cpu, M6811_PORTD, level);
544       break;
545
546     case CPU_WRITE_PORT:
547       break;
548
549     default:
550       hw_abort (me, "bad switch");
551       break;
552     }
553
554   /* Schedule an event to be delivered immediately after current
555      instruction.  */
556   if(controller->event != NULL)
557     hw_event_queue_deschedule(me, controller->event);
558   controller->event =
559     hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
560 }
561
562
563 io_reg_desc config_desc[] = {
564   { M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
565   { M6811_NOCOP, "NOCOP ", "COP System Disable" },
566   { M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
567   { M6811_EEON,  "EEON  ", "Enable On-chip EEprom" },
568   { 0,  0, 0 }
569 };
570
571 io_reg_desc hprio_desc[] = {
572   { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
573   { M6811_SMOD,  "SMOD  ", "Special Mode" },
574   { M6811_MDA,   "MDA   ", "Mode Select A" },
575   { M6811_IRV,   "IRV   ", "Internal Read Visibility" },
576   { 0,  0, 0 }
577 };
578
579 io_reg_desc option_desc[] = {
580   { M6811_ADPU,  "ADPU  ", "A/D Powerup" },
581   { M6811_CSEL,  "CSEL  ", "A/D/EE Charge pump clock source select" },
582   { M6811_IRQE,  "IRQE  ", "IRQ Edge/Level sensitive" },
583   { M6811_DLY,   "DLY   ", "Stop exit turn on delay" },
584   { M6811_CME,   "CME   ", "Clock Monitor Enable" },
585   { M6811_CR1,   "CR1   ", "COP timer rate select (CR1)" },
586   { M6811_CR0,   "CR0   ", "COP timer rate select (CR0)" },
587   { 0,  0, 0 }
588 };
589
590 static void
591 m68hc11_info (struct hw *me)
592 {
593   SIM_DESC sd;
594   uint16 base = 0;
595   sim_cpu *cpu;
596   struct m68hc11sio *controller;
597   uint8 val;
598   
599   sd = hw_system (me);
600   cpu = STATE_CPU (sd, 0);
601   controller = hw_data (me);
602
603   base = cpu_get_io_base (cpu);
604   sim_io_printf (sd, "M68HC11:\n");
605
606   val = cpu->ios[M6811_HPRIO];
607   print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
608   switch (cpu->cpu_mode)
609     {
610     case M6811_MDA | M6811_SMOD:
611       sim_io_printf (sd, "[test]\n");
612       break;
613     case M6811_SMOD:
614       sim_io_printf (sd, "[bootstrap]\n");
615       break;
616     case M6811_MDA:
617       sim_io_printf (sd, "[extended]\n");
618       break;
619     default:
620       sim_io_printf (sd, "[single]\n");
621       break;
622     }
623
624   val = cpu->ios[M6811_CONFIG];
625   print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
626   sim_io_printf (sd, "\n");
627
628   val = cpu->ios[M6811_OPTION];
629   print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
630   sim_io_printf (sd, "\n");
631
632   val = cpu->ios[M6811_INIT];
633   print_io_byte (sd, "INIT  ", 0, val, base + M6811_INIT);
634   sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
635                  (((uint16) (val & 0xF0)) << 8),
636                  (((uint16) (val & 0x0F)) << 12));
637
638
639   cpu_info (sd, cpu);
640   interrupts_info (sd, &cpu->cpu_interrupts);
641 }
642
643 static int
644 m68hc11_ioctl (struct hw *me,
645                hw_ioctl_request request,
646                va_list ap)
647 {
648   m68hc11_info (me);
649   return 0;
650 }
651
652 /* Setup an oscillator on an input port.
653
654    TON represents the time in seconds that the input port should be set to 1.
655    TOFF is the time in seconds for the input port to be set to 0.
656
657    The oscillator frequency is therefore 1 / (ton + toff).
658
659    REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
660    stops.  */
661 int
662 m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
663                            double ton, double toff, signed64 repeat)
664 {
665   sim_cpu *cpu;
666   struct input_osc *osc;
667   double f;
668
669   cpu = STATE_CPU (sd, 0);
670
671   /* Find oscillator that corresponds to the input port.  */
672   osc = find_oscillator (hw_data (cpu->hw_cpu), port);
673   if (osc == 0)
674     return -1;
675
676   /* Compute the ON time in cpu cycles.  */
677   f = (double) (cpu->cpu_frequency) * ton;
678   osc->on_time = (signed64) (f / 4.0);
679   if (osc->on_time < 1)
680     osc->on_time = 1;
681
682   /* Compute the OFF time in cpu cycles.  */
683   f = (double) (cpu->cpu_frequency) * toff;
684   osc->off_time = (signed64) (f / 4.0);
685   if (osc->off_time < 1)
686     osc->off_time = 1;
687
688   osc->repeat = repeat;
689   if (osc->event)
690     hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
691
692   osc->event = hw_event_queue_schedule (cpu->hw_cpu,
693                                         osc->value ? osc->on_time
694                                         : osc->off_time,
695                                         oscillator_handler, osc);
696   return 0;
697 }
698
699 /* Clear the oscillator.  */
700 int
701 m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port)
702 {
703   sim_cpu *cpu;
704   struct input_osc *osc;
705
706   cpu = STATE_CPU (sd, 0);
707   osc = find_oscillator (hw_data (cpu->hw_cpu), port);
708   if (osc == 0)
709     return -1;
710
711   if (osc->event)
712     hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
713   osc->event = 0;
714   osc->repeat = 0;
715   return 0;
716 }
717
718 static int
719 get_frequency (const char *s, double *f)
720 {
721   char *p;
722   
723   *f = strtod (s, &p);
724   if (s == p)
725     return -1;
726
727   if (*p)
728     {
729       if (strcasecmp (p, "khz") == 0)
730         *f = *f * 1000.0;
731       else if (strcasecmp (p, "mhz") == 0)
732         *f = *f  * 1000000.0;
733       else if (strcasecmp (p, "hz") != 0)
734         return -1;
735     }
736   return 0;
737 }
738
739 static SIM_RC
740 m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu,
741                         int opt, char *arg, int is_command)
742 {
743   struct m68hc11cpu *controller;
744   double f;
745   char *p;
746   int i;
747   int title_printed = 0;
748   
749   if (cpu == 0)
750     cpu = STATE_CPU (sd, 0);
751
752   controller = hw_data (cpu->hw_cpu);
753   switch (opt)
754     {
755     case OPTION_OSC_SET:
756       p = strchr (arg, ',');
757       if (p)
758         *p++ = 0;
759
760       if (p == 0)
761         sim_io_eprintf (sd, "No frequency specified\n");
762       else if (get_frequency (p, &f) < 0 || f < 1.0e-8)
763         sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p);
764       else if (m68hc11cpu_set_oscillator (sd, arg,
765                                           1.0 / (f * 2.0),
766                                           1.0 / (f * 2.0), LONG_MAX))
767         sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
768       break;
769
770     case OPTION_OSC_CLEAR:
771       if (m68hc11cpu_clear_oscillator (sd, arg) != 0)
772         sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
773       break;
774
775     case OPTION_OSC_INFO:
776       for (i = 0; i < controller->last_oscillator; i++)
777         {
778           signed64 t;
779           struct input_osc *osc;
780
781           osc = &controller->oscillators[i];
782           if (osc->event)
783             {
784               double f;
785               int cur_value;
786               int next_value;
787               char freq[32];
788
789               if (title_printed == 0)
790                 {
791                   title_printed = 1;
792                   sim_io_printf (sd, " PORT  Frequency   Current"
793                                  "    Next    Transition time\n");
794                 }
795
796               f = (double) (osc->on_time + osc->off_time);
797               f = (double) (cpu->cpu_frequency / 4) / f;
798               t = hw_event_remain_time (cpu->hw_cpu, osc->event);
799
800               if (f > 10000.0)
801                 sprintf (freq, "%6.2f", f / 1000.0);
802               else
803                 sprintf (freq, "%6.2f", f);
804               cur_value = osc->value ? 1 : 0;
805               next_value = osc->value ? 0 : 1;
806               if (f > 10000.0)
807                 sim_io_printf (sd, " %4.4s  %8.8s khz"
808                                "      %d       %d    %35.35s\n",
809                                osc->name, freq,
810                                cur_value, next_value,
811                                cycle_to_string (cpu, t,
812                                                 PRINT_TIME | PRINT_CYCLE));
813               else
814                 sim_io_printf (sd, " %4.4s  %8.8s hz "
815                                "      %d       %d    %35.35s\n",
816                                osc->name, freq,
817                                cur_value, next_value,
818                                cycle_to_string (cpu, t,
819                                                 PRINT_TIME | PRINT_CYCLE));
820             }
821         }
822       break;      
823     }
824
825   return SIM_RC_OK;
826 }
827
828 /* generic read/write */
829
830 static unsigned
831 m68hc11cpu_io_read_buffer (struct hw *me,
832                            void *dest,
833                            int space,
834                            unsigned_word base,
835                            unsigned nr_bytes)
836 {
837   SIM_DESC sd;
838   struct m68hc11cpu *controller = hw_data (me);
839   sim_cpu *cpu;
840   unsigned byte = 0;
841   int result;
842   
843   HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
844
845   sd  = hw_system (me);
846   cpu = STATE_CPU (sd, 0);
847
848   if (base >= cpu->bank_start && base < cpu->bank_end)
849     {
850       address_word virt_addr = phys_to_virt (cpu, base);
851       if (virt_addr != base)
852         return sim_core_read_buffer (sd, cpu, space, dest,
853                                      virt_addr, nr_bytes);
854     }
855
856   /* Handle reads for the sub-devices.  */
857   base -= controller->attach_address;
858   result = sim_core_read_buffer (sd, cpu,
859                                  io_map, dest, base, nr_bytes);
860   if (result > 0)
861     return result;
862   
863   while (nr_bytes)
864     {
865       if (base >= controller->attach_size)
866         break;
867
868       memcpy (dest, &cpu->ios[base], 1);
869       dest = (char*) dest + 1;
870       base++;
871       byte++;
872       nr_bytes--;
873     }
874   return byte;
875 }     
876
877 void
878 m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
879                      unsigned addr, uint8 val)
880 {
881   uint8 mask;
882   uint8 delta;
883   int check_interrupts = 0;
884   int i;
885   
886   switch (addr)
887     {
888     case M6811_PORTA:
889       if (cpu->ios[M6811_PACTL] & M6811_DDRA7)
890         mask = 3;
891       else
892         mask = 0x83;
893
894       val = val & mask;
895       val |= cpu->ios[M6811_PORTA] & ~mask;
896       delta = val ^ cpu->ios[M6811_PORTA];
897       cpu->ios[M6811_PORTA] = val;
898       if (delta & 0x80)
899         {
900           /* Pulse accumulator is enabled.  */
901           if ((cpu->ios[M6811_PACTL] & M6811_PAEN)
902               && !(cpu->ios[M6811_PACTL] & M6811_PAMOD))
903             {
904               int inc;
905
906               /* Increment event counter according to rising/falling edge.  */
907               if (cpu->ios[M6811_PACTL] & M6811_PEDGE)
908                 inc = (val & 0x80) ? 1 : 0;
909               else
910                 inc = (val & 0x80) ? 0 : 1;
911
912               cpu->ios[M6811_PACNT] += inc;
913
914               /* Event counter overflowed.  */
915               if (inc && cpu->ios[M6811_PACNT] == 0)
916                 {
917                   cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
918                   check_interrupts = 1;
919                 }
920             }
921         }
922
923       /* Scan IC3, IC2 and IC1.  Bit number is 3 - i.  */
924       for (i = 0; i < 3; i++)
925         {
926           uint8 mask = (1 << i);
927           
928           if (delta & mask)
929             {
930               uint8 edge;
931               int captured;
932
933               edge = cpu->ios[M6811_TCTL2];
934               edge = (edge >> (2 * i)) & 0x3;
935               switch (edge)
936                 {
937                 case 0:
938                   captured = 0;
939                   break;
940                 case 1:
941                   captured = (val & mask) != 0;
942                   break;
943                 case 2:
944                   captured = (val & mask) == 0;
945                   break;
946                 default:
947                   captured = 1;
948                   break;
949                 }
950               if (captured)
951                 {
952                   cpu->ios[M6811_TFLG1] |= (1 << i);
953                   hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
954                   check_interrupts = 1;
955                 }
956             }
957         }
958       break;
959
960     case M6811_PORTC:
961       mask = cpu->ios[M6811_DDRC];
962       val = val & mask;
963       val |= cpu->ios[M6811_PORTC] & ~mask;
964       cpu->ios[M6811_PORTC] = val;
965       break;
966
967     case M6811_PORTD:
968       mask = cpu->ios[M6811_DDRD];
969       val = val & mask;
970       val |= cpu->ios[M6811_PORTD] & ~mask;
971       cpu->ios[M6811_PORTD] = val;
972       break;
973
974     default:
975       break;
976     }
977
978   if (check_interrupts)
979     interrupts_update_pending (&cpu->cpu_interrupts);
980 }
981
982 static void
983 m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
984                      unsigned_word addr, uint8 val)
985 {
986   switch (addr)
987     {
988     case M6811_PORTA:
989       hw_port_event (me, PORT_A, val);
990       break;
991
992     case M6811_PIOC:
993       break;
994
995     case M6811_PORTC:
996       hw_port_event (me, PORT_C, val);
997       break;
998
999     case M6811_PORTB:
1000       hw_port_event (me, PORT_B, val);
1001       break;
1002
1003     case M6811_PORTCL:
1004       break;
1005
1006     case M6811_DDRC:
1007       break;
1008
1009     case M6811_PORTD:
1010       hw_port_event (me, PORT_D, val);
1011       break;
1012
1013     case M6811_DDRD:
1014       break;
1015
1016     case M6811_TMSK2:
1017       
1018       break;
1019       
1020       /* Change the RAM and I/O mapping.  */
1021     case M6811_INIT:
1022       {
1023         uint8 old_bank = cpu->ios[M6811_INIT];
1024         
1025         cpu->ios[M6811_INIT] = val;
1026
1027         /* Update IO mapping.  Detach from the old address
1028            and attach to the new one.  */
1029         if ((old_bank & 0x0F) != (val & 0x0F))
1030           {
1031             struct m68hc11cpu *controller = hw_data (me);
1032
1033             hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
1034                                controller->attach_space,
1035                                controller->attach_address,
1036                                controller->attach_size,
1037                                me);
1038             controller->attach_address = (val & 0x0F0) << 12;
1039             hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
1040                                controller->attach_space,
1041                                controller->attach_address,
1042                                controller->attach_size,
1043                                me);
1044           }
1045         if ((old_bank & 0xF0) != (val & 0xF0))
1046           {
1047             ;
1048           }
1049         return;
1050       }
1051
1052     /* Writing the config is similar to programing the eeprom.
1053        The config register value is the last byte of the EEPROM.
1054        This last byte is not mapped in memory (that's why we have
1055        to add '1' to 'end_addr').  */
1056     case M6811_CONFIG:
1057       {
1058         return;
1059       }
1060       
1061
1062       /* COP reset.  */
1063     case M6811_COPRST:
1064       if (val == 0xAA && cpu->ios[addr] == 0x55)
1065         {
1066           val = 0;
1067           /* COP reset here.  */
1068         }
1069       break;
1070       
1071     default:
1072       break;
1073
1074     }
1075   cpu->ios[addr] = val;
1076 }
1077
1078 static unsigned
1079 m68hc11cpu_io_write_buffer (struct hw *me,
1080                             const void *source,
1081                             int space,
1082                             unsigned_word base,
1083                             unsigned nr_bytes)
1084 {
1085   SIM_DESC sd;
1086   struct m68hc11cpu *controller = hw_data (me);
1087   unsigned byte;
1088   sim_cpu *cpu;
1089   int result;
1090
1091   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
1092
1093   sd = hw_system (me); 
1094   cpu = STATE_CPU (sd, 0);  
1095
1096   if (base >= cpu->bank_start && base < cpu->bank_end)
1097     {
1098       address_word virt_addr = phys_to_virt (cpu, base);
1099       if (virt_addr != base)
1100         return sim_core_write_buffer (sd, cpu, space, source,
1101                                       virt_addr, nr_bytes);
1102     }
1103   base -= controller->attach_address;
1104   result = sim_core_write_buffer (sd, cpu,
1105                                   io_map, source, base, nr_bytes);
1106   if (result > 0)
1107     return result;
1108
1109   byte = 0;
1110   while (nr_bytes)
1111     {
1112       uint8 val;
1113       if (base >= controller->attach_size)
1114         break;
1115
1116       val = *((uint8*) source);
1117       m68hc11cpu_io_write (me, cpu, base, val);
1118       source = (char*) source + 1;
1119       base++;
1120       byte++;
1121       nr_bytes--;
1122     }
1123   return byte;
1124 }
1125
1126 const struct hw_descriptor dv_m68hc11_descriptor[] = {
1127   { "m68hc11", m68hc11cpu_finish },
1128   { "m68hc12", m68hc11cpu_finish },
1129   { NULL },
1130 };
1131