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