1 /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@worldnet.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 2 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, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 m68hc11cpu - m68hc11 cpu virtual device
29 m68hc12cpu - m68hc12 cpu virtual device
33 Implements the external m68hc11/68hc12 functionality. This includes
34 the delivery of of interrupts generated from other devices and the
35 handling of device specific registers.
42 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
46 Frequency of the quartz used by the processor.
48 mode [single | expanded | bootstrap | test]
50 Cpu operating mode (the MODA and MODB external pins).
57 Reset the cpu and generates a cpu-reset event (used to reset
62 Deliver a non-maskable interrupt to the processor.
67 Event generated after the CPU performs a reset.
72 When delivering an interrupt, this code assumes that there is only
73 one processor (number 0).
80 /* Pending interrupts for delivery by event handler. */
84 struct hw_event
*event
;
85 unsigned_word attach_address
;
102 static const struct hw_port_descriptor m68hc11cpu_ports
[] = {
104 /* Interrupt inputs. */
105 { "reset", RESET_PORT
, 0, input_port
, },
106 { "nmi", NMI_PORT
, 0, input_port
, },
107 { "irq", IRQ_PORT
, 0, input_port
, },
109 /* Events generated for connection to other devices. */
110 { "cpu-reset", CPU_RESET_PORT
, 0, output_port
, },
115 static hw_io_read_buffer_method m68hc11cpu_io_read_buffer
;
116 static hw_io_write_buffer_method m68hc11cpu_io_write_buffer
;
117 static hw_ioctl_method m68hc11_ioctl
;
119 /* Finish off the partially created hw device. Attach our local
120 callbacks. Wire up our port names etc. */
122 static hw_port_event_method m68hc11cpu_port_event
;
126 dv_m6811_attach_address_callback (struct hw
*me
,
130 address_word nr_bytes
,
133 HW_TRACE ((me
, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
134 level
, space
, (unsigned long) addr
, (unsigned long) nr_bytes
,
139 sim_core_attach (hw_system (me
),
142 access_read_write_exec
,
151 /*printf("Attach from sub device: %d\n", (long) addr);*/
152 sim_core_attach (hw_system (me
),
165 dv_m6811_detach_address_callback (struct hw
*me
,
169 address_word nr_bytes
,
172 sim_core_detach (hw_system (me
), NULL
, /*cpu*/
177 m68hc11_delete (struct hw
* me
)
179 struct m68hc11cpu
*controller
;
181 controller
= hw_data (me
);
183 hw_detach_address (me
, M6811_IO_LEVEL
,
184 controller
->attach_space
,
185 controller
->attach_address
,
186 controller
->attach_size
, me
);
191 attach_m68hc11_regs (struct hw
*me
,
192 struct m68hc11cpu
*controller
)
196 reg_property_spec reg
;
197 const char *cpu_mode
;
199 if (hw_find_property (me
, "reg") == NULL
)
200 hw_abort (me
, "Missing \"reg\" property");
202 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
203 hw_abort (me
, "\"reg\" property must contain one addr/size entry");
205 hw_unit_address_to_attach_address (hw_parent (me
),
207 &controller
->attach_space
,
208 &controller
->attach_address
,
210 hw_unit_size_to_attach_size (hw_parent (me
),
212 &controller
->attach_size
, me
);
214 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
,
215 controller
->attach_space
,
216 controller
->attach_address
,
217 controller
->attach_size
,
219 set_hw_delete (me
, m68hc11_delete
);
221 /* Get cpu frequency. */
223 cpu
= STATE_CPU (sd
, 0);
224 if (hw_find_property (me
, "clock") != NULL
)
226 cpu
->cpu_frequency
= hw_find_integer_property (me
, "clock");
230 cpu
->cpu_frequency
= 8*1000*1000;
233 cpu_mode
= "expanded";
234 if (hw_find_property (me
, "mode") != NULL
)
235 cpu_mode
= hw_find_string_property (me
, "mode");
237 if (strcmp (cpu_mode
, "test") == 0)
238 cpu
->cpu_mode
= M6811_MDA
| M6811_SMOD
;
239 else if (strcmp (cpu_mode
, "bootstrap") == 0)
240 cpu
->cpu_mode
= M6811_SMOD
;
241 else if (strcmp (cpu_mode
, "single") == 0)
244 cpu
->cpu_mode
= M6811_MDA
;
248 m68hc11cpu_finish (struct hw
*me
)
250 struct m68hc11cpu
*controller
;
252 controller
= HW_ZALLOC (me
, struct m68hc11cpu
);
253 set_hw_data (me
, controller
);
254 set_hw_io_read_buffer (me
, m68hc11cpu_io_read_buffer
);
255 set_hw_io_write_buffer (me
, m68hc11cpu_io_write_buffer
);
256 set_hw_ports (me
, m68hc11cpu_ports
);
257 set_hw_port_event (me
, m68hc11cpu_port_event
);
258 set_hw_attach_address (me
, dv_m6811_attach_address_callback
);
259 set_hw_detach_address (me
, dv_m6811_detach_address_callback
);
261 set_hw_ioctl (me
, m68hc11_ioctl
);
263 me
->to_ioctl
= m68hc11_ioctl
;
266 /* Initialize the pending interrupt flags. */
267 controller
->pending_level
= 0;
268 controller
->pending_reset
= 0;
269 controller
->pending_nmi
= 0;
270 controller
->event
= NULL
;
272 attach_m68hc11_regs (me
, controller
);
275 /* An event arrives on an interrupt port. */
278 deliver_m68hc11cpu_interrupt (struct hw
*me
, void *data
)
284 m68hc11cpu_port_event (struct hw
*me
,
290 struct m68hc11cpu
*controller
= hw_data (me
);
295 cpu
= STATE_CPU (sd
, 0);
299 HW_TRACE ((me
, "port-in reset"));
301 /* The reset is made in 3 steps:
302 - First, cleanup the current sim_cpu struct.
304 - Restart the cpu for the reset (get the CPU mode from the
305 CONFIG register that gets initialized by EEPROM device). */
307 hw_port_event (me
, CPU_RESET_PORT
, 1);
312 controller
->pending_nmi
= 1;
313 HW_TRACE ((me
, "port-in nmi"));
317 /* level == 0 means that the interrupt was cleared. */
319 controller
->pending_level
= -1; /* signal end of interrupt */
321 controller
->pending_level
= level
;
322 HW_TRACE ((me
, "port-in level=%d", level
));
326 hw_abort (me
, "bad switch");
330 /* Schedule an event to be delivered immediately after current
332 if(controller
->event
!= NULL
)
333 hw_event_queue_deschedule(me
, controller
->event
);
335 hw_event_queue_schedule (me
, 0, deliver_m68hc11cpu_interrupt
, NULL
);
339 io_reg_desc config_desc
[] = {
340 { M6811_NOSEC
, "NOSEC ", "Security Mode Disable" },
341 { M6811_NOCOP
, "NOCOP ", "COP System Disable" },
342 { M6811_ROMON
, "ROMON ", "Enable On-chip Rom" },
343 { M6811_EEON
, "EEON ", "Enable On-chip EEprom" },
347 io_reg_desc hprio_desc
[] = {
348 { M6811_RBOOT
, "RBOOT ", "Read Bootstrap ROM" },
349 { M6811_SMOD
, "SMOD ", "Special Mode" },
350 { M6811_MDA
, "MDA ", "Mode Select A" },
351 { M6811_IRV
, "IRV ", "Internal Read Visibility" },
355 io_reg_desc option_desc
[] = {
356 { M6811_ADPU
, "ADPU ", "A/D Powerup" },
357 { M6811_CSEL
, "CSEL ", "A/D/EE Charge pump clock source select" },
358 { M6811_IRQE
, "IRQE ", "IRQ Edge/Level sensitive" },
359 { M6811_DLY
, "DLY ", "Stop exit turn on delay" },
360 { M6811_CME
, "CME ", "Clock Monitor Enable" },
361 { M6811_CR1
, "CR1 ", "COP timer rate select (CR1)" },
362 { M6811_CR0
, "CR0 ", "COP timer rate select (CR0)" },
367 m68hc11_info (struct hw
*me
)
372 struct m68hc11sio
*controller
;
376 cpu
= STATE_CPU (sd
, 0);
377 controller
= hw_data (me
);
379 base
= cpu_get_io_base (cpu
);
380 sim_io_printf (sd
, "M68HC11:\n");
382 val
= cpu
->ios
[M6811_HPRIO
];
383 print_io_byte (sd
, "HPRIO ", hprio_desc
, val
, base
+ M6811_HPRIO
);
384 sim_io_printf (sd
, "\n");
386 val
= cpu
->ios
[M6811_CONFIG
];
387 print_io_byte (sd
, "CONFIG", config_desc
, val
, base
+ M6811_CONFIG
);
388 sim_io_printf (sd
, "\n");
390 val
= cpu
->ios
[M6811_OPTION
];
391 print_io_byte (sd
, "OPTION", option_desc
, val
, base
+ M6811_OPTION
);
392 sim_io_printf (sd
, "\n");
394 val
= cpu
->ios
[M6811_INIT
];
395 print_io_byte (sd
, "INIT ", 0, val
, base
+ M6811_INIT
);
396 sim_io_printf (sd
, "Ram = 0x%04x IO = 0x%04x\n",
397 (((uint16
) (val
& 0xF0)) << 8),
398 (((uint16
) (val
& 0x0F)) << 12));
402 interrupts_info (sd
, &cpu
->cpu_interrupts
);
406 m68hc11_ioctl (struct hw
*me
,
407 hw_ioctl_request request
,
414 /* generic read/write */
417 m68hc11cpu_io_read_buffer (struct hw
*me
,
424 struct m68hc11cpu
*controller
= hw_data (me
);
429 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
432 cpu
= STATE_CPU (sd
, 0);
434 /* Handle reads for the sub-devices. */
435 base
-= controller
->attach_address
;
436 result
= sim_core_read_buffer (sd
, cpu
,
437 io_map
, dest
, base
, nr_bytes
);
443 if (base
>= controller
->attach_size
)
446 memcpy (dest
, &cpu
->ios
[base
], 1);
457 m68hc11cpu_io_write (struct hw
*me
, sim_cpu
*cpu
,
458 unsigned_word addr
, uint8 val
)
490 /* Change the RAM and I/O mapping. */
493 uint8 old_bank
= cpu
->ios
[M6811_INIT
];
495 cpu
->ios
[M6811_INIT
] = val
;
497 /* Update IO mapping. Detach from the old address
498 and attach to the new one. */
499 if ((old_bank
& 0xF0) != (val
& 0xF0))
501 struct m68hc11cpu
*controller
= hw_data (me
);
503 hw_detach_address (hw_parent (me
), M6811_IO_LEVEL
,
504 controller
->attach_space
,
505 controller
->attach_address
,
506 controller
->attach_size
,
508 controller
->attach_address
= (val
& 0x0F0) << 12;
509 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
,
510 controller
->attach_space
,
511 controller
->attach_address
,
512 controller
->attach_size
,
515 if ((old_bank
& 0x0F) != (val
& 0x0F))
522 /* Writing the config is similar to programing the eeprom.
523 The config register value is the last byte of the EEPROM.
524 This last byte is not mapped in memory (that's why we have
525 to add '1' to 'end_addr'). */
534 if (val
== 0xAA && cpu
->ios
[addr
] == 0x55)
537 /* COP reset here. */
545 cpu
->ios
[addr
] = val
;
549 m68hc11cpu_io_write_buffer (struct hw
*me
,
556 struct m68hc11cpu
*controller
= hw_data (me
);
561 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
564 cpu
= STATE_CPU (sd
, 0);
565 base
-= controller
->attach_address
;
566 result
= sim_core_write_buffer (sd
, cpu
,
567 io_map
, source
, base
, nr_bytes
);
575 if (base
>= controller
->attach_size
)
578 val
= *((uint8
*) source
);
579 m68hc11cpu_io_write (me
, cpu
, base
, val
);
588 const struct hw_descriptor dv_m68hc11_descriptor
[] = {
589 { "m68hc11", m68hc11cpu_finish
},
590 { "m68hc12", m68hc11cpu_finish
},