1 /* dv-m68hc11.c -- CPU 68HC11 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
33 Implements the external m68hc11 functionality. This includes the
34 delivery of of interrupts generated from other devices and the
35 handling of device specific registers.
42 Register base (should be 0x1000 0x03f).
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
);
277 /* An event arrives on an interrupt port. */
280 deliver_m68hc11cpu_interrupt (struct hw
*me
, void *data
)
286 m68hc11cpu_port_event (struct hw
*me
,
292 struct m68hc11cpu
*controller
= hw_data (me
);
297 cpu
= STATE_CPU (sd
, 0);
301 HW_TRACE ((me
, "port-in reset"));
303 /* The reset is made in 3 steps:
304 - First, cleanup the current sim_cpu struct.
306 - Restart the cpu for the reset (get the CPU mode from the
307 CONFIG register that gets initialized by EEPROM device). */
309 hw_port_event (me
, CPU_RESET_PORT
, 1);
314 controller
->pending_nmi
= 1;
315 HW_TRACE ((me
, "port-in nmi"));
319 /* level == 0 means that the interrupt was cleared. */
321 controller
->pending_level
= -1; /* signal end of interrupt */
323 controller
->pending_level
= level
;
324 HW_TRACE ((me
, "port-in level=%d", level
));
328 hw_abort (me
, "bad switch");
332 /* Schedule an event to be delivered immediately after current
334 if(controller
->event
!= NULL
)
335 hw_event_queue_deschedule(me
, controller
->event
);
337 hw_event_queue_schedule (me
, 0, deliver_m68hc11cpu_interrupt
, NULL
);
341 io_reg_desc config_desc
[] = {
342 { M6811_NOSEC
, "NOSEC ", "Security Mode Disable" },
343 { M6811_NOCOP
, "NOCOP ", "COP System Disable" },
344 { M6811_ROMON
, "ROMON ", "Enable On-chip Rom" },
345 { M6811_EEON
, "EEON ", "Enable On-chip EEprom" },
349 io_reg_desc hprio_desc
[] = {
350 { M6811_RBOOT
, "RBOOT ", "Read Bootstrap ROM" },
351 { M6811_SMOD
, "SMOD ", "Special Mode" },
352 { M6811_MDA
, "MDA ", "Mode Select A" },
353 { M6811_IRV
, "IRV ", "Internal Read Visibility" },
357 io_reg_desc option_desc
[] = {
358 { M6811_ADPU
, "ADPU ", "A/D Powerup" },
359 { M6811_CSEL
, "CSEL ", "A/D/EE Charge pump clock source select" },
360 { M6811_IRQE
, "IRQE ", "IRQ Edge/Level sensitive" },
361 { M6811_DLY
, "DLY ", "Stop exit turn on delay" },
362 { M6811_CME
, "CME ", "Clock Monitor Enable" },
363 { M6811_CR1
, "CR1 ", "COP timer rate select (CR1)" },
364 { M6811_CR0
, "CR0 ", "COP timer rate select (CR0)" },
369 m68hc11_info (struct hw
*me
)
374 struct m68hc11sio
*controller
;
378 cpu
= STATE_CPU (sd
, 0);
379 controller
= hw_data (me
);
381 base
= cpu_get_io_base (cpu
);
382 sim_io_printf (sd
, "M68HC11:\n");
384 val
= cpu
->ios
[M6811_HPRIO
];
385 print_io_byte (sd
, "HPRIO ", hprio_desc
, val
, base
+ M6811_HPRIO
);
386 sim_io_printf (sd
, "\n");
388 val
= cpu
->ios
[M6811_CONFIG
];
389 print_io_byte (sd
, "CONFIG", config_desc
, val
, base
+ M6811_CONFIG
);
390 sim_io_printf (sd
, "\n");
392 val
= cpu
->ios
[M6811_OPTION
];
393 print_io_byte (sd
, "OPTION", option_desc
, val
, base
+ M6811_OPTION
);
394 sim_io_printf (sd
, "\n");
396 val
= cpu
->ios
[M6811_INIT
];
397 print_io_byte (sd
, "INIT ", 0, val
, base
+ M6811_INIT
);
398 sim_io_printf (sd
, "Ram = 0x%04x IO = 0x%04x\n",
399 (((uint16
) (val
& 0xF0)) << 8),
400 (((uint16
) (val
& 0x0F)) << 12));
404 interrupts_info (sd
, &cpu
->cpu_interrupts
);
408 m68hc11_ioctl (struct hw
*me
,
409 hw_ioctl_request request
,
416 /* generic read/write */
419 m68hc11cpu_io_read_buffer (struct hw
*me
,
426 struct m68hc11cpu
*controller
= hw_data (me
);
431 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
434 cpu
= STATE_CPU (sd
, 0);
436 /* Handle reads for the sub-devices. */
437 base
-= controller
->attach_address
;
438 result
= sim_core_read_buffer (sd
, cpu
,
439 io_map
, dest
, base
, nr_bytes
);
448 memcpy (dest
, &cpu
->ios
[base
], 1);
459 m68hc11cpu_io_write (struct hw
*me
, sim_cpu
*cpu
,
460 unsigned_word addr
, uint8 val
)
492 /* Change the RAM and I/O mapping. */
495 uint8 old_bank
= cpu
->ios
[M6811_INIT
];
497 cpu
->ios
[M6811_INIT
] = val
;
499 /* Update IO mapping. Detach from the old address
500 and attach to the new one. */
501 if ((old_bank
& 0xF0) != (val
& 0xF0))
503 struct m68hc11cpu
*controller
= hw_data (me
);
505 hw_detach_address (hw_parent (me
), M6811_IO_LEVEL
,
506 controller
->attach_space
,
507 controller
->attach_address
,
508 controller
->attach_size
,
510 controller
->attach_address
= (val
& 0x0F0) << 12;
511 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
,
512 controller
->attach_space
,
513 controller
->attach_address
,
514 controller
->attach_size
,
517 if ((old_bank
& 0x0F) != (val
& 0x0F))
524 /* Writing the config is similar to programing the eeprom.
525 The config register value is the last byte of the EEPROM.
526 This last byte is not mapped in memory (that's why we have
527 to add '1' to 'end_addr'). */
536 if (val
== 0xAA && cpu
->ios
[addr
] == 0x55)
539 /* COP reset here. */
547 cpu
->ios
[addr
] = val
;
551 m68hc11cpu_io_write_buffer (struct hw
*me
,
558 struct m68hc11cpu
*controller
= hw_data (me
);
563 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
566 cpu
= STATE_CPU (sd
, 0);
567 base
-= controller
->attach_address
;
568 result
= sim_core_write_buffer (sd
, cpu
,
569 io_map
, source
, base
, nr_bytes
);
580 val
= *((uint8
*) source
);
581 m68hc11cpu_io_write (me
, cpu
, base
, val
);
590 const struct hw_descriptor dv_m68hc11_descriptor
[] = {
591 { "m68hc11", m68hc11cpu_finish
, },