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