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