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