Fix autoconf breakage + commit target.c, omitted in previous delta
[deliverable/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11.c
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.)
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 m68hc12cpu - m68hc12 cpu virtual device
30
31 DESCRIPTION
32
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.
36
37
38 PROPERTIES
39
40 reg <base> <size>
41
42 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
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
79 struct 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
94 enum {
95 RESET_PORT,
96 NMI_PORT,
97 IRQ_PORT,
98 CPU_RESET_PORT
99 };
100
101
102 static 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
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;
118
119 /* Finish off the partially created hw device. Attach our local
120 callbacks. Wire up our port names etc. */
121
122 static hw_port_event_method m68hc11cpu_port_event;
123
124
125 static void
126 dv_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
164 static void
165 dv_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 static void
177 m68hc11_delete (struct hw* me)
178 {
179 struct m68hc11cpu *controller;
180
181 controller = hw_data (me);
182
183 hw_detach_address (me, M6811_IO_LEVEL,
184 controller->attach_space,
185 controller->attach_address,
186 controller->attach_size, me);
187 }
188
189
190 static void
191 attach_m68hc11_regs (struct hw *me,
192 struct m68hc11cpu *controller)
193 {
194 SIM_DESC sd;
195 sim_cpu *cpu;
196 reg_property_spec reg;
197 const char *cpu_mode;
198
199 if (hw_find_property (me, "reg") == NULL)
200 hw_abort (me, "Missing \"reg\" property");
201
202 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
203 hw_abort (me, "\"reg\" property must contain one addr/size entry");
204
205 hw_unit_address_to_attach_address (hw_parent (me),
206 &reg.address,
207 &controller->attach_space,
208 &controller->attach_address,
209 me);
210 hw_unit_size_to_attach_size (hw_parent (me),
211 &reg.size,
212 &controller->attach_size, me);
213
214 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
215 controller->attach_space,
216 controller->attach_address,
217 controller->attach_size,
218 me);
219 set_hw_delete (me, m68hc11_delete);
220
221 /* Get cpu frequency. */
222 sd = hw_system (me);
223 cpu = STATE_CPU (sd, 0);
224 if (hw_find_property (me, "clock") != NULL)
225 {
226 cpu->cpu_frequency = hw_find_integer_property (me, "clock");
227 }
228 else
229 {
230 cpu->cpu_frequency = 8*1000*1000;
231 }
232
233 cpu_mode = "expanded";
234 if (hw_find_property (me, "mode") != NULL)
235 cpu_mode = hw_find_string_property (me, "mode");
236
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)
242 cpu->cpu_mode = 0;
243 else
244 cpu->cpu_mode = M6811_MDA;
245 }
246
247 static void
248 m68hc11cpu_finish (struct hw *me)
249 {
250 struct m68hc11cpu *controller;
251
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);
260 #ifdef set_hw_ioctl
261 set_hw_ioctl (me, m68hc11_ioctl);
262 #else
263 me->to_ioctl = m68hc11_ioctl;
264 #endif
265
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;
271
272 attach_m68hc11_regs (me, controller);
273 }
274
275 /* An event arrives on an interrupt port. */
276
277 static void
278 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
279 {
280 }
281
282
283 static void
284 m68hc11cpu_port_event (struct hw *me,
285 int my_port,
286 struct hw *source,
287 int source_port,
288 int level)
289 {
290 struct m68hc11cpu *controller = hw_data (me);
291 SIM_DESC sd;
292 sim_cpu* cpu;
293
294 sd = hw_system (me);
295 cpu = STATE_CPU (sd, 0);
296 switch (my_port)
297 {
298 case RESET_PORT:
299 HW_TRACE ((me, "port-in reset"));
300
301 /* The reset is made in 3 steps:
302 - First, cleanup the current sim_cpu struct.
303 - Reset the devices.
304 - Restart the cpu for the reset (get the CPU mode from the
305 CONFIG register that gets initialized by EEPROM device). */
306 cpu_reset (cpu);
307 hw_port_event (me, CPU_RESET_PORT, 1);
308 cpu_restart (cpu);
309 break;
310
311 case NMI_PORT:
312 controller->pending_nmi = 1;
313 HW_TRACE ((me, "port-in nmi"));
314 break;
315
316 case IRQ_PORT:
317 /* level == 0 means that the interrupt was cleared. */
318 if(level == 0)
319 controller->pending_level = -1; /* signal end of interrupt */
320 else
321 controller->pending_level = level;
322 HW_TRACE ((me, "port-in level=%d", level));
323 break;
324
325 default:
326 hw_abort (me, "bad switch");
327 break;
328 }
329
330 /* Schedule an event to be delivered immediately after current
331 instruction. */
332 if(controller->event != NULL)
333 hw_event_queue_deschedule(me, controller->event);
334 controller->event =
335 hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
336 }
337
338
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" },
344 { 0, 0, 0 }
345 };
346
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" },
352 { 0, 0, 0 }
353 };
354
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)" },
363 { 0, 0, 0 }
364 };
365
366 static void
367 m68hc11_info (struct hw *me)
368 {
369 SIM_DESC sd;
370 uint16 base = 0;
371 sim_cpu *cpu;
372 struct m68hc11sio *controller;
373 uint8 val;
374
375 sd = hw_system (me);
376 cpu = STATE_CPU (sd, 0);
377 controller = hw_data (me);
378
379 base = cpu_get_io_base (cpu);
380 sim_io_printf (sd, "M68HC11:\n");
381
382 val = cpu->ios[M6811_HPRIO];
383 print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
384 sim_io_printf (sd, "\n");
385
386 val = cpu->ios[M6811_CONFIG];
387 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
388 sim_io_printf (sd, "\n");
389
390 val = cpu->ios[M6811_OPTION];
391 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
392 sim_io_printf (sd, "\n");
393
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));
399
400
401 cpu_info (sd, cpu);
402 interrupts_info (sd, &cpu->cpu_interrupts);
403 }
404
405 static int
406 m68hc11_ioctl (struct hw *me,
407 hw_ioctl_request request,
408 va_list ap)
409 {
410 m68hc11_info (me);
411 return 0;
412 }
413
414 /* generic read/write */
415
416 static unsigned
417 m68hc11cpu_io_read_buffer (struct hw *me,
418 void *dest,
419 int space,
420 unsigned_word base,
421 unsigned nr_bytes)
422 {
423 SIM_DESC sd;
424 struct m68hc11cpu *controller = hw_data (me);
425 sim_cpu *cpu;
426 unsigned byte = 0;
427 int result;
428
429 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
430
431 sd = hw_system (me);
432 cpu = STATE_CPU (sd, 0);
433
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);
438 if (result > 0)
439 return result;
440
441 while (nr_bytes)
442 {
443 if (base >= controller->attach_size)
444 break;
445
446 memcpy (dest, &cpu->ios[base], 1);
447 dest++;
448 base++;
449 byte++;
450 nr_bytes--;
451 }
452 return byte;
453 }
454
455
456 static void
457 m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
458 unsigned_word addr, uint8 val)
459 {
460 switch (addr)
461 {
462 case M6811_PORTA:
463 break;
464
465 case M6811_PIOC:
466 break;
467
468 case M6811_PORTC:
469 break;
470
471 case M6811_PORTB:
472 break;
473
474 case M6811_PORTCL:
475 break;
476
477 case M6811_DDRC:
478 break;
479
480 case M6811_PORTD:
481 break;
482
483 case M6811_DDRD:
484 break;
485
486 case M6811_TMSK2:
487
488 break;
489
490 /* Change the RAM and I/O mapping. */
491 case M6811_INIT:
492 {
493 uint8 old_bank = cpu->ios[M6811_INIT];
494
495 cpu->ios[M6811_INIT] = val;
496
497 /* Update IO mapping. Detach from the old address
498 and attach to the new one. */
499 if ((old_bank & 0xF0) != (val & 0xF0))
500 {
501 struct m68hc11cpu *controller = hw_data (me);
502
503 hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
504 controller->attach_space,
505 controller->attach_address,
506 controller->attach_size,
507 me);
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,
513 me);
514 }
515 if ((old_bank & 0x0F) != (val & 0x0F))
516 {
517 ;
518 }
519 return;
520 }
521
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'). */
526 case M6811_CONFIG:
527 {
528 return;
529 }
530
531
532 /* COP reset. */
533 case M6811_COPRST:
534 if (val == 0xAA && cpu->ios[addr] == 0x55)
535 {
536 val = 0;
537 /* COP reset here. */
538 }
539 break;
540
541 default:
542 break;
543
544 }
545 cpu->ios[addr] = val;
546 }
547
548 static unsigned
549 m68hc11cpu_io_write_buffer (struct hw *me,
550 const void *source,
551 int space,
552 unsigned_word base,
553 unsigned nr_bytes)
554 {
555 SIM_DESC sd;
556 struct m68hc11cpu *controller = hw_data (me);
557 unsigned byte;
558 sim_cpu *cpu;
559 int result;
560
561 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
562
563 sd = hw_system (me);
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);
568 if (result > 0)
569 return result;
570
571 byte = 0;
572 while (nr_bytes)
573 {
574 uint8 val;
575 if (base >= controller->attach_size)
576 break;
577
578 val = *((uint8*) source);
579 m68hc11cpu_io_write (me, cpu, base, val);
580 source++;
581 base++;
582 byte++;
583 nr_bytes--;
584 }
585 return byte;
586 }
587
588 const struct hw_descriptor dv_m68hc11_descriptor[] = {
589 { "m68hc11", m68hc11cpu_finish },
590 { "m68hc12", m68hc11cpu_finish },
591 { NULL },
592 };
593
This page took 0.047875 seconds and 4 git commands to generate.