]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/m68hc11/dv-m68hc11.c
* sim-main.h (phys_to_virt): Use memory bank parameters to translate
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11.c
1 /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@nerim.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 "sim-hw.h"
25 #include "hw-main.h"
26 #include "sim-options.h"
27 #include "hw-base.h"
28 #include <limits.h>
29
30 /* DEVICE
31
32 m68hc11cpu - m68hc11 cpu virtual device
33 m68hc12cpu - m68hc12 cpu virtual device
34
35 DESCRIPTION
36
37 Implements the external m68hc11/68hc12 functionality. This includes
38 the delivery of of interrupts generated from other devices and the
39 handling of device specific registers.
40
41
42 PROPERTIES
43
44 reg <base> <size>
45
46 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
47
48 clock <hz>
49
50 Frequency of the quartz used by the processor.
51
52 mode [single | expanded | bootstrap | test]
53
54 Cpu operating mode (the MODA and MODB external pins).
55
56
57 PORTS
58
59 reset (input)
60
61 Reset the cpu and generates a cpu-reset event (used to reset
62 other devices).
63
64 nmi (input)
65
66 Deliver a non-maskable interrupt to the processor.
67
68
69 set-port-a (input)
70 set-port-c (input)
71 set-pord-d (input)
72
73 Allow an external device to set the value of port A, C or D inputs.
74
75
76 cpu-reset (output)
77
78 Event generated after the CPU performs a reset.
79
80
81 port-a (output)
82 port-b (output)
83 port-c (output)
84 port-d (output)
85
86 Event generated when the value of the output port A, B, C or D
87 changes.
88
89
90 BUGS
91
92 When delivering an interrupt, this code assumes that there is only
93 one processor (number 0).
94
95 */
96
97 enum
98 {
99 OPTION_OSC_SET = OPTION_START,
100 OPTION_OSC_CLEAR,
101 OPTION_OSC_INFO
102 };
103
104 static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
105
106 static const OPTION m68hc11_options[] =
107 {
108 { {"osc-set", required_argument, NULL, OPTION_OSC_SET },
109 '\0', "BIT,FREQ", "Set the oscillator on input port BIT",
110 m68hc11_option_handler },
111 { {"osc-clear", required_argument, NULL, OPTION_OSC_CLEAR },
112 '\0', "BIT", "Clear oscillator on input port BIT",
113 m68hc11_option_handler },
114 { {"osc-info", no_argument, NULL, OPTION_OSC_INFO },
115 '\0', NULL, "Print information about current input oscillators",
116 m68hc11_option_handler },
117
118 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
119 };
120
121 struct input_osc
122 {
123 signed64 on_time;
124 signed64 off_time;
125 signed64 repeat;
126 struct hw_event *event;
127 const char *name;
128 uint8 mask;
129 uint8 value;
130 uint16 addr;
131 };
132
133 #define NR_PORT_A_OSC (4)
134 #define NR_PORT_B_OSC (0)
135 #define NR_PORT_C_OSC (8)
136 #define NR_PORT_D_OSC (6)
137 #define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC)
138 struct m68hc11cpu {
139 /* Pending interrupts for delivery by event handler. */
140 int pending_reset;
141 int pending_nmi;
142 int pending_level;
143 struct hw_event *event;
144 unsigned_word attach_address;
145 int attach_size;
146 int attach_space;
147 int last_oscillator;
148 struct input_osc oscillators[NR_OSC];
149 };
150
151
152
153 /* input port ID's */
154
155 enum {
156 RESET_PORT,
157 NMI_PORT,
158 IRQ_PORT,
159 CPU_RESET_PORT,
160 SET_PORT_A,
161 SET_PORT_C,
162 SET_PORT_D,
163 CPU_WRITE_PORT,
164 PORT_A,
165 PORT_B,
166 PORT_C,
167 PORT_D,
168 CAPTURE
169 };
170
171
172 static const struct hw_port_descriptor m68hc11cpu_ports[] = {
173
174 /* Interrupt inputs. */
175 { "reset", RESET_PORT, 0, input_port, },
176 { "nmi", NMI_PORT, 0, input_port, },
177 { "irq", IRQ_PORT, 0, input_port, },
178
179 { "set-port-a", SET_PORT_A, 0, input_port, },
180 { "set-port-c", SET_PORT_C, 0, input_port, },
181 { "set-port-d", SET_PORT_D, 0, input_port, },
182
183 { "cpu-write-port", CPU_WRITE_PORT, 0, input_port, },
184
185 /* Events generated for connection to other devices. */
186 { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
187
188 /* Events generated when the corresponding port is
189 changed by the program. */
190 { "port-a", PORT_A, 0, output_port, },
191 { "port-b", PORT_B, 0, output_port, },
192 { "port-c", PORT_C, 0, output_port, },
193 { "port-d", PORT_D, 0, output_port, },
194
195 { "capture", CAPTURE, 0, output_port, },
196
197 { NULL, },
198 };
199
200 static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
201 static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
202 static hw_ioctl_method m68hc11_ioctl;
203
204 /* Finish off the partially created hw device. Attach our local
205 callbacks. Wire up our port names etc. */
206
207 static hw_port_event_method m68hc11cpu_port_event;
208
209 static void make_oscillator (struct m68hc11cpu *controller,
210 const char *id, uint16 addr, uint8 mask);
211 static struct input_osc *find_oscillator (struct m68hc11cpu *controller,
212 const char *id);
213 static void reset_oscillators (struct hw *me);
214
215 static void
216 dv_m6811_attach_address_callback (struct hw *me,
217 int level,
218 int space,
219 address_word addr,
220 address_word nr_bytes,
221 struct hw *client)
222 {
223 HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
224 level, space, (unsigned long) addr, (unsigned long) nr_bytes,
225 hw_path (client)));
226
227 if (space != io_map)
228 {
229 sim_core_attach (hw_system (me),
230 NULL, /*cpu*/
231 level,
232 access_read_write_exec,
233 space, addr,
234 nr_bytes,
235 0, /* modulo */
236 client,
237 NULL);
238 }
239 else
240 {
241 /*printf("Attach from sub device: %d\n", (long) addr);*/
242 sim_core_attach (hw_system (me),
243 NULL, /*cpu*/
244 level,
245 access_io,
246 space, addr,
247 nr_bytes,
248 0, /* modulo */
249 client,
250 NULL);
251 }
252 }
253
254 static void
255 dv_m6811_detach_address_callback (struct hw *me,
256 int level,
257 int space,
258 address_word addr,
259 address_word nr_bytes,
260 struct hw *client)
261 {
262 sim_core_detach (hw_system (me), NULL, /*cpu*/
263 level, space, addr);
264 }
265
266 static void
267 m68hc11_delete (struct hw* me)
268 {
269 struct m68hc11cpu *controller;
270
271 controller = hw_data (me);
272
273 reset_oscillators (me);
274 hw_detach_address (me, M6811_IO_LEVEL,
275 controller->attach_space,
276 controller->attach_address,
277 controller->attach_size, me);
278 }
279
280
281 static void
282 attach_m68hc11_regs (struct hw *me,
283 struct m68hc11cpu *controller)
284 {
285 SIM_DESC sd;
286 sim_cpu *cpu;
287 reg_property_spec reg;
288 const char *cpu_mode;
289
290 if (hw_find_property (me, "reg") == NULL)
291 hw_abort (me, "Missing \"reg\" property");
292
293 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
294 hw_abort (me, "\"reg\" property must contain one addr/size entry");
295
296 hw_unit_address_to_attach_address (hw_parent (me),
297 &reg.address,
298 &controller->attach_space,
299 &controller->attach_address,
300 me);
301 hw_unit_size_to_attach_size (hw_parent (me),
302 &reg.size,
303 &controller->attach_size, me);
304
305 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
306 controller->attach_space,
307 controller->attach_address,
308 controller->attach_size,
309 me);
310 set_hw_delete (me, m68hc11_delete);
311
312 /* Get cpu frequency. */
313 sd = hw_system (me);
314 cpu = STATE_CPU (sd, 0);
315 if (hw_find_property (me, "clock") != NULL)
316 {
317 cpu->cpu_frequency = hw_find_integer_property (me, "clock");
318 }
319 else
320 {
321 cpu->cpu_frequency = 8*1000*1000;
322 }
323
324 if (hw_find_property (me, "use_bank") != NULL)
325 hw_attach_address (hw_parent (me), 0,
326 exec_map,
327 cpu->bank_start,
328 cpu->bank_end - cpu->bank_start,
329 me);
330
331 cpu_mode = "expanded";
332 if (hw_find_property (me, "mode") != NULL)
333 cpu_mode = hw_find_string_property (me, "mode");
334
335 if (strcmp (cpu_mode, "test") == 0)
336 cpu->cpu_mode = M6811_MDA | M6811_SMOD;
337 else if (strcmp (cpu_mode, "bootstrap") == 0)
338 cpu->cpu_mode = M6811_SMOD;
339 else if (strcmp (cpu_mode, "single") == 0)
340 cpu->cpu_mode = 0;
341 else
342 cpu->cpu_mode = M6811_MDA;
343
344 controller->last_oscillator = 0;
345
346 /* Create oscillators for input port A. */
347 make_oscillator (controller, "A7", M6811_PORTA, 0x80);
348 make_oscillator (controller, "A2", M6811_PORTA, 0x04);
349 make_oscillator (controller, "A1", M6811_PORTA, 0x02);
350 make_oscillator (controller, "A0", M6811_PORTA, 0x01);
351
352 /* port B is output only. */
353
354 /* Create oscillators for input port C. */
355 make_oscillator (controller, "C0", M6811_PORTC, 0x01);
356 make_oscillator (controller, "C1", M6811_PORTC, 0x02);
357 make_oscillator (controller, "C2", M6811_PORTC, 0x04);
358 make_oscillator (controller, "C3", M6811_PORTC, 0x08);
359 make_oscillator (controller, "C4", M6811_PORTC, 0x10);
360 make_oscillator (controller, "C5", M6811_PORTC, 0x20);
361 make_oscillator (controller, "C6", M6811_PORTC, 0x40);
362 make_oscillator (controller, "C7", M6811_PORTC, 0x80);
363
364 /* Create oscillators for input port D. */
365 make_oscillator (controller, "D0", M6811_PORTD, 0x01);
366 make_oscillator (controller, "D1", M6811_PORTD, 0x02);
367 make_oscillator (controller, "D2", M6811_PORTD, 0x04);
368 make_oscillator (controller, "D3", M6811_PORTD, 0x08);
369 make_oscillator (controller, "D4", M6811_PORTD, 0x10);
370 make_oscillator (controller, "D5", M6811_PORTD, 0x20);
371
372 /* Add oscillator commands. */
373 sim_add_option_table (sd, 0, m68hc11_options);
374 }
375
376 static void
377 m68hc11cpu_finish (struct hw *me)
378 {
379 struct m68hc11cpu *controller;
380
381 controller = HW_ZALLOC (me, struct m68hc11cpu);
382 set_hw_data (me, controller);
383 set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
384 set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
385 set_hw_ports (me, m68hc11cpu_ports);
386 set_hw_port_event (me, m68hc11cpu_port_event);
387 set_hw_attach_address (me, dv_m6811_attach_address_callback);
388 set_hw_detach_address (me, dv_m6811_detach_address_callback);
389 #ifdef set_hw_ioctl
390 set_hw_ioctl (me, m68hc11_ioctl);
391 #else
392 me->to_ioctl = m68hc11_ioctl;
393 #endif
394
395 /* Initialize the pending interrupt flags. */
396 controller->pending_level = 0;
397 controller->pending_reset = 0;
398 controller->pending_nmi = 0;
399 controller->event = NULL;
400
401 attach_m68hc11_regs (me, controller);
402 }
403
404 /* An event arrives on an interrupt port. */
405
406 static void
407 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
408 {
409 }
410
411 static void
412 make_oscillator (struct m68hc11cpu *controller, const char *name,
413 uint16 addr, uint8 mask)
414 {
415 struct input_osc *osc;
416
417 if (controller->last_oscillator >= NR_OSC)
418 hw_abort (0, "Too many oscillators");
419
420 osc = &controller->oscillators[controller->last_oscillator];
421 osc->name = name;
422 osc->addr = addr;
423 osc->mask = mask;
424 controller->last_oscillator++;
425 }
426
427 /* Find the oscillator given the input port name. */
428 static struct input_osc *
429 find_oscillator (struct m68hc11cpu *controller, const char *name)
430 {
431 int i;
432
433 for (i = 0; i < controller->last_oscillator; i++)
434 if (strcasecmp (controller->oscillators[i].name, name) == 0)
435 return &controller->oscillators[i];
436
437 return 0;
438 }
439
440 static void
441 oscillator_handler (struct hw *me, void *data)
442 {
443 struct input_osc *osc = (struct input_osc*) data;
444 SIM_DESC sd;
445 sim_cpu *cpu;
446 signed64 dt;
447 uint8 val;
448
449 sd = hw_system (me);
450 cpu = STATE_CPU (sd, 0);
451
452 /* Change the input bit. */
453 osc->value ^= osc->mask;
454 val = cpu->ios[osc->addr] & ~osc->mask;
455 val |= osc->value;
456 m68hc11cpu_set_port (me, cpu, osc->addr, val);
457
458 /* Setup event to toggle the bit. */
459 if (osc->value)
460 dt = osc->on_time;
461 else
462 dt = osc->off_time;
463
464 if (dt && --osc->repeat >= 0)
465 {
466 sim_events *events = STATE_EVENTS (sd);
467
468 dt += events->nr_ticks_to_process;
469 osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc);
470 }
471 else
472 osc->event = 0;
473 }
474
475 static void
476 reset_oscillators (struct hw *me)
477 {
478 struct m68hc11cpu *controller = hw_data (me);
479 int i;
480
481 for (i = 0; i < controller->last_oscillator; i++)
482 {
483 if (controller->oscillators[i].event)
484 {
485 hw_event_queue_deschedule (me, controller->oscillators[i].event);
486 controller->oscillators[i].event = 0;
487 }
488 }
489 }
490
491 static void
492 m68hc11cpu_port_event (struct hw *me,
493 int my_port,
494 struct hw *source,
495 int source_port,
496 int level)
497 {
498 struct m68hc11cpu *controller = hw_data (me);
499 SIM_DESC sd;
500 sim_cpu* cpu;
501
502 sd = hw_system (me);
503 cpu = STATE_CPU (sd, 0);
504 switch (my_port)
505 {
506 case RESET_PORT:
507 HW_TRACE ((me, "port-in reset"));
508
509 /* The reset is made in 3 steps:
510 - First, cleanup the current sim_cpu struct.
511 - Reset the devices.
512 - Restart the cpu for the reset (get the CPU mode from the
513 CONFIG register that gets initialized by EEPROM device). */
514 cpu_reset (cpu);
515 reset_oscillators (me);
516 hw_port_event (me, CPU_RESET_PORT, 1);
517 cpu_restart (cpu);
518 break;
519
520 case NMI_PORT:
521 controller->pending_nmi = 1;
522 HW_TRACE ((me, "port-in nmi"));
523 break;
524
525 case IRQ_PORT:
526 /* level == 0 means that the interrupt was cleared. */
527 if(level == 0)
528 controller->pending_level = -1; /* signal end of interrupt */
529 else
530 controller->pending_level = level;
531 HW_TRACE ((me, "port-in level=%d", level));
532 break;
533
534 case SET_PORT_A:
535 m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
536 break;
537
538 case SET_PORT_C:
539 m68hc11cpu_set_port (me, cpu, M6811_PORTC, level);
540 break;
541
542 case SET_PORT_D:
543 m68hc11cpu_set_port (me, cpu, M6811_PORTD, level);
544 break;
545
546 case CPU_WRITE_PORT:
547 break;
548
549 default:
550 hw_abort (me, "bad switch");
551 break;
552 }
553
554 /* Schedule an event to be delivered immediately after current
555 instruction. */
556 if(controller->event != NULL)
557 hw_event_queue_deschedule(me, controller->event);
558 controller->event =
559 hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
560 }
561
562
563 io_reg_desc config_desc[] = {
564 { M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
565 { M6811_NOCOP, "NOCOP ", "COP System Disable" },
566 { M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
567 { M6811_EEON, "EEON ", "Enable On-chip EEprom" },
568 { 0, 0, 0 }
569 };
570
571 io_reg_desc hprio_desc[] = {
572 { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
573 { M6811_SMOD, "SMOD ", "Special Mode" },
574 { M6811_MDA, "MDA ", "Mode Select A" },
575 { M6811_IRV, "IRV ", "Internal Read Visibility" },
576 { 0, 0, 0 }
577 };
578
579 io_reg_desc option_desc[] = {
580 { M6811_ADPU, "ADPU ", "A/D Powerup" },
581 { M6811_CSEL, "CSEL ", "A/D/EE Charge pump clock source select" },
582 { M6811_IRQE, "IRQE ", "IRQ Edge/Level sensitive" },
583 { M6811_DLY, "DLY ", "Stop exit turn on delay" },
584 { M6811_CME, "CME ", "Clock Monitor Enable" },
585 { M6811_CR1, "CR1 ", "COP timer rate select (CR1)" },
586 { M6811_CR0, "CR0 ", "COP timer rate select (CR0)" },
587 { 0, 0, 0 }
588 };
589
590 static void
591 m68hc11_info (struct hw *me)
592 {
593 SIM_DESC sd;
594 uint16 base = 0;
595 sim_cpu *cpu;
596 struct m68hc11sio *controller;
597 uint8 val;
598
599 sd = hw_system (me);
600 cpu = STATE_CPU (sd, 0);
601 controller = hw_data (me);
602
603 base = cpu_get_io_base (cpu);
604 sim_io_printf (sd, "M68HC11:\n");
605
606 val = cpu->ios[M6811_HPRIO];
607 print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
608 switch (cpu->cpu_mode)
609 {
610 case M6811_MDA | M6811_SMOD:
611 sim_io_printf (sd, "[test]\n");
612 break;
613 case M6811_SMOD:
614 sim_io_printf (sd, "[bootstrap]\n");
615 break;
616 case M6811_MDA:
617 sim_io_printf (sd, "[extended]\n");
618 break;
619 default:
620 sim_io_printf (sd, "[single]\n");
621 break;
622 }
623
624 val = cpu->ios[M6811_CONFIG];
625 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
626 sim_io_printf (sd, "\n");
627
628 val = cpu->ios[M6811_OPTION];
629 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
630 sim_io_printf (sd, "\n");
631
632 val = cpu->ios[M6811_INIT];
633 print_io_byte (sd, "INIT ", 0, val, base + M6811_INIT);
634 sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
635 (((uint16) (val & 0xF0)) << 8),
636 (((uint16) (val & 0x0F)) << 12));
637
638
639 cpu_info (sd, cpu);
640 interrupts_info (sd, &cpu->cpu_interrupts);
641 }
642
643 static int
644 m68hc11_ioctl (struct hw *me,
645 hw_ioctl_request request,
646 va_list ap)
647 {
648 m68hc11_info (me);
649 return 0;
650 }
651
652 /* Setup an oscillator on an input port.
653
654 TON represents the time in seconds that the input port should be set to 1.
655 TOFF is the time in seconds for the input port to be set to 0.
656
657 The oscillator frequency is therefore 1 / (ton + toff).
658
659 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
660 stops. */
661 int
662 m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
663 double ton, double toff, signed64 repeat)
664 {
665 sim_cpu *cpu;
666 struct input_osc *osc;
667 double f;
668
669 cpu = STATE_CPU (sd, 0);
670
671 /* Find oscillator that corresponds to the input port. */
672 osc = find_oscillator (hw_data (cpu->hw_cpu), port);
673 if (osc == 0)
674 return -1;
675
676 /* Compute the ON time in cpu cycles. */
677 f = (double) (cpu->cpu_frequency) * ton;
678 osc->on_time = (signed64) (f / 4.0);
679 if (osc->on_time < 1)
680 osc->on_time = 1;
681
682 /* Compute the OFF time in cpu cycles. */
683 f = (double) (cpu->cpu_frequency) * toff;
684 osc->off_time = (signed64) (f / 4.0);
685 if (osc->off_time < 1)
686 osc->off_time = 1;
687
688 osc->repeat = repeat;
689 if (osc->event)
690 hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
691
692 osc->event = hw_event_queue_schedule (cpu->hw_cpu,
693 osc->value ? osc->on_time
694 : osc->off_time,
695 oscillator_handler, osc);
696 return 0;
697 }
698
699 /* Clear the oscillator. */
700 int
701 m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port)
702 {
703 sim_cpu *cpu;
704 struct input_osc *osc;
705
706 cpu = STATE_CPU (sd, 0);
707 osc = find_oscillator (hw_data (cpu->hw_cpu), port);
708 if (osc == 0)
709 return -1;
710
711 if (osc->event)
712 hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
713 osc->event = 0;
714 osc->repeat = 0;
715 return 0;
716 }
717
718 static int
719 get_frequency (const char *s, double *f)
720 {
721 char *p;
722
723 *f = strtod (s, &p);
724 if (s == p)
725 return -1;
726
727 if (*p)
728 {
729 if (strcasecmp (p, "khz") == 0)
730 *f = *f * 1000.0;
731 else if (strcasecmp (p, "mhz") == 0)
732 *f = *f * 1000000.0;
733 else if (strcasecmp (p, "hz") != 0)
734 return -1;
735 }
736 return 0;
737 }
738
739 static SIM_RC
740 m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu,
741 int opt, char *arg, int is_command)
742 {
743 struct m68hc11cpu *controller;
744 double f;
745 char *p;
746 int i;
747 int title_printed = 0;
748
749 if (cpu == 0)
750 cpu = STATE_CPU (sd, 0);
751
752 controller = hw_data (cpu->hw_cpu);
753 switch (opt)
754 {
755 case OPTION_OSC_SET:
756 p = strchr (arg, ',');
757 if (p)
758 *p++ = 0;
759
760 if (p == 0)
761 sim_io_eprintf (sd, "No frequency specified\n");
762 else if (get_frequency (p, &f) < 0 || f < 1.0e-8)
763 sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p);
764 else if (m68hc11cpu_set_oscillator (sd, arg,
765 1.0 / (f * 2.0),
766 1.0 / (f * 2.0), LONG_MAX))
767 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
768 break;
769
770 case OPTION_OSC_CLEAR:
771 if (m68hc11cpu_clear_oscillator (sd, arg) != 0)
772 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
773 break;
774
775 case OPTION_OSC_INFO:
776 for (i = 0; i < controller->last_oscillator; i++)
777 {
778 signed64 t;
779 struct input_osc *osc;
780
781 osc = &controller->oscillators[i];
782 if (osc->event)
783 {
784 double f;
785 int cur_value;
786 int next_value;
787 char freq[32];
788
789 if (title_printed == 0)
790 {
791 title_printed = 1;
792 sim_io_printf (sd, " PORT Frequency Current"
793 " Next Transition time\n");
794 }
795
796 f = (double) (osc->on_time + osc->off_time);
797 f = (double) (cpu->cpu_frequency / 4) / f;
798 t = hw_event_remain_time (cpu->hw_cpu, osc->event);
799
800 if (f > 10000.0)
801 sprintf (freq, "%6.2f", f / 1000.0);
802 else
803 sprintf (freq, "%6.2f", f);
804 cur_value = osc->value ? 1 : 0;
805 next_value = osc->value ? 0 : 1;
806 if (f > 10000.0)
807 sim_io_printf (sd, " %4.4s %8.8s khz"
808 " %d %d %35.35s\n",
809 osc->name, freq,
810 cur_value, next_value,
811 cycle_to_string (cpu, t));
812 else
813 sim_io_printf (sd, " %4.4s %8.8s hz "
814 " %d %d %35.35s\n",
815 osc->name, freq,
816 cur_value, next_value,
817 cycle_to_string (cpu, t));
818 }
819 }
820 break;
821 }
822
823 return SIM_RC_OK;
824 }
825
826 /* generic read/write */
827
828 static unsigned
829 m68hc11cpu_io_read_buffer (struct hw *me,
830 void *dest,
831 int space,
832 unsigned_word base,
833 unsigned nr_bytes)
834 {
835 SIM_DESC sd;
836 struct m68hc11cpu *controller = hw_data (me);
837 sim_cpu *cpu;
838 unsigned byte = 0;
839 int result;
840
841 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
842
843 sd = hw_system (me);
844 cpu = STATE_CPU (sd, 0);
845
846 if (base >= cpu->bank_start && base < cpu->bank_end)
847 {
848 address_word virt_addr = phys_to_virt (cpu, base);
849 if (virt_addr != base)
850 return sim_core_read_buffer (sd, cpu, space, dest,
851 virt_addr, nr_bytes);
852 }
853
854 /* Handle reads for the sub-devices. */
855 base -= controller->attach_address;
856 result = sim_core_read_buffer (sd, cpu,
857 io_map, dest, base, nr_bytes);
858 if (result > 0)
859 return result;
860
861 while (nr_bytes)
862 {
863 if (base >= controller->attach_size)
864 break;
865
866 memcpy (dest, &cpu->ios[base], 1);
867 dest = (char*) dest + 1;
868 base++;
869 byte++;
870 nr_bytes--;
871 }
872 return byte;
873 }
874
875 void
876 m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
877 unsigned addr, uint8 val)
878 {
879 uint8 mask;
880 uint8 delta;
881 int check_interrupts = 0;
882 int i;
883
884 switch (addr)
885 {
886 case M6811_PORTA:
887 if (cpu->ios[M6811_PACTL] & M6811_DDRA7)
888 mask = 3;
889 else
890 mask = 0x83;
891
892 val = val & mask;
893 val |= cpu->ios[M6811_PORTA] & ~mask;
894 delta = val ^ cpu->ios[M6811_PORTA];
895 cpu->ios[M6811_PORTA] = val;
896 if (delta & 0x80)
897 {
898 /* Pulse accumulator is enabled. */
899 if ((cpu->ios[M6811_PACTL] & M6811_PAEN)
900 && !(cpu->ios[M6811_PACTL] & M6811_PAMOD))
901 {
902 int inc;
903
904 /* Increment event counter according to rising/falling edge. */
905 if (cpu->ios[M6811_PACTL] & M6811_PEDGE)
906 inc = (val & 0x80) ? 1 : 0;
907 else
908 inc = (val & 0x80) ? 0 : 1;
909
910 cpu->ios[M6811_PACNT] += inc;
911
912 /* Event counter overflowed. */
913 if (inc && cpu->ios[M6811_PACNT] == 0)
914 {
915 cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
916 check_interrupts = 1;
917 }
918 }
919 }
920
921 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
922 for (i = 0; i < 3; i++)
923 {
924 uint8 mask = (1 << i);
925
926 if (delta & mask)
927 {
928 uint8 edge;
929 int captured;
930
931 edge = cpu->ios[M6811_TCTL2];
932 edge = (edge >> (2 * i)) & 0x3;
933 switch (edge)
934 {
935 case 0:
936 captured = 0;
937 break;
938 case 1:
939 captured = (val & mask) != 0;
940 break;
941 case 2:
942 captured = (val & mask) == 0;
943 break;
944 default:
945 captured = 1;
946 break;
947 }
948 if (captured)
949 {
950 cpu->ios[M6811_TFLG1] |= (1 << i);
951 hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
952 check_interrupts = 1;
953 }
954 }
955 }
956 break;
957
958 case M6811_PORTC:
959 mask = cpu->ios[M6811_DDRC];
960 val = val & mask;
961 val |= cpu->ios[M6811_PORTC] & ~mask;
962 cpu->ios[M6811_PORTC] = val;
963 break;
964
965 case M6811_PORTD:
966 mask = cpu->ios[M6811_DDRD];
967 val = val & mask;
968 val |= cpu->ios[M6811_PORTD] & ~mask;
969 cpu->ios[M6811_PORTD] = val;
970 break;
971
972 default:
973 break;
974 }
975
976 if (check_interrupts)
977 interrupts_update_pending (&cpu->cpu_interrupts);
978 }
979
980 static void
981 m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
982 unsigned_word addr, uint8 val)
983 {
984 switch (addr)
985 {
986 case M6811_PORTA:
987 hw_port_event (me, PORT_A, val);
988 break;
989
990 case M6811_PIOC:
991 break;
992
993 case M6811_PORTC:
994 hw_port_event (me, PORT_C, val);
995 break;
996
997 case M6811_PORTB:
998 hw_port_event (me, PORT_B, val);
999 break;
1000
1001 case M6811_PORTCL:
1002 break;
1003
1004 case M6811_DDRC:
1005 break;
1006
1007 case M6811_PORTD:
1008 hw_port_event (me, PORT_D, val);
1009 break;
1010
1011 case M6811_DDRD:
1012 break;
1013
1014 case M6811_TMSK2:
1015
1016 break;
1017
1018 /* Change the RAM and I/O mapping. */
1019 case M6811_INIT:
1020 {
1021 uint8 old_bank = cpu->ios[M6811_INIT];
1022
1023 cpu->ios[M6811_INIT] = val;
1024
1025 /* Update IO mapping. Detach from the old address
1026 and attach to the new one. */
1027 if ((old_bank & 0x0F) != (val & 0x0F))
1028 {
1029 struct m68hc11cpu *controller = hw_data (me);
1030
1031 hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
1032 controller->attach_space,
1033 controller->attach_address,
1034 controller->attach_size,
1035 me);
1036 controller->attach_address = (val & 0x0F0) << 12;
1037 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
1038 controller->attach_space,
1039 controller->attach_address,
1040 controller->attach_size,
1041 me);
1042 }
1043 if ((old_bank & 0xF0) != (val & 0xF0))
1044 {
1045 ;
1046 }
1047 return;
1048 }
1049
1050 /* Writing the config is similar to programing the eeprom.
1051 The config register value is the last byte of the EEPROM.
1052 This last byte is not mapped in memory (that's why we have
1053 to add '1' to 'end_addr'). */
1054 case M6811_CONFIG:
1055 {
1056 return;
1057 }
1058
1059
1060 /* COP reset. */
1061 case M6811_COPRST:
1062 if (val == 0xAA && cpu->ios[addr] == 0x55)
1063 {
1064 val = 0;
1065 /* COP reset here. */
1066 }
1067 break;
1068
1069 default:
1070 break;
1071
1072 }
1073 cpu->ios[addr] = val;
1074 }
1075
1076 static unsigned
1077 m68hc11cpu_io_write_buffer (struct hw *me,
1078 const void *source,
1079 int space,
1080 unsigned_word base,
1081 unsigned nr_bytes)
1082 {
1083 SIM_DESC sd;
1084 struct m68hc11cpu *controller = hw_data (me);
1085 unsigned byte;
1086 sim_cpu *cpu;
1087 int result;
1088
1089 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
1090
1091 sd = hw_system (me);
1092 cpu = STATE_CPU (sd, 0);
1093
1094 if (base >= cpu->bank_start && base < cpu->bank_end)
1095 {
1096 address_word virt_addr = phys_to_virt (cpu, base);
1097 if (virt_addr != base)
1098 return sim_core_write_buffer (sd, cpu, space, source,
1099 virt_addr, nr_bytes);
1100 }
1101 base -= controller->attach_address;
1102 result = sim_core_write_buffer (sd, cpu,
1103 io_map, source, base, nr_bytes);
1104 if (result > 0)
1105 return result;
1106
1107 byte = 0;
1108 while (nr_bytes)
1109 {
1110 uint8 val;
1111 if (base >= controller->attach_size)
1112 break;
1113
1114 val = *((uint8*) source);
1115 m68hc11cpu_io_write (me, cpu, base, val);
1116 source = (char*) source + 1;
1117 base++;
1118 byte++;
1119 nr_bytes--;
1120 }
1121 return byte;
1122 }
1123
1124 const struct hw_descriptor dv_m68hc11_descriptor[] = {
1125 { "m68hc11", m68hc11cpu_finish },
1126 { "m68hc12", m68hc11cpu_finish },
1127 { NULL },
1128 };
1129