1 /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2 Copyright (C) 1999-2022 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"
34 m68hc11cpu - m68hc11 cpu virtual device
35 m68hc12cpu - m68hc12 cpu virtual device
39 Implements the external m68hc11/68hc12 functionality. This includes
40 the delivery of of interrupts generated from other devices and the
41 handling of device specific registers.
48 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
52 Frequency of the quartz used by the processor.
54 mode [single | expanded | bootstrap | test]
56 Cpu operating mode (the MODA and MODB external pins).
63 Reset the cpu and generates a cpu-reset event (used to reset
68 Deliver a non-maskable interrupt to the processor.
75 Allow an external device to set the value of port A, C or D inputs.
80 Event generated after the CPU performs a reset.
88 Event generated when the value of the output port A, B, C or D
94 When delivering an interrupt, this code assumes that there is only
95 one processor (number 0).
101 OPTION_OSC_SET
= OPTION_START
,
106 static DECLARE_OPTION_HANDLER (m68hc11_option_handler
);
108 static const OPTION m68hc11_options
[] =
110 { {"osc-set", required_argument
, NULL
, OPTION_OSC_SET
},
111 '\0', "BIT,FREQ", "Set the oscillator on input port BIT",
112 m68hc11_option_handler
},
113 { {"osc-clear", required_argument
, NULL
, OPTION_OSC_CLEAR
},
114 '\0', "BIT", "Clear oscillator on input port BIT",
115 m68hc11_option_handler
},
116 { {"osc-info", no_argument
, NULL
, OPTION_OSC_INFO
},
117 '\0', NULL
, "Print information about current input oscillators",
118 m68hc11_option_handler
},
120 { {NULL
, no_argument
, NULL
, 0}, '\0', NULL
, NULL
, NULL
}
128 struct hw_event
*event
;
135 #define NR_PORT_A_OSC (4)
136 #define NR_PORT_B_OSC (0)
137 #define NR_PORT_C_OSC (8)
138 #define NR_PORT_D_OSC (6)
139 #define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC)
141 /* Pending interrupts for delivery by event handler. */
145 struct hw_event
*event
;
146 unsigned_word attach_address
;
147 unsigned int attach_size
;
150 struct input_osc oscillators
[NR_OSC
];
155 /* input port ID's */
174 static const struct hw_port_descriptor m68hc11cpu_ports
[] = {
176 /* Interrupt inputs. */
177 { "reset", RESET_PORT
, 0, input_port
, },
178 { "nmi", NMI_PORT
, 0, input_port
, },
179 { "irq", IRQ_PORT
, 0, input_port
, },
181 { "set-port-a", SET_PORT_A
, 0, input_port
, },
182 { "set-port-c", SET_PORT_C
, 0, input_port
, },
183 { "set-port-d", SET_PORT_D
, 0, input_port
, },
185 { "cpu-write-port", CPU_WRITE_PORT
, 0, input_port
, },
187 /* Events generated for connection to other devices. */
188 { "cpu-reset", CPU_RESET_PORT
, 0, output_port
, },
190 /* Events generated when the corresponding port is
191 changed by the program. */
192 { "port-a", PORT_A
, 0, output_port
, },
193 { "port-b", PORT_B
, 0, output_port
, },
194 { "port-c", PORT_C
, 0, output_port
, },
195 { "port-d", PORT_D
, 0, output_port
, },
197 { "capture", CAPTURE
, 0, output_port
, },
202 static hw_io_read_buffer_method m68hc11cpu_io_read_buffer
;
203 static hw_io_write_buffer_method m68hc11cpu_io_write_buffer
;
204 static hw_ioctl_method m68hc11_ioctl
;
206 /* Finish off the partially created hw device. Attach our local
207 callbacks. Wire up our port names etc. */
209 static hw_port_event_method m68hc11cpu_port_event
;
211 static void make_oscillator (struct m68hc11cpu
*controller
,
212 const char *id
, uint16_t addr
, uint8_t mask
);
213 static struct input_osc
*find_oscillator (struct m68hc11cpu
*controller
,
215 static void reset_oscillators (struct hw
*me
);
218 dv_m6811_attach_address_callback (struct hw
*me
,
222 address_word nr_bytes
,
225 HW_TRACE ((me
, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
226 level
, space
, (unsigned long) addr
, (unsigned long) nr_bytes
,
231 sim_core_attach (hw_system (me
),
234 access_read_write_exec
,
243 /*printf("Attach from sub device: %d\n", (long) addr);*/
244 sim_core_attach (hw_system (me
),
257 dv_m6811_detach_address_callback (struct hw
*me
,
261 address_word nr_bytes
,
264 sim_core_detach (hw_system (me
), NULL
, /*cpu*/
269 m68hc11_delete (struct hw
* me
)
271 struct m68hc11cpu
*controller
;
273 controller
= hw_data (me
);
275 reset_oscillators (me
);
276 hw_detach_address (me
, M6811_IO_LEVEL
,
277 controller
->attach_space
,
278 controller
->attach_address
,
279 controller
->attach_size
, me
);
284 attach_m68hc11_regs (struct hw
*me
,
285 struct m68hc11cpu
*controller
)
289 reg_property_spec reg
;
290 const char *cpu_mode
;
292 if (hw_find_property (me
, "reg") == NULL
)
293 hw_abort (me
, "Missing \"reg\" property");
295 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
296 hw_abort (me
, "\"reg\" property must contain one addr/size entry");
298 hw_unit_address_to_attach_address (hw_parent (me
),
300 &controller
->attach_space
,
301 &controller
->attach_address
,
303 hw_unit_size_to_attach_size (hw_parent (me
),
305 &controller
->attach_size
, me
);
307 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
,
308 controller
->attach_space
,
309 controller
->attach_address
,
310 controller
->attach_size
,
312 set_hw_delete (me
, m68hc11_delete
);
314 /* Get cpu frequency. */
316 cpu
= STATE_CPU (sd
, 0);
317 if (hw_find_property (me
, "clock") != NULL
)
319 cpu
->cpu_frequency
= hw_find_integer_property (me
, "clock");
323 cpu
->cpu_frequency
= 8*1000*1000;
326 if (hw_find_property (me
, "use_bank") != NULL
)
327 hw_attach_address (hw_parent (me
), 0,
330 cpu
->bank_end
- cpu
->bank_start
,
333 cpu_mode
= "expanded";
334 if (hw_find_property (me
, "mode") != NULL
)
335 cpu_mode
= hw_find_string_property (me
, "mode");
337 if (strcmp (cpu_mode
, "test") == 0)
338 cpu
->cpu_mode
= M6811_MDA
| M6811_SMOD
;
339 else if (strcmp (cpu_mode
, "bootstrap") == 0)
340 cpu
->cpu_mode
= M6811_SMOD
;
341 else if (strcmp (cpu_mode
, "single") == 0)
344 cpu
->cpu_mode
= M6811_MDA
;
346 controller
->last_oscillator
= 0;
348 /* Create oscillators for input port A. */
349 make_oscillator (controller
, "A7", M6811_PORTA
, 0x80);
350 make_oscillator (controller
, "A2", M6811_PORTA
, 0x04);
351 make_oscillator (controller
, "A1", M6811_PORTA
, 0x02);
352 make_oscillator (controller
, "A0", M6811_PORTA
, 0x01);
354 /* port B is output only. */
356 /* Create oscillators for input port C. */
357 make_oscillator (controller
, "C0", M6811_PORTC
, 0x01);
358 make_oscillator (controller
, "C1", M6811_PORTC
, 0x02);
359 make_oscillator (controller
, "C2", M6811_PORTC
, 0x04);
360 make_oscillator (controller
, "C3", M6811_PORTC
, 0x08);
361 make_oscillator (controller
, "C4", M6811_PORTC
, 0x10);
362 make_oscillator (controller
, "C5", M6811_PORTC
, 0x20);
363 make_oscillator (controller
, "C6", M6811_PORTC
, 0x40);
364 make_oscillator (controller
, "C7", M6811_PORTC
, 0x80);
366 /* Create oscillators for input port D. */
367 make_oscillator (controller
, "D0", M6811_PORTD
, 0x01);
368 make_oscillator (controller
, "D1", M6811_PORTD
, 0x02);
369 make_oscillator (controller
, "D2", M6811_PORTD
, 0x04);
370 make_oscillator (controller
, "D3", M6811_PORTD
, 0x08);
371 make_oscillator (controller
, "D4", M6811_PORTD
, 0x10);
372 make_oscillator (controller
, "D5", M6811_PORTD
, 0x20);
374 /* Add oscillator commands. */
375 sim_add_option_table (sd
, 0, m68hc11_options
);
379 m68hc11cpu_finish (struct hw
*me
)
381 struct m68hc11cpu
*controller
;
383 controller
= HW_ZALLOC (me
, struct m68hc11cpu
);
384 set_hw_data (me
, controller
);
385 set_hw_io_read_buffer (me
, m68hc11cpu_io_read_buffer
);
386 set_hw_io_write_buffer (me
, m68hc11cpu_io_write_buffer
);
387 set_hw_ports (me
, m68hc11cpu_ports
);
388 set_hw_port_event (me
, m68hc11cpu_port_event
);
389 set_hw_attach_address (me
, dv_m6811_attach_address_callback
);
390 set_hw_detach_address (me
, dv_m6811_detach_address_callback
);
392 set_hw_ioctl (me
, m68hc11_ioctl
);
394 me
->to_ioctl
= m68hc11_ioctl
;
397 /* Initialize the pending interrupt flags. */
398 controller
->pending_level
= 0;
399 controller
->pending_reset
= 0;
400 controller
->pending_nmi
= 0;
401 controller
->event
= NULL
;
403 attach_m68hc11_regs (me
, controller
);
406 /* An event arrives on an interrupt port. */
409 deliver_m68hc11cpu_interrupt (struct hw
*me
, void *data
)
414 make_oscillator (struct m68hc11cpu
*controller
, const char *name
,
415 uint16_t addr
, uint8_t mask
)
417 struct input_osc
*osc
;
419 if (controller
->last_oscillator
>= NR_OSC
)
420 hw_abort (0, "Too many oscillators");
422 osc
= &controller
->oscillators
[controller
->last_oscillator
];
426 controller
->last_oscillator
++;
429 /* Find the oscillator given the input port name. */
430 static struct input_osc
*
431 find_oscillator (struct m68hc11cpu
*controller
, const char *name
)
435 for (i
= 0; i
< controller
->last_oscillator
; i
++)
436 if (strcasecmp (controller
->oscillators
[i
].name
, name
) == 0)
437 return &controller
->oscillators
[i
];
443 oscillator_handler (struct hw
*me
, void *data
)
445 struct input_osc
*osc
= (struct input_osc
*) data
;
452 cpu
= STATE_CPU (sd
, 0);
454 /* Change the input bit. */
455 osc
->value
^= osc
->mask
;
456 val
= cpu
->ios
[osc
->addr
] & ~osc
->mask
;
458 m68hc11cpu_set_port (me
, cpu
, osc
->addr
, val
);
460 /* Setup event to toggle the bit. */
466 if (dt
&& --osc
->repeat
>= 0)
468 sim_events
*events
= STATE_EVENTS (sd
);
470 dt
+= events
->nr_ticks_to_process
;
471 osc
->event
= hw_event_queue_schedule (me
, dt
, oscillator_handler
, osc
);
478 reset_oscillators (struct hw
*me
)
480 struct m68hc11cpu
*controller
= hw_data (me
);
483 for (i
= 0; i
< controller
->last_oscillator
; i
++)
485 if (controller
->oscillators
[i
].event
)
487 hw_event_queue_deschedule (me
, controller
->oscillators
[i
].event
);
488 controller
->oscillators
[i
].event
= 0;
494 m68hc11cpu_port_event (struct hw
*me
,
500 struct m68hc11cpu
*controller
= hw_data (me
);
505 cpu
= STATE_CPU (sd
, 0);
509 HW_TRACE ((me
, "port-in reset"));
511 /* The reset is made in 3 steps:
512 - First, cleanup the current sim_cpu struct.
514 - Restart the cpu for the reset (get the CPU mode from the
515 CONFIG register that gets initialized by EEPROM device). */
517 reset_oscillators (me
);
518 hw_port_event (me
, CPU_RESET_PORT
, 1);
523 controller
->pending_nmi
= 1;
524 HW_TRACE ((me
, "port-in nmi"));
528 /* level == 0 means that the interrupt was cleared. */
530 controller
->pending_level
= -1; /* signal end of interrupt */
532 controller
->pending_level
= level
;
533 HW_TRACE ((me
, "port-in level=%d", level
));
537 m68hc11cpu_set_port (me
, cpu
, M6811_PORTA
, level
);
541 m68hc11cpu_set_port (me
, cpu
, M6811_PORTC
, level
);
545 m68hc11cpu_set_port (me
, cpu
, M6811_PORTD
, level
);
552 hw_abort (me
, "bad switch");
556 /* Schedule an event to be delivered immediately after current
558 if(controller
->event
!= NULL
)
559 hw_event_queue_deschedule(me
, controller
->event
);
561 hw_event_queue_schedule (me
, 0, deliver_m68hc11cpu_interrupt
, NULL
);
565 io_reg_desc config_desc
[] = {
566 { M6811_NOSEC
, "NOSEC ", "Security Mode Disable" },
567 { M6811_NOCOP
, "NOCOP ", "COP System Disable" },
568 { M6811_ROMON
, "ROMON ", "Enable On-chip Rom" },
569 { M6811_EEON
, "EEON ", "Enable On-chip EEprom" },
573 io_reg_desc hprio_desc
[] = {
574 { M6811_RBOOT
, "RBOOT ", "Read Bootstrap ROM" },
575 { M6811_SMOD
, "SMOD ", "Special Mode" },
576 { M6811_MDA
, "MDA ", "Mode Select A" },
577 { M6811_IRV
, "IRV ", "Internal Read Visibility" },
581 io_reg_desc option_desc
[] = {
582 { M6811_ADPU
, "ADPU ", "A/D Powerup" },
583 { M6811_CSEL
, "CSEL ", "A/D/EE Charge pump clock source select" },
584 { M6811_IRQE
, "IRQE ", "IRQ Edge/Level sensitive" },
585 { M6811_DLY
, "DLY ", "Stop exit turn on delay" },
586 { M6811_CME
, "CME ", "Clock Monitor Enable" },
587 { M6811_CR1
, "CR1 ", "COP timer rate select (CR1)" },
588 { M6811_CR0
, "CR0 ", "COP timer rate select (CR0)" },
593 m68hc11_info (struct hw
*me
)
598 struct m68hc11sio
*controller
;
602 cpu
= STATE_CPU (sd
, 0);
603 controller
= hw_data (me
);
605 base
= cpu_get_io_base (cpu
);
606 sim_io_printf (sd
, "M68HC11:\n");
608 val
= cpu
->ios
[M6811_HPRIO
];
609 print_io_byte (sd
, "HPRIO ", hprio_desc
, val
, base
+ M6811_HPRIO
);
610 switch (cpu
->cpu_mode
)
612 case M6811_MDA
| M6811_SMOD
:
613 sim_io_printf (sd
, "[test]\n");
616 sim_io_printf (sd
, "[bootstrap]\n");
619 sim_io_printf (sd
, "[extended]\n");
622 sim_io_printf (sd
, "[single]\n");
626 val
= cpu
->ios
[M6811_CONFIG
];
627 print_io_byte (sd
, "CONFIG", config_desc
, val
, base
+ M6811_CONFIG
);
628 sim_io_printf (sd
, "\n");
630 val
= cpu
->ios
[M6811_OPTION
];
631 print_io_byte (sd
, "OPTION", option_desc
, val
, base
+ M6811_OPTION
);
632 sim_io_printf (sd
, "\n");
634 val
= cpu
->ios
[M6811_INIT
];
635 print_io_byte (sd
, "INIT ", 0, val
, base
+ M6811_INIT
);
636 sim_io_printf (sd
, "Ram = 0x%04x IO = 0x%04x\n",
637 (((uint16_t) (val
& 0xF0)) << 8),
638 (((uint16_t) (val
& 0x0F)) << 12));
642 interrupts_info (sd
, &cpu
->cpu_interrupts
);
646 m68hc11_ioctl (struct hw
*me
,
647 hw_ioctl_request request
,
654 /* Setup an oscillator on an input port.
656 TON represents the time in seconds that the input port should be set to 1.
657 TOFF is the time in seconds for the input port to be set to 0.
659 The oscillator frequency is therefore 1 / (ton + toff).
661 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
664 m68hc11cpu_set_oscillator (SIM_DESC sd
, const char *port
,
665 double ton
, double toff
, int64_t repeat
)
668 struct input_osc
*osc
;
671 cpu
= STATE_CPU (sd
, 0);
673 /* Find oscillator that corresponds to the input port. */
674 osc
= find_oscillator (hw_data (cpu
->hw_cpu
), port
);
678 /* Compute the ON time in cpu cycles. */
679 f
= (double) (cpu
->cpu_frequency
) * ton
;
680 osc
->on_time
= (int64_t) (f
/ 4.0);
681 if (osc
->on_time
< 1)
684 /* Compute the OFF time in cpu cycles. */
685 f
= (double) (cpu
->cpu_frequency
) * toff
;
686 osc
->off_time
= (int64_t) (f
/ 4.0);
687 if (osc
->off_time
< 1)
690 osc
->repeat
= repeat
;
692 hw_event_queue_deschedule (cpu
->hw_cpu
, osc
->event
);
694 osc
->event
= hw_event_queue_schedule (cpu
->hw_cpu
,
695 osc
->value
? osc
->on_time
697 oscillator_handler
, osc
);
701 /* Clear the oscillator. */
703 m68hc11cpu_clear_oscillator (SIM_DESC sd
, const char *port
)
706 struct input_osc
*osc
;
708 cpu
= STATE_CPU (sd
, 0);
709 osc
= find_oscillator (hw_data (cpu
->hw_cpu
), port
);
714 hw_event_queue_deschedule (cpu
->hw_cpu
, osc
->event
);
721 get_frequency (const char *s
, double *f
)
731 if (strcasecmp (p
, "khz") == 0)
733 else if (strcasecmp (p
, "mhz") == 0)
735 else if (strcasecmp (p
, "hz") != 0)
742 m68hc11_option_handler (SIM_DESC sd
, sim_cpu
*cpu
,
743 int opt
, char *arg
, int is_command
)
745 struct m68hc11cpu
*controller
;
749 int title_printed
= 0;
752 cpu
= STATE_CPU (sd
, 0);
754 controller
= hw_data (cpu
->hw_cpu
);
758 p
= strchr (arg
, ',');
763 sim_io_eprintf (sd
, "No frequency specified\n");
764 else if (get_frequency (p
, &f
) < 0 || f
< 1.0e-8)
765 sim_io_eprintf (sd
, "Invalid frequency: '%s'\n", p
);
766 else if (m68hc11cpu_set_oscillator (sd
, arg
,
768 1.0 / (f
* 2.0), LONG_MAX
))
769 sim_io_eprintf (sd
, "Invalid input port: '%s'\n", arg
);
772 case OPTION_OSC_CLEAR
:
773 if (m68hc11cpu_clear_oscillator (sd
, arg
) != 0)
774 sim_io_eprintf (sd
, "Invalid input port: '%s'\n", arg
);
777 case OPTION_OSC_INFO
:
778 for (i
= 0; i
< controller
->last_oscillator
; i
++)
781 struct input_osc
*osc
;
783 osc
= &controller
->oscillators
[i
];
791 if (title_printed
== 0)
794 sim_io_printf (sd
, " PORT Frequency Current"
795 " Next Transition time\n");
798 f
= (double) (osc
->on_time
+ osc
->off_time
);
799 f
= (double) (cpu
->cpu_frequency
/ 4) / f
;
800 t
= hw_event_remain_time (cpu
->hw_cpu
, osc
->event
);
803 sprintf (freq
, "%6.2f", f
/ 1000.0);
805 sprintf (freq
, "%6.2f", f
);
806 cur_value
= osc
->value
? 1 : 0;
807 next_value
= osc
->value
? 0 : 1;
809 sim_io_printf (sd
, " %4.4s %8.8s khz"
812 cur_value
, next_value
,
813 cycle_to_string (cpu
, t
,
814 PRINT_TIME
| PRINT_CYCLE
));
816 sim_io_printf (sd
, " %4.4s %8.8s hz "
819 cur_value
, next_value
,
820 cycle_to_string (cpu
, t
,
821 PRINT_TIME
| PRINT_CYCLE
));
830 /* generic read/write */
833 m68hc11cpu_io_read_buffer (struct hw
*me
,
840 struct m68hc11cpu
*controller
= hw_data (me
);
845 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
848 cpu
= STATE_CPU (sd
, 0);
850 if (base
>= cpu
->bank_start
&& base
< 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
, &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
)
885 int check_interrupts
= 0;
891 if (cpu
->ios
[M6811_PACTL
] & M6811_DDRA7
)
897 val
|= cpu
->ios
[M6811_PORTA
] & ~mask
;
898 delta
= val
^ cpu
->ios
[M6811_PORTA
];
899 cpu
->ios
[M6811_PORTA
] = val
;
902 /* Pulse accumulator is enabled. */
903 if ((cpu
->ios
[M6811_PACTL
] & M6811_PAEN
)
904 && !(cpu
->ios
[M6811_PACTL
] & M6811_PAMOD
))
908 /* Increment event counter according to rising/falling edge. */
909 if (cpu
->ios
[M6811_PACTL
] & M6811_PEDGE
)
910 inc
= (val
& 0x80) ? 1 : 0;
912 inc
= (val
& 0x80) ? 0 : 1;
914 cpu
->ios
[M6811_PACNT
] += inc
;
916 /* Event counter overflowed. */
917 if (inc
&& cpu
->ios
[M6811_PACNT
] == 0)
919 cpu
->ios
[M6811_TFLG2
] |= M6811_PAOVI
;
920 check_interrupts
= 1;
925 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
926 for (i
= 0; i
< 3; i
++)
928 uint8_t mask
= (1 << i
);
935 edge
= cpu
->ios
[M6811_TCTL2
];
936 edge
= (edge
>> (2 * i
)) & 0x3;
943 captured
= (val
& mask
) != 0;
946 captured
= (val
& mask
) == 0;
954 cpu
->ios
[M6811_TFLG1
] |= (1 << i
);
955 hw_port_event (me
, CAPTURE
, M6811_TIC1
+ 3 - i
);
956 check_interrupts
= 1;
963 mask
= cpu
->ios
[M6811_DDRC
];
965 val
|= cpu
->ios
[M6811_PORTC
] & ~mask
;
966 cpu
->ios
[M6811_PORTC
] = val
;
970 mask
= cpu
->ios
[M6811_DDRD
];
972 val
|= cpu
->ios
[M6811_PORTD
] & ~mask
;
973 cpu
->ios
[M6811_PORTD
] = val
;
980 if (check_interrupts
)
981 interrupts_update_pending (&cpu
->cpu_interrupts
);
985 m68hc11cpu_io_write (struct hw
*me
, sim_cpu
*cpu
,
986 unsigned_word addr
, uint8_t val
)
991 hw_port_event (me
, PORT_A
, val
);
998 hw_port_event (me
, PORT_C
, val
);
1002 hw_port_event (me
, PORT_B
, val
);
1012 hw_port_event (me
, PORT_D
, val
);
1022 /* Change the RAM and I/O mapping. */
1025 uint8_t old_bank
= cpu
->ios
[M6811_INIT
];
1027 cpu
->ios
[M6811_INIT
] = val
;
1029 /* Update IO mapping. Detach from the old address
1030 and attach to the new one. */
1031 if ((old_bank
& 0x0F) != (val
& 0x0F))
1033 struct m68hc11cpu
*controller
= hw_data (me
);
1035 hw_detach_address (hw_parent (me
), M6811_IO_LEVEL
,
1036 controller
->attach_space
,
1037 controller
->attach_address
,
1038 controller
->attach_size
,
1040 controller
->attach_address
= (val
& 0x0F0) << 12;
1041 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
,
1042 controller
->attach_space
,
1043 controller
->attach_address
,
1044 controller
->attach_size
,
1047 if ((old_bank
& 0xF0) != (val
& 0xF0))
1054 /* Writing the config is similar to programing the eeprom.
1055 The config register value is the last byte of the EEPROM.
1056 This last byte is not mapped in memory (that's why we have
1057 to add '1' to 'end_addr'). */
1066 if (val
== 0xAA && cpu
->ios
[addr
] == 0x55)
1069 /* COP reset here. */
1077 cpu
->ios
[addr
] = val
;
1081 m68hc11cpu_io_write_buffer (struct hw
*me
,
1088 struct m68hc11cpu
*controller
= hw_data (me
);
1093 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
1095 sd
= hw_system (me
);
1096 cpu
= STATE_CPU (sd
, 0);
1098 if (base
>= cpu
->bank_start
&& base
< cpu
->bank_end
)
1100 address_word virt_addr
= phys_to_virt (cpu
, base
);
1101 if (virt_addr
!= base
)
1102 return sim_core_write_buffer (sd
, cpu
, space
, source
,
1103 virt_addr
, nr_bytes
);
1105 base
-= controller
->attach_address
;
1106 result
= sim_core_write_buffer (sd
, cpu
,
1107 io_map
, source
, base
, nr_bytes
);
1115 if (base
>= controller
->attach_size
)
1118 val
= *((uint8_t*) source
);
1119 m68hc11cpu_io_write (me
, cpu
, base
, val
);
1120 source
= (char*) source
+ 1;
1128 const struct hw_descriptor dv_m68hc11_descriptor
[] = {
1129 { "m68hc11", m68hc11cpu_finish
},
1130 { "m68hc12", m68hc11cpu_finish
},