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.)
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.
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.
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/>.
21 /* This must come before any other includes. */
27 #include "sim-options.h"
32 #include "m68hc11-sim.h"
36 m68hc11cpu - m68hc11 cpu virtual device
37 m68hc12cpu - m68hc12 cpu virtual device
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.
50 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
54 Frequency of the quartz used by the processor.
56 mode [single | expanded | bootstrap | test]
58 Cpu operating mode (the MODA and MODB external pins).
65 Reset the cpu and generates a cpu-reset event (used to reset
70 Deliver a non-maskable interrupt to the processor.
77 Allow an external device to set the value of port A, C or D inputs.
82 Event generated after the CPU performs a reset.
90 Event generated when the value of the output port A, B, C or D
96 When delivering an interrupt, this code assumes that there is only
97 one processor (number 0).
103 OPTION_OSC_SET
= OPTION_START
,
108 static DECLARE_OPTION_HANDLER (m68hc11_option_handler
);
110 static const OPTION m68hc11_options
[] =
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
},
122 { {NULL
, no_argument
, NULL
, 0}, '\0', NULL
, NULL
, NULL
}
130 struct hw_event
*event
;
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)
143 /* Pending interrupts for delivery by event handler. */
147 struct hw_event
*event
;
148 unsigned_word attach_address
;
149 unsigned int attach_size
;
152 struct input_osc oscillators
[NR_OSC
];
157 /* input port ID's */
176 static const struct hw_port_descriptor m68hc11cpu_ports
[] = {
178 /* Interrupt inputs. */
179 { "reset", RESET_PORT
, 0, input_port
, },
180 { "nmi", NMI_PORT
, 0, input_port
, },
181 { "irq", IRQ_PORT
, 0, input_port
, },
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
, },
187 { "cpu-write-port", CPU_WRITE_PORT
, 0, input_port
, },
189 /* Events generated for connection to other devices. */
190 { "cpu-reset", CPU_RESET_PORT
, 0, output_port
, },
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
, },
199 { "capture", CAPTURE
, 0, output_port
, },
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
;
208 /* Finish off the partially created hw device. Attach our local
209 callbacks. Wire up our port names etc. */
211 static hw_port_event_method m68hc11cpu_port_event
;
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
,
217 static void reset_oscillators (struct hw
*me
);
220 dv_m6811_attach_address_callback (struct hw
*me
,
224 address_word nr_bytes
,
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
,
233 sim_core_attach (hw_system (me
),
236 access_read_write_exec
,
245 /*printf("Attach from sub device: %d\n", (long) addr);*/
246 sim_core_attach (hw_system (me
),
259 m68hc11_delete (struct hw
* me
)
261 struct m68hc11cpu
*controller
;
263 controller
= hw_data (me
);
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
);
274 attach_m68hc11_regs (struct hw
*me
,
275 struct m68hc11cpu
*controller
)
279 struct m68hc11_sim_cpu
*m68hc11_cpu
;
280 reg_property_spec reg
;
281 const char *cpu_mode
;
283 if (hw_find_property (me
, "reg") == NULL
)
284 hw_abort (me
, "Missing \"reg\" property");
286 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
287 hw_abort (me
, "\"reg\" property must contain one addr/size entry");
289 hw_unit_address_to_attach_address (hw_parent (me
),
291 &controller
->attach_space
,
292 &controller
->attach_address
,
294 hw_unit_size_to_attach_size (hw_parent (me
),
296 &controller
->attach_size
, me
);
298 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
,
299 controller
->attach_space
,
300 controller
->attach_address
,
301 controller
->attach_size
,
303 set_hw_delete (me
, m68hc11_delete
);
305 /* Get cpu frequency. */
307 cpu
= STATE_CPU (sd
, 0);
308 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
309 if (hw_find_property (me
, "clock") != NULL
)
311 m68hc11_cpu
->cpu_frequency
= hw_find_integer_property (me
, "clock");
315 m68hc11_cpu
->cpu_frequency
= 8*1000*1000;
318 if (hw_find_property (me
, "use_bank") != NULL
)
319 hw_attach_address (hw_parent (me
), 0,
321 m68hc11_cpu
->bank_start
,
322 m68hc11_cpu
->bank_end
- m68hc11_cpu
->bank_start
,
325 cpu_mode
= "expanded";
326 if (hw_find_property (me
, "mode") != NULL
)
327 cpu_mode
= hw_find_string_property (me
, "mode");
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;
336 m68hc11_cpu
->cpu_mode
= M6811_MDA
;
338 controller
->last_oscillator
= 0;
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);
346 /* port B is output only. */
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);
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);
366 /* Add oscillator commands. */
367 sim_add_option_table (sd
, 0, m68hc11_options
);
371 m68hc11cpu_finish (struct hw
*me
)
373 struct m68hc11cpu
*controller
;
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
);
383 set_hw_ioctl (me
, m68hc11_ioctl
);
385 me
->to_ioctl
= m68hc11_ioctl
;
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
;
394 attach_m68hc11_regs (me
, controller
);
397 /* An event arrives on an interrupt port. */
400 deliver_m68hc11cpu_interrupt (struct hw
*me
, void *data
)
405 make_oscillator (struct m68hc11cpu
*controller
, const char *name
,
406 uint16_t addr
, uint8_t mask
)
408 struct input_osc
*osc
;
410 if (controller
->last_oscillator
>= NR_OSC
)
411 hw_abort (0, "Too many oscillators");
413 osc
= &controller
->oscillators
[controller
->last_oscillator
];
417 controller
->last_oscillator
++;
420 /* Find the oscillator given the input port name. */
421 static struct input_osc
*
422 find_oscillator (struct m68hc11cpu
*controller
, const char *name
)
426 for (i
= 0; i
< controller
->last_oscillator
; i
++)
427 if (strcasecmp (controller
->oscillators
[i
].name
, name
) == 0)
428 return &controller
->oscillators
[i
];
434 oscillator_handler (struct hw
*me
, void *data
)
436 struct input_osc
*osc
= (struct input_osc
*) data
;
439 struct m68hc11_sim_cpu
*m68hc11_cpu
;
444 cpu
= STATE_CPU (sd
, 0);
445 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
447 /* Change the input bit. */
448 osc
->value
^= osc
->mask
;
449 val
= m68hc11_cpu
->ios
[osc
->addr
] & ~osc
->mask
;
451 m68hc11cpu_set_port (me
, cpu
, osc
->addr
, val
);
453 /* Setup event to toggle the bit. */
459 if (dt
&& --osc
->repeat
>= 0)
461 sim_events
*events
= STATE_EVENTS (sd
);
463 dt
+= events
->nr_ticks_to_process
;
464 osc
->event
= hw_event_queue_schedule (me
, dt
, oscillator_handler
, osc
);
471 reset_oscillators (struct hw
*me
)
473 struct m68hc11cpu
*controller
= hw_data (me
);
476 for (i
= 0; i
< controller
->last_oscillator
; i
++)
478 if (controller
->oscillators
[i
].event
)
480 hw_event_queue_deschedule (me
, controller
->oscillators
[i
].event
);
481 controller
->oscillators
[i
].event
= 0;
487 m68hc11cpu_port_event (struct hw
*me
,
493 struct m68hc11cpu
*controller
= hw_data (me
);
498 cpu
= STATE_CPU (sd
, 0);
502 HW_TRACE ((me
, "port-in reset"));
504 /* The reset is made in 3 steps:
505 - First, cleanup the current sim_cpu struct.
507 - Restart the cpu for the reset (get the CPU mode from the
508 CONFIG register that gets initialized by EEPROM device). */
510 reset_oscillators (me
);
511 hw_port_event (me
, CPU_RESET_PORT
, 1);
516 controller
->pending_nmi
= 1;
517 HW_TRACE ((me
, "port-in nmi"));
521 /* level == 0 means that the interrupt was cleared. */
523 controller
->pending_level
= -1; /* signal end of interrupt */
525 controller
->pending_level
= level
;
526 HW_TRACE ((me
, "port-in level=%d", level
));
530 m68hc11cpu_set_port (me
, cpu
, M6811_PORTA
, level
);
534 m68hc11cpu_set_port (me
, cpu
, M6811_PORTC
, level
);
538 m68hc11cpu_set_port (me
, cpu
, M6811_PORTD
, level
);
545 hw_abort (me
, "bad switch");
549 /* Schedule an event to be delivered immediately after current
551 if(controller
->event
!= NULL
)
552 hw_event_queue_deschedule(me
, controller
->event
);
554 hw_event_queue_schedule (me
, 0, deliver_m68hc11cpu_interrupt
, NULL
);
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" },
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" },
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)" },
586 m68hc11_info (struct hw
*me
)
591 struct m68hc11_sim_cpu
*m68hc11_cpu
;
595 cpu
= STATE_CPU (sd
, 0);
596 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
598 base
= cpu_get_io_base (cpu
);
599 sim_io_printf (sd
, "M68HC11:\n");
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
)
605 case M6811_MDA
| M6811_SMOD
:
606 sim_io_printf (sd
, "[test]\n");
609 sim_io_printf (sd
, "[bootstrap]\n");
612 sim_io_printf (sd
, "[extended]\n");
615 sim_io_printf (sd
, "[single]\n");
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");
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");
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));
635 interrupts_info (sd
, &m68hc11_cpu
->cpu_interrupts
);
639 m68hc11_ioctl (struct hw
*me
,
640 hw_ioctl_request request
,
647 /* Setup an oscillator on an input port.
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.
652 The oscillator frequency is therefore 1 / (ton + toff).
654 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
657 m68hc11cpu_set_oscillator (SIM_DESC sd
, const char *port
,
658 double ton
, double toff
, int64_t repeat
)
661 struct m68hc11_sim_cpu
*m68hc11_cpu
;
662 struct input_osc
*osc
;
665 cpu
= STATE_CPU (sd
, 0);
666 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
668 /* Find oscillator that corresponds to the input port. */
669 osc
= find_oscillator (hw_data (m68hc11_cpu
->hw_cpu
), port
);
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)
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)
685 osc
->repeat
= repeat
;
687 hw_event_queue_deschedule (m68hc11_cpu
->hw_cpu
, osc
->event
);
689 osc
->event
= hw_event_queue_schedule (m68hc11_cpu
->hw_cpu
,
690 osc
->value
? osc
->on_time
692 oscillator_handler
, osc
);
696 /* Clear the oscillator. */
698 m68hc11cpu_clear_oscillator (SIM_DESC sd
, const char *port
)
701 struct m68hc11_sim_cpu
*m68hc11_cpu
;
702 struct input_osc
*osc
;
704 cpu
= STATE_CPU (sd
, 0);
705 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
706 osc
= find_oscillator (hw_data (m68hc11_cpu
->hw_cpu
), port
);
711 hw_event_queue_deschedule (m68hc11_cpu
->hw_cpu
, osc
->event
);
718 get_frequency (const char *s
, double *f
)
728 if (strcasecmp (p
, "khz") == 0)
730 else if (strcasecmp (p
, "mhz") == 0)
732 else if (strcasecmp (p
, "hz") != 0)
739 m68hc11_option_handler (SIM_DESC sd
, sim_cpu
*cpu
,
740 int opt
, char *arg
, int is_command
)
742 struct m68hc11_sim_cpu
*m68hc11_cpu
;
743 struct m68hc11cpu
*controller
;
747 int title_printed
= 0;
750 cpu
= STATE_CPU (sd
, 0);
751 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
753 controller
= hw_data (m68hc11_cpu
->hw_cpu
);
757 p
= strchr (arg
, ',');
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
,
767 1.0 / (f
* 2.0), LONG_MAX
))
768 sim_io_eprintf (sd
, "Invalid input port: '%s'\n", arg
);
771 case OPTION_OSC_CLEAR
:
772 if (m68hc11cpu_clear_oscillator (sd
, arg
) != 0)
773 sim_io_eprintf (sd
, "Invalid input port: '%s'\n", arg
);
776 case OPTION_OSC_INFO
:
777 for (i
= 0; i
< controller
->last_oscillator
; i
++)
780 struct input_osc
*osc
;
782 osc
= &controller
->oscillators
[i
];
789 if (title_printed
== 0)
792 sim_io_printf (sd
, " PORT Frequency Current"
793 " Next Transition time\n");
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
);
801 sprintf (freq
, "%6.2f", f
/ 1000.0);
803 sprintf (freq
, "%6.2f", f
);
804 cur_value
= osc
->value
? 1 : 0;
805 next_value
= osc
->value
? 0 : 1;
807 sim_io_printf (sd
, " %4.4s %8.8s khz"
810 cur_value
, next_value
,
811 cycle_to_string (cpu
, t
,
812 PRINT_TIME
| PRINT_CYCLE
));
814 sim_io_printf (sd
, " %4.4s %8.8s hz "
817 cur_value
, next_value
,
818 cycle_to_string (cpu
, t
,
819 PRINT_TIME
| PRINT_CYCLE
));
828 /* generic read/write */
831 m68hc11cpu_io_read_buffer (struct hw
*me
,
838 struct m68hc11cpu
*controller
= hw_data (me
);
840 struct m68hc11_sim_cpu
*m68hc11_cpu
;
844 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
847 cpu
= STATE_CPU (sd
, 0);
848 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
850 if (base
>= m68hc11_cpu
->bank_start
&& base
< m68hc11_cpu
->bank_end
)
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
);
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
);
867 if (base
>= controller
->attach_size
)
870 memcpy (dest
, &m68hc11_cpu
->ios
[base
], 1);
871 dest
= (char*) dest
+ 1;
880 m68hc11cpu_set_port (struct hw
*me
, sim_cpu
*cpu
,
881 unsigned addr
, uint8_t val
)
883 struct m68hc11_sim_cpu
*m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
886 int check_interrupts
= 0;
892 if (m68hc11_cpu
->ios
[M6811_PACTL
] & M6811_DDRA7
)
898 val
|= m68hc11_cpu
->ios
[M6811_PORTA
] & ~mask
;
899 delta
= val
^ m68hc11_cpu
->ios
[M6811_PORTA
];
900 m68hc11_cpu
->ios
[M6811_PORTA
] = val
;
903 /* Pulse accumulator is enabled. */
904 if ((m68hc11_cpu
->ios
[M6811_PACTL
] & M6811_PAEN
)
905 && !(m68hc11_cpu
->ios
[M6811_PACTL
] & M6811_PAMOD
))
909 /* Increment event counter according to rising/falling edge. */
910 if (m68hc11_cpu
->ios
[M6811_PACTL
] & M6811_PEDGE
)
911 inc
= (val
& 0x80) ? 1 : 0;
913 inc
= (val
& 0x80) ? 0 : 1;
915 m68hc11_cpu
->ios
[M6811_PACNT
] += inc
;
917 /* Event counter overflowed. */
918 if (inc
&& m68hc11_cpu
->ios
[M6811_PACNT
] == 0)
920 m68hc11_cpu
->ios
[M6811_TFLG2
] |= M6811_PAOVI
;
921 check_interrupts
= 1;
926 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
927 for (i
= 0; i
< 3; i
++)
936 edge
= m68hc11_cpu
->ios
[M6811_TCTL2
];
937 edge
= (edge
>> (2 * i
)) & 0x3;
944 captured
= (val
& mask
) != 0;
947 captured
= (val
& mask
) == 0;
955 m68hc11_cpu
->ios
[M6811_TFLG1
] |= (1 << i
);
956 hw_port_event (me
, CAPTURE
, M6811_TIC1
+ 3 - i
);
957 check_interrupts
= 1;
964 mask
= m68hc11_cpu
->ios
[M6811_DDRC
];
966 val
|= m68hc11_cpu
->ios
[M6811_PORTC
] & ~mask
;
967 m68hc11_cpu
->ios
[M6811_PORTC
] = val
;
971 mask
= m68hc11_cpu
->ios
[M6811_DDRD
];
973 val
|= m68hc11_cpu
->ios
[M6811_PORTD
] & ~mask
;
974 m68hc11_cpu
->ios
[M6811_PORTD
] = val
;
981 if (check_interrupts
)
982 interrupts_update_pending (&m68hc11_cpu
->cpu_interrupts
);
986 m68hc11cpu_io_write (struct hw
*me
, sim_cpu
*cpu
,
987 unsigned_word addr
, uint8_t val
)
989 struct m68hc11_sim_cpu
*m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
994 hw_port_event (me
, PORT_A
, val
);
1001 hw_port_event (me
, PORT_C
, val
);
1005 hw_port_event (me
, PORT_B
, val
);
1015 hw_port_event (me
, PORT_D
, val
);
1025 /* Change the RAM and I/O mapping. */
1028 uint8_t old_bank
= m68hc11_cpu
->ios
[M6811_INIT
];
1030 m68hc11_cpu
->ios
[M6811_INIT
] = val
;
1032 /* Update IO mapping. Detach from the old address
1033 and attach to the new one. */
1034 if ((old_bank
& 0x0F) != (val
& 0x0F))
1036 struct m68hc11cpu
*controller
= hw_data (me
);
1038 hw_detach_address (hw_parent (me
), M6811_IO_LEVEL
,
1039 controller
->attach_space
,
1040 controller
->attach_address
,
1041 controller
->attach_size
,
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
,
1050 if ((old_bank
& 0xF0) != (val
& 0xF0))
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'). */
1069 if (val
== 0xAA && m68hc11_cpu
->ios
[addr
] == 0x55)
1072 /* COP reset here. */
1080 m68hc11_cpu
->ios
[addr
] = val
;
1084 m68hc11cpu_io_write_buffer (struct hw
*me
,
1091 struct m68hc11cpu
*controller
= hw_data (me
);
1094 struct m68hc11_sim_cpu
*m68hc11_cpu
;
1097 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
1099 sd
= hw_system (me
);
1100 cpu
= STATE_CPU (sd
, 0);
1101 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
1103 if (base
>= m68hc11_cpu
->bank_start
&& base
< m68hc11_cpu
->bank_end
)
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
);
1110 base
-= controller
->attach_address
;
1111 result
= sim_core_write_buffer (sd
, cpu
,
1112 io_map
, source
, base
, nr_bytes
);
1120 if (base
>= controller
->attach_size
)
1123 val
= *((uint8_t*) source
);
1124 m68hc11cpu_io_write (me
, cpu
, base
, val
);
1125 source
= (char*) source
+ 1;
1133 const struct hw_descriptor dv_m68hc11_descriptor
[] = {
1134 { "m68hc11", m68hc11cpu_finish
},
1135 { "m68hc12", m68hc11cpu_finish
},