Home | History | Annotate | Line # | Download | only in m68hc11
      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 (at) 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
    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
    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
    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
    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
    400 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
    401 {
    402 }
    403 
    404 static void
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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