]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11.c
Use address mapping levels for 68hc11 simulator (kill overlap hack)
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11.c
CommitLineData
e0709f50
AC
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.)
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 2 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, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22
23#include "sim-main.h"
24#include "hw-main.h"
25
26/* DEVICE
27
28 m68hc11cpu - m68hc11 cpu virtual device
29
30
31 DESCRIPTION
32
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.
36
37
38 PROPERTIES
39
40 reg <base> <size>
41
42 Register base (should be 0x1000 0x03f).
43
44 clock <hz>
45
46 Frequency of the quartz used by the processor.
47
48 mode [single | expanded | bootstrap | test]
49
50 Cpu operating mode (the MODA and MODB external pins).
51
52
53 PORTS
54
55 reset (input)
56
57 Reset the cpu and generates a cpu-reset event (used to reset
58 other devices).
59
60 nmi (input)
61
62 Deliver a non-maskable interrupt to the processor.
63
64
65 cpu-reset (output)
66
67 Event generated after the CPU performs a reset.
68
69
70 BUGS
71
72 When delivering an interrupt, this code assumes that there is only
73 one processor (number 0).
74
75 */
76
77
78
79struct m68hc11cpu {
80 /* Pending interrupts for delivery by event handler. */
81 int pending_reset;
82 int pending_nmi;
83 int pending_level;
84 struct hw_event *event;
85 unsigned_word attach_address;
86 int attach_size;
87 int attach_space;
88};
89
90
91
92/* input port ID's */
93
94enum {
95 RESET_PORT,
96 NMI_PORT,
97 IRQ_PORT,
98 CPU_RESET_PORT
99};
100
101
102static const struct hw_port_descriptor m68hc11cpu_ports[] = {
103
104 /* Interrupt inputs. */
105 { "reset", RESET_PORT, 0, input_port, },
106 { "nmi", NMI_PORT, 0, input_port, },
107 { "irq", IRQ_PORT, 0, input_port, },
108
109 /* Events generated for connection to other devices. */
110 { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
111
112 { NULL, },
113};
114
115static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
116static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
117static hw_ioctl_method m68hc11_ioctl;
118
119/* Finish off the partially created hw device. Attach our local
120 callbacks. Wire up our port names etc. */
121
122static hw_port_event_method m68hc11cpu_port_event;
123
124
125static void
126dv_m6811_attach_address_callback (struct hw *me,
127 int level,
128 int space,
129 address_word addr,
130 address_word nr_bytes,
131 struct hw *client)
132{
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,
135 hw_path (client)));
136
137 if (space != io_map)
138 {
139 sim_core_attach (hw_system (me),
140 NULL, /*cpu*/
141 level,
142 access_read_write_exec,
143 space, addr,
144 nr_bytes,
145 0, /* modulo */
146 client,
147 NULL);
148 }
149 else
150 {
151 /*printf("Attach from sub device: %d\n", (long) addr);*/
152 sim_core_attach (hw_system (me),
153 NULL, /*cpu*/
154 level,
155 access_io,
156 space, addr,
157 nr_bytes,
158 0, /* modulo */
159 client,
160 NULL);
161 }
162}
163
164static void
165dv_m6811_detach_address_callback (struct hw *me,
166 int level,
167 int space,
168 address_word addr,
169 address_word nr_bytes,
170 struct hw *client)
171{
172 sim_core_detach (hw_system (me), NULL, /*cpu*/
173 level, space, addr);
174}
175
176
177static void
178attach_m68hc11_regs (struct hw *me,
179 struct m68hc11cpu *controller)
180{
181 SIM_DESC sd;
182 sim_cpu *cpu;
183 reg_property_spec reg;
184 const char *cpu_mode;
185
186 if (hw_find_property (me, "reg") == NULL)
187 hw_abort (me, "Missing \"reg\" property");
188
189 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
190 hw_abort (me, "\"reg\" property must contain one addr/size entry");
191
192 hw_unit_address_to_attach_address (hw_parent (me),
193 &reg.address,
194 &controller->attach_space,
195 &controller->attach_address,
196 me);
197 hw_unit_size_to_attach_size (hw_parent (me),
198 &reg.size,
199 &controller->attach_size, me);
200
63348d04 201 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
202 controller->attach_space,
203 controller->attach_address,
204 controller->attach_size,
205 me);
206
207
208 /* Get cpu frequency. */
209 sd = hw_system (me);
210 cpu = STATE_CPU (sd, 0);
211 if (hw_find_property (me, "clock") != NULL)
212 {
213 cpu->cpu_frequency = hw_find_integer_property (me, "clock");
214 }
215 else
216 {
217 cpu->cpu_frequency = 8*1000*1000;
218 }
219
220 cpu_mode = "expanded";
221 if (hw_find_property (me, "mode") != NULL)
222 cpu_mode = hw_find_string_property (me, "mode");
223
224 if (strcmp (cpu_mode, "test") == 0)
225 cpu->cpu_mode = M6811_MDA | M6811_SMOD;
226 else if (strcmp (cpu_mode, "bootstrap") == 0)
227 cpu->cpu_mode = M6811_SMOD;
228 else if (strcmp (cpu_mode, "single") == 0)
229 cpu->cpu_mode = 0;
230 else
231 cpu->cpu_mode = M6811_MDA;
232}
233
234static void
235m68hc11cpu_finish (struct hw *me)
236{
237 struct m68hc11cpu *controller;
238
239 controller = HW_ZALLOC (me, struct m68hc11cpu);
e0709f50
AC
240 set_hw_data (me, controller);
241 set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
242 set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
243 set_hw_ports (me, m68hc11cpu_ports);
244 set_hw_port_event (me, m68hc11cpu_port_event);
245 set_hw_attach_address (me, dv_m6811_attach_address_callback);
246 set_hw_detach_address (me, dv_m6811_detach_address_callback);
247#ifdef set_hw_ioctl
248 set_hw_ioctl (me, m68hc11_ioctl);
249#else
250 me->to_ioctl = m68hc11_ioctl;
251#endif
252
253 /* Initialize the pending interrupt flags. */
254 controller->pending_level = 0;
255 controller->pending_reset = 0;
256 controller->pending_nmi = 0;
257 controller->event = NULL;
258
259 attach_m68hc11_regs (me, controller);
260}
261
262
263
264/* An event arrives on an interrupt port. */
265
266static void
267deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
268{
269}
270
271
272static void
273m68hc11cpu_port_event (struct hw *me,
274 int my_port,
275 struct hw *source,
276 int source_port,
277 int level)
278{
279 struct m68hc11cpu *controller = hw_data (me);
280 SIM_DESC sd;
281 sim_cpu* cpu;
282
283 sd = hw_system (me);
284 cpu = STATE_CPU (sd, 0);
285 switch (my_port)
286 {
287 case RESET_PORT:
288 HW_TRACE ((me, "port-in reset"));
289
290 /* The reset is made in 3 steps:
291 - First, cleanup the current sim_cpu struct.
292 - Reset the devices.
293 - Restart the cpu for the reset (get the CPU mode from the
294 CONFIG register that gets initialized by EEPROM device). */
295 cpu_reset (cpu);
296 hw_port_event (me, CPU_RESET_PORT, 1);
297 cpu_restart (cpu);
298 break;
299
300 case NMI_PORT:
301 controller->pending_nmi = 1;
302 HW_TRACE ((me, "port-in nmi"));
303 break;
304
305 case IRQ_PORT:
306 /* level == 0 means that the interrupt was cleared. */
307 if(level == 0)
308 controller->pending_level = -1; /* signal end of interrupt */
309 else
310 controller->pending_level = level;
311 HW_TRACE ((me, "port-in level=%d", level));
312 break;
313
314 default:
315 hw_abort (me, "bad switch");
316 break;
317 }
318
319 /* Schedule an event to be delivered immediately after current
320 instruction. */
321 if(controller->event != NULL)
322 hw_event_queue_deschedule(me, controller->event);
323 controller->event =
324 hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
325}
326
327
328io_reg_desc config_desc[] = {
329 { M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
330 { M6811_NOCOP, "NOCOP ", "COP System Disable" },
331 { M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
332 { M6811_EEON, "EEON ", "Enable On-chip EEprom" },
333 { 0, 0, 0 }
334};
335
336io_reg_desc hprio_desc[] = {
337 { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
338 { M6811_SMOD, "SMOD ", "Special Mode" },
339 { M6811_MDA, "MDA ", "Mode Select A" },
340 { M6811_IRV, "IRV ", "Internal Read Visibility" },
341 { 0, 0, 0 }
342};
343
344io_reg_desc option_desc[] = {
345 { M6811_ADPU, "ADPU ", "A/D Powerup" },
346 { M6811_CSEL, "CSEL ", "A/D/EE Charge pump clock source select" },
347 { M6811_IRQE, "IRQE ", "IRQ Edge/Level sensitive" },
348 { M6811_DLY, "DLY ", "Stop exit turn on delay" },
349 { M6811_CME, "CME ", "Clock Monitor Enable" },
350 { M6811_CR1, "CR1 ", "COP timer rate select (CR1)" },
351 { M6811_CR0, "CR0 ", "COP timer rate select (CR0)" },
352 { 0, 0, 0 }
353};
354
355static void
356m68hc11_info (struct hw *me)
357{
358 SIM_DESC sd;
359 uint16 base = 0;
360 sim_cpu *cpu;
361 struct m68hc11sio *controller;
362 uint8 val;
363
364 sd = hw_system (me);
365 cpu = STATE_CPU (sd, 0);
366 controller = hw_data (me);
367
368 base = cpu_get_io_base (cpu);
369 sim_io_printf (sd, "M68HC11:\n");
370
371 val = cpu->ios[M6811_HPRIO];
372 print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
373 sim_io_printf (sd, "\n");
374
375 val = cpu->ios[M6811_CONFIG];
376 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
377 sim_io_printf (sd, "\n");
378
379 val = cpu->ios[M6811_OPTION];
380 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
381 sim_io_printf (sd, "\n");
382
383 val = cpu->ios[M6811_INIT];
384 print_io_byte (sd, "INIT ", 0, val, base + M6811_INIT);
385 sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
386 (((uint16) (val & 0xF0)) << 8),
387 (((uint16) (val & 0x0F)) << 12));
388
389
390 cpu_info (sd, cpu);
391 interrupts_info (sd, &cpu->cpu_interrupts);
392}
393
394static int
395m68hc11_ioctl (struct hw *me,
396 hw_ioctl_request request,
397 va_list ap)
398{
399 m68hc11_info (me);
400 return 0;
401}
402
403/* generic read/write */
404
405static unsigned
406m68hc11cpu_io_read_buffer (struct hw *me,
407 void *dest,
408 int space,
409 unsigned_word base,
410 unsigned nr_bytes)
411{
412 SIM_DESC sd;
413 struct m68hc11cpu *controller = hw_data (me);
414 sim_cpu *cpu;
415 unsigned byte = 0;
416 int result;
417
418 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
419
420 sd = hw_system (me);
421 cpu = STATE_CPU (sd, 0);
422
423 /* Handle reads for the sub-devices. */
424 base -= controller->attach_address;
425 result = sim_core_read_buffer (sd, cpu,
426 io_map, dest, base, nr_bytes);
427 if (result > 0)
428 return result;
429
430 while (nr_bytes)
431 {
432 if (base >= 0x3F)
433 break;
434
435 memcpy (dest, &cpu->ios[base], 1);
436 dest++;
437 base++;
438 byte++;
439 nr_bytes--;
440 }
441 return byte;
442}
443
444
445static void
446m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
447 unsigned_word addr, uint8 val)
448{
449 switch (addr)
450 {
451 case M6811_PORTA:
452 break;
453
454 case M6811_PIOC:
455 break;
456
457 case M6811_PORTC:
458 break;
459
460 case M6811_PORTB:
461 break;
462
463 case M6811_PORTCL:
464 break;
465
466 case M6811_DDRC:
467 break;
468
469 case M6811_PORTD:
470 break;
471
472 case M6811_DDRD:
473 break;
474
475 case M6811_TMSK2:
476
477 break;
478
479 /* Change the RAM and I/O mapping. */
480 case M6811_INIT:
481 {
482 uint8 old_bank = cpu->ios[M6811_INIT];
483
484 cpu->ios[M6811_INIT] = val;
485
486 /* Update IO mapping. Detach from the old address
487 and attach to the new one. */
488 if ((old_bank & 0xF0) != (val & 0xF0))
489 {
490 struct m68hc11cpu *controller = hw_data (me);
491
63348d04 492 hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
493 controller->attach_space,
494 controller->attach_address,
495 controller->attach_size,
496 me);
497 controller->attach_address = (val & 0x0F0) << 12;
63348d04 498 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
499 controller->attach_space,
500 controller->attach_address,
501 controller->attach_size,
502 me);
503 }
504 if ((old_bank & 0x0F) != (val & 0x0F))
505 {
506 ;
507 }
508 return;
509 }
510
511 /* Writing the config is similar to programing the eeprom.
512 The config register value is the last byte of the EEPROM.
513 This last byte is not mapped in memory (that's why we have
514 to add '1' to 'end_addr'). */
515 case M6811_CONFIG:
516 {
517 return;
518 }
519
520
521 /* COP reset. */
522 case M6811_COPRST:
523 if (val == 0xAA && cpu->ios[addr] == 0x55)
524 {
525 val = 0;
526 /* COP reset here. */
527 }
528 break;
529
530 default:
531 break;
532
533 }
534 cpu->ios[addr] = val;
535}
536
537static unsigned
538m68hc11cpu_io_write_buffer (struct hw *me,
539 const void *source,
540 int space,
541 unsigned_word base,
542 unsigned nr_bytes)
543{
544 SIM_DESC sd;
545 struct m68hc11cpu *controller = hw_data (me);
546 unsigned byte;
547 sim_cpu *cpu;
548 int result;
549
550 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
551
552 sd = hw_system (me);
553 cpu = STATE_CPU (sd, 0);
554 base -= controller->attach_address;
555 result = sim_core_write_buffer (sd, cpu,
556 io_map, source, base, nr_bytes);
557 if (result > 0)
558 return result;
559
560 byte = 0;
561 while (nr_bytes)
562 {
563 uint8 val;
564 if (base >= 0x3F)
565 break;
566
567 val = *((uint8*) source);
568 m68hc11cpu_io_write (me, cpu, base, val);
569 source++;
570 base++;
571 byte++;
572 nr_bytes--;
573 }
574 return byte;
575}
576
577const struct hw_descriptor dv_m68hc11_descriptor[] = {
578 { "m68hc11", m68hc11cpu_finish, },
579 { NULL },
580};
581