1 /*  dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2     Copyright (C) 1999-2013 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
dv_m6811_attach_address_callback(struct hw * me,int level,int space,address_word addr,address_word nr_bytes,struct hw * client)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
dv_m6811_detach_address_callback(struct hw * me,int level,int space,address_word addr,address_word nr_bytes,struct hw * client)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
m68hc11_delete(struct hw * me)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
attach_m68hc11_regs(struct hw * me,struct m68hc11cpu * controller)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
m68hc11cpu_finish(struct hw * me)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
deliver_m68hc11cpu_interrupt(struct hw * me,void * data)406 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
407 {
408 }
409 
410 static void
make_oscillator(struct m68hc11cpu * controller,const char * name,uint16 addr,uint8 mask)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 *
find_oscillator(struct m68hc11cpu * controller,const char * name)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
oscillator_handler(struct hw * me,void * data)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
reset_oscillators(struct hw * me)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
m68hc11cpu_port_event(struct hw * me,int my_port,struct hw * source,int source_port,int level)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
m68hc11_info(struct hw * me)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
m68hc11_ioctl(struct hw * me,hw_ioctl_request request,va_list ap)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
m68hc11cpu_set_oscillator(SIM_DESC sd,const char * port,double ton,double toff,signed64 repeat)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
m68hc11cpu_clear_oscillator(SIM_DESC sd,const char * port)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
get_frequency(const char * s,double * f)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
m68hc11_option_handler(SIM_DESC sd,sim_cpu * cpu,int opt,char * arg,int is_command)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
m68hc11cpu_io_read_buffer(struct hw * me,void * dest,int space,unsigned_word base,unsigned nr_bytes)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
m68hc11cpu_set_port(struct hw * me,sim_cpu * cpu,unsigned addr,uint8 val)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
m68hc11cpu_io_write(struct hw * me,sim_cpu * cpu,unsigned_word addr,uint8 val)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
m68hc11cpu_io_write_buffer(struct hw * me,const void * source,int space,unsigned_word base,unsigned nr_bytes)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 
1131