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