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