Extend objdump's --show-all-symbols option so that it also shows the extra symbols...
[binutils-gdb.git] / sim / m68hc11 / dv-m68hc11.c
blob93300bacae4bba2ea87f831b773470efbb91e119
1 /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2 Copyright (C) 1999-2024 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@nerim.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 3 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, see <http://www.gnu.org/licenses/>.
21 /* This must come before any other includes. */
22 #include "defs.h"
24 #include "sim-main.h"
25 #include "sim-hw.h"
26 #include "hw-main.h"
27 #include "sim-options.h"
28 #include "hw-base.h"
29 #include <limits.h>
30 #include <stdlib.h>
32 #include "m68hc11-sim.h"
34 /* DEVICE
36 m68hc11cpu - m68hc11 cpu virtual device
37 m68hc12cpu - m68hc12 cpu virtual device
39 DESCRIPTION
41 Implements the external m68hc11/68hc12 functionality. This includes
42 the delivery of of interrupts generated from other devices and the
43 handling of device specific registers.
46 PROPERTIES
48 reg <base> <size>
50 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
52 clock <hz>
54 Frequency of the quartz used by the processor.
56 mode [single | expanded | bootstrap | test]
58 Cpu operating mode (the MODA and MODB external pins).
61 PORTS
63 reset (input)
65 Reset the cpu and generates a cpu-reset event (used to reset
66 other devices).
68 nmi (input)
70 Deliver a non-maskable interrupt to the processor.
73 set-port-a (input)
74 set-port-c (input)
75 set-pord-d (input)
77 Allow an external device to set the value of port A, C or D inputs.
80 cpu-reset (output)
82 Event generated after the CPU performs a reset.
85 port-a (output)
86 port-b (output)
87 port-c (output)
88 port-d (output)
90 Event generated when the value of the output port A, B, C or D
91 changes.
94 BUGS
96 When delivering an interrupt, this code assumes that there is only
97 one processor (number 0).
101 enum
103 OPTION_OSC_SET = OPTION_START,
104 OPTION_OSC_CLEAR,
105 OPTION_OSC_INFO
108 static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
110 static const OPTION m68hc11_options[] =
112 { {"osc-set", required_argument, NULL, OPTION_OSC_SET },
113 '\0', "BIT,FREQ", "Set the oscillator on input port BIT",
114 m68hc11_option_handler },
115 { {"osc-clear", required_argument, NULL, OPTION_OSC_CLEAR },
116 '\0', "BIT", "Clear oscillator on input port BIT",
117 m68hc11_option_handler },
118 { {"osc-info", no_argument, NULL, OPTION_OSC_INFO },
119 '\0', NULL, "Print information about current input oscillators",
120 m68hc11_option_handler },
122 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
125 struct input_osc
127 int64_t on_time;
128 int64_t off_time;
129 int64_t repeat;
130 struct hw_event *event;
131 const char *name;
132 uint8_t mask;
133 uint8_t value;
134 uint16_t addr;
137 #define NR_PORT_A_OSC (4)
138 #define NR_PORT_B_OSC (0)
139 #define NR_PORT_C_OSC (8)
140 #define NR_PORT_D_OSC (6)
141 #define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC)
142 struct m68hc11cpu {
143 /* Pending interrupts for delivery by event handler. */
144 int pending_reset;
145 int pending_nmi;
146 int pending_level;
147 struct hw_event *event;
148 unsigned_word attach_address;
149 unsigned int attach_size;
150 int attach_space;
151 int last_oscillator;
152 struct input_osc oscillators[NR_OSC];
157 /* input port ID's */
159 enum {
160 RESET_PORT,
161 NMI_PORT,
162 IRQ_PORT,
163 CPU_RESET_PORT,
164 SET_PORT_A,
165 SET_PORT_C,
166 SET_PORT_D,
167 CPU_WRITE_PORT,
168 PORT_A,
169 PORT_B,
170 PORT_C,
171 PORT_D,
172 CAPTURE
176 static const struct hw_port_descriptor m68hc11cpu_ports[] = {
178 /* Interrupt inputs. */
179 { "reset", RESET_PORT, 0, input_port, },
180 { "nmi", NMI_PORT, 0, input_port, },
181 { "irq", IRQ_PORT, 0, input_port, },
183 { "set-port-a", SET_PORT_A, 0, input_port, },
184 { "set-port-c", SET_PORT_C, 0, input_port, },
185 { "set-port-d", SET_PORT_D, 0, input_port, },
187 { "cpu-write-port", CPU_WRITE_PORT, 0, input_port, },
189 /* Events generated for connection to other devices. */
190 { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
192 /* Events generated when the corresponding port is
193 changed by the program. */
194 { "port-a", PORT_A, 0, output_port, },
195 { "port-b", PORT_B, 0, output_port, },
196 { "port-c", PORT_C, 0, output_port, },
197 { "port-d", PORT_D, 0, output_port, },
199 { "capture", CAPTURE, 0, output_port, },
201 { NULL, },
204 static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
205 static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
206 static hw_ioctl_method m68hc11_ioctl;
208 /* Finish off the partially created hw device. Attach our local
209 callbacks. Wire up our port names etc. */
211 static hw_port_event_method m68hc11cpu_port_event;
213 static void make_oscillator (struct m68hc11cpu *controller,
214 const char *id, uint16_t addr, uint8_t mask);
215 static struct input_osc *find_oscillator (struct m68hc11cpu *controller,
216 const char *id);
217 static void reset_oscillators (struct hw *me);
219 static void
220 dv_m6811_attach_address_callback (struct hw *me,
221 int level,
222 int space,
223 address_word addr,
224 address_word nr_bytes,
225 struct hw *client)
227 HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
228 level, space, (unsigned long) addr, (unsigned long) nr_bytes,
229 hw_path (client)));
231 if (space != io_map)
233 sim_core_attach (hw_system (me),
234 NULL, /*cpu*/
235 level,
236 access_read_write_exec,
237 space, addr,
238 nr_bytes,
239 0, /* modulo */
240 client,
241 NULL);
243 else
245 /*printf("Attach from sub device: %d\n", (long) addr);*/
246 sim_core_attach (hw_system (me),
247 NULL, /*cpu*/
248 level,
249 access_io,
250 space, addr,
251 nr_bytes,
252 0, /* modulo */
253 client,
254 NULL);
258 static void
259 m68hc11_delete (struct hw* me)
261 struct m68hc11cpu *controller;
263 controller = hw_data (me);
265 reset_oscillators (me);
266 hw_detach_address (me, M6811_IO_LEVEL,
267 controller->attach_space,
268 controller->attach_address,
269 controller->attach_size, me);
273 static void
274 attach_m68hc11_regs (struct hw *me,
275 struct m68hc11cpu *controller)
277 SIM_DESC sd;
278 sim_cpu *cpu;
279 struct m68hc11_sim_cpu *m68hc11_cpu;
280 reg_property_spec reg;
281 const char *cpu_mode;
283 if (hw_find_property (me, "reg") == NULL)
284 hw_abort (me, "Missing \"reg\" property");
286 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
287 hw_abort (me, "\"reg\" property must contain one addr/size entry");
289 hw_unit_address_to_attach_address (hw_parent (me),
290 &reg.address,
291 &controller->attach_space,
292 &controller->attach_address,
293 me);
294 hw_unit_size_to_attach_size (hw_parent (me),
295 &reg.size,
296 &controller->attach_size, me);
298 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
299 controller->attach_space,
300 controller->attach_address,
301 controller->attach_size,
302 me);
303 set_hw_delete (me, m68hc11_delete);
305 /* Get cpu frequency. */
306 sd = hw_system (me);
307 cpu = STATE_CPU (sd, 0);
308 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
309 if (hw_find_property (me, "clock") != NULL)
311 m68hc11_cpu->cpu_frequency = hw_find_integer_property (me, "clock");
313 else
315 m68hc11_cpu->cpu_frequency = 8*1000*1000;
318 if (hw_find_property (me, "use_bank") != NULL)
319 hw_attach_address (hw_parent (me), 0,
320 exec_map,
321 m68hc11_cpu->bank_start,
322 m68hc11_cpu->bank_end - m68hc11_cpu->bank_start,
323 me);
325 cpu_mode = "expanded";
326 if (hw_find_property (me, "mode") != NULL)
327 cpu_mode = hw_find_string_property (me, "mode");
329 if (strcmp (cpu_mode, "test") == 0)
330 m68hc11_cpu->cpu_mode = M6811_MDA | M6811_SMOD;
331 else if (strcmp (cpu_mode, "bootstrap") == 0)
332 m68hc11_cpu->cpu_mode = M6811_SMOD;
333 else if (strcmp (cpu_mode, "single") == 0)
334 m68hc11_cpu->cpu_mode = 0;
335 else
336 m68hc11_cpu->cpu_mode = M6811_MDA;
338 controller->last_oscillator = 0;
340 /* Create oscillators for input port A. */
341 make_oscillator (controller, "A7", M6811_PORTA, 0x80);
342 make_oscillator (controller, "A2", M6811_PORTA, 0x04);
343 make_oscillator (controller, "A1", M6811_PORTA, 0x02);
344 make_oscillator (controller, "A0", M6811_PORTA, 0x01);
346 /* port B is output only. */
348 /* Create oscillators for input port C. */
349 make_oscillator (controller, "C0", M6811_PORTC, 0x01);
350 make_oscillator (controller, "C1", M6811_PORTC, 0x02);
351 make_oscillator (controller, "C2", M6811_PORTC, 0x04);
352 make_oscillator (controller, "C3", M6811_PORTC, 0x08);
353 make_oscillator (controller, "C4", M6811_PORTC, 0x10);
354 make_oscillator (controller, "C5", M6811_PORTC, 0x20);
355 make_oscillator (controller, "C6", M6811_PORTC, 0x40);
356 make_oscillator (controller, "C7", M6811_PORTC, 0x80);
358 /* Create oscillators for input port D. */
359 make_oscillator (controller, "D0", M6811_PORTD, 0x01);
360 make_oscillator (controller, "D1", M6811_PORTD, 0x02);
361 make_oscillator (controller, "D2", M6811_PORTD, 0x04);
362 make_oscillator (controller, "D3", M6811_PORTD, 0x08);
363 make_oscillator (controller, "D4", M6811_PORTD, 0x10);
364 make_oscillator (controller, "D5", M6811_PORTD, 0x20);
366 /* Add oscillator commands. */
367 sim_add_option_table (sd, 0, m68hc11_options);
370 static void
371 m68hc11cpu_finish (struct hw *me)
373 struct m68hc11cpu *controller;
375 controller = HW_ZALLOC (me, struct m68hc11cpu);
376 set_hw_data (me, controller);
377 set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
378 set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
379 set_hw_ports (me, m68hc11cpu_ports);
380 set_hw_port_event (me, m68hc11cpu_port_event);
381 set_hw_attach_address (me, dv_m6811_attach_address_callback);
382 #ifdef set_hw_ioctl
383 set_hw_ioctl (me, m68hc11_ioctl);
384 #else
385 me->to_ioctl = m68hc11_ioctl;
386 #endif
388 /* Initialize the pending interrupt flags. */
389 controller->pending_level = 0;
390 controller->pending_reset = 0;
391 controller->pending_nmi = 0;
392 controller->event = NULL;
394 attach_m68hc11_regs (me, controller);
397 /* An event arrives on an interrupt port. */
399 static void
400 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
404 static void
405 make_oscillator (struct m68hc11cpu *controller, const char *name,
406 uint16_t addr, uint8_t mask)
408 struct input_osc *osc;
410 if (controller->last_oscillator >= NR_OSC)
411 hw_abort (0, "Too many oscillators");
413 osc = &controller->oscillators[controller->last_oscillator];
414 osc->name = name;
415 osc->addr = addr;
416 osc->mask = mask;
417 controller->last_oscillator++;
420 /* Find the oscillator given the input port name. */
421 static struct input_osc *
422 find_oscillator (struct m68hc11cpu *controller, const char *name)
424 int i;
426 for (i = 0; i < controller->last_oscillator; i++)
427 if (strcasecmp (controller->oscillators[i].name, name) == 0)
428 return &controller->oscillators[i];
430 return 0;
433 static void
434 oscillator_handler (struct hw *me, void *data)
436 struct input_osc *osc = (struct input_osc*) data;
437 SIM_DESC sd;
438 sim_cpu *cpu;
439 struct m68hc11_sim_cpu *m68hc11_cpu;
440 int64_t dt;
441 uint8_t val;
443 sd = hw_system (me);
444 cpu = STATE_CPU (sd, 0);
445 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
447 /* Change the input bit. */
448 osc->value ^= osc->mask;
449 val = m68hc11_cpu->ios[osc->addr] & ~osc->mask;
450 val |= osc->value;
451 m68hc11cpu_set_port (me, cpu, osc->addr, val);
453 /* Setup event to toggle the bit. */
454 if (osc->value)
455 dt = osc->on_time;
456 else
457 dt = osc->off_time;
459 if (dt && --osc->repeat >= 0)
461 sim_events *events = STATE_EVENTS (sd);
463 dt += events->nr_ticks_to_process;
464 osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc);
466 else
467 osc->event = 0;
470 static void
471 reset_oscillators (struct hw *me)
473 struct m68hc11cpu *controller = hw_data (me);
474 int i;
476 for (i = 0; i < controller->last_oscillator; i++)
478 if (controller->oscillators[i].event)
480 hw_event_queue_deschedule (me, controller->oscillators[i].event);
481 controller->oscillators[i].event = 0;
486 static void
487 m68hc11cpu_port_event (struct hw *me,
488 int my_port,
489 struct hw *source,
490 int source_port,
491 int level)
493 struct m68hc11cpu *controller = hw_data (me);
494 SIM_DESC sd;
495 sim_cpu *cpu;
497 sd = hw_system (me);
498 cpu = STATE_CPU (sd, 0);
499 switch (my_port)
501 case RESET_PORT:
502 HW_TRACE ((me, "port-in reset"));
504 /* The reset is made in 3 steps:
505 - First, cleanup the current sim_cpu struct.
506 - Reset the devices.
507 - Restart the cpu for the reset (get the CPU mode from the
508 CONFIG register that gets initialized by EEPROM device). */
509 cpu_reset (cpu);
510 reset_oscillators (me);
511 hw_port_event (me, CPU_RESET_PORT, 1);
512 cpu_restart (cpu);
513 break;
515 case NMI_PORT:
516 controller->pending_nmi = 1;
517 HW_TRACE ((me, "port-in nmi"));
518 break;
520 case IRQ_PORT:
521 /* level == 0 means that the interrupt was cleared. */
522 if(level == 0)
523 controller->pending_level = -1; /* signal end of interrupt */
524 else
525 controller->pending_level = level;
526 HW_TRACE ((me, "port-in level=%d", level));
527 break;
529 case SET_PORT_A:
530 m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
531 break;
533 case SET_PORT_C:
534 m68hc11cpu_set_port (me, cpu, M6811_PORTC, level);
535 break;
537 case SET_PORT_D:
538 m68hc11cpu_set_port (me, cpu, M6811_PORTD, level);
539 break;
541 case CPU_WRITE_PORT:
542 break;
544 default:
545 hw_abort (me, "bad switch");
546 break;
549 /* Schedule an event to be delivered immediately after current
550 instruction. */
551 if(controller->event != NULL)
552 hw_event_queue_deschedule(me, controller->event);
553 controller->event =
554 hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
558 io_reg_desc config_desc[] = {
559 { M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
560 { M6811_NOCOP, "NOCOP ", "COP System Disable" },
561 { M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
562 { M6811_EEON, "EEON ", "Enable On-chip EEprom" },
563 { 0, 0, 0 }
566 io_reg_desc hprio_desc[] = {
567 { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
568 { M6811_SMOD, "SMOD ", "Special Mode" },
569 { M6811_MDA, "MDA ", "Mode Select A" },
570 { M6811_IRV, "IRV ", "Internal Read Visibility" },
571 { 0, 0, 0 }
574 io_reg_desc option_desc[] = {
575 { M6811_ADPU, "ADPU ", "A/D Powerup" },
576 { M6811_CSEL, "CSEL ", "A/D/EE Charge pump clock source select" },
577 { M6811_IRQE, "IRQE ", "IRQ Edge/Level sensitive" },
578 { M6811_DLY, "DLY ", "Stop exit turn on delay" },
579 { M6811_CME, "CME ", "Clock Monitor Enable" },
580 { M6811_CR1, "CR1 ", "COP timer rate select (CR1)" },
581 { M6811_CR0, "CR0 ", "COP timer rate select (CR0)" },
582 { 0, 0, 0 }
585 static void
586 m68hc11_info (struct hw *me)
588 SIM_DESC sd;
589 uint16_t base = 0;
590 sim_cpu *cpu;
591 struct m68hc11_sim_cpu *m68hc11_cpu;
592 uint8_t val;
594 sd = hw_system (me);
595 cpu = STATE_CPU (sd, 0);
596 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
598 base = cpu_get_io_base (cpu);
599 sim_io_printf (sd, "M68HC11:\n");
601 val = m68hc11_cpu->ios[M6811_HPRIO];
602 print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
603 switch (m68hc11_cpu->cpu_mode)
605 case M6811_MDA | M6811_SMOD:
606 sim_io_printf (sd, "[test]\n");
607 break;
608 case M6811_SMOD:
609 sim_io_printf (sd, "[bootstrap]\n");
610 break;
611 case M6811_MDA:
612 sim_io_printf (sd, "[extended]\n");
613 break;
614 default:
615 sim_io_printf (sd, "[single]\n");
616 break;
619 val = m68hc11_cpu->ios[M6811_CONFIG];
620 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
621 sim_io_printf (sd, "\n");
623 val = m68hc11_cpu->ios[M6811_OPTION];
624 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
625 sim_io_printf (sd, "\n");
627 val = m68hc11_cpu->ios[M6811_INIT];
628 print_io_byte (sd, "INIT ", 0, val, base + M6811_INIT);
629 sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
630 (((uint16_t) (val & 0xF0)) << 8),
631 (((uint16_t) (val & 0x0F)) << 12));
634 cpu_info (sd, cpu);
635 interrupts_info (sd, &m68hc11_cpu->cpu_interrupts);
638 static int
639 m68hc11_ioctl (struct hw *me,
640 hw_ioctl_request request,
641 va_list ap)
643 m68hc11_info (me);
644 return 0;
647 /* Setup an oscillator on an input port.
649 TON represents the time in seconds that the input port should be set to 1.
650 TOFF is the time in seconds for the input port to be set to 0.
652 The oscillator frequency is therefore 1 / (ton + toff).
654 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
655 stops. */
657 m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
658 double ton, double toff, int64_t repeat)
660 sim_cpu *cpu;
661 struct m68hc11_sim_cpu *m68hc11_cpu;
662 struct input_osc *osc;
663 double f;
665 cpu = STATE_CPU (sd, 0);
666 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
668 /* Find oscillator that corresponds to the input port. */
669 osc = find_oscillator (hw_data (m68hc11_cpu->hw_cpu), port);
670 if (osc == 0)
671 return -1;
673 /* Compute the ON time in cpu cycles. */
674 f = (double) (m68hc11_cpu->cpu_frequency) * ton;
675 osc->on_time = (int64_t) (f / 4.0);
676 if (osc->on_time < 1)
677 osc->on_time = 1;
679 /* Compute the OFF time in cpu cycles. */
680 f = (double) (m68hc11_cpu->cpu_frequency) * toff;
681 osc->off_time = (int64_t) (f / 4.0);
682 if (osc->off_time < 1)
683 osc->off_time = 1;
685 osc->repeat = repeat;
686 if (osc->event)
687 hw_event_queue_deschedule (m68hc11_cpu->hw_cpu, osc->event);
689 osc->event = hw_event_queue_schedule (m68hc11_cpu->hw_cpu,
690 osc->value ? osc->on_time
691 : osc->off_time,
692 oscillator_handler, osc);
693 return 0;
696 /* Clear the oscillator. */
698 m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port)
700 sim_cpu *cpu;
701 struct m68hc11_sim_cpu *m68hc11_cpu;
702 struct input_osc *osc;
704 cpu = STATE_CPU (sd, 0);
705 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
706 osc = find_oscillator (hw_data (m68hc11_cpu->hw_cpu), port);
707 if (osc == 0)
708 return -1;
710 if (osc->event)
711 hw_event_queue_deschedule (m68hc11_cpu->hw_cpu, osc->event);
712 osc->event = 0;
713 osc->repeat = 0;
714 return 0;
717 static int
718 get_frequency (const char *s, double *f)
720 char *p;
722 *f = strtod (s, &p);
723 if (s == p)
724 return -1;
726 if (*p)
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;
735 return 0;
738 static SIM_RC
739 m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu,
740 int opt, char *arg, int is_command)
742 struct m68hc11_sim_cpu *m68hc11_cpu;
743 struct m68hc11cpu *controller;
744 double f;
745 char *p;
746 int i;
747 int title_printed = 0;
749 if (cpu == 0)
750 cpu = STATE_CPU (sd, 0);
751 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
753 controller = hw_data (m68hc11_cpu->hw_cpu);
754 switch (opt)
756 case OPTION_OSC_SET:
757 p = strchr (arg, ',');
758 if (p)
759 *p++ = 0;
761 if (p == 0)
762 sim_io_eprintf (sd, "No frequency specified\n");
763 else if (get_frequency (p, &f) < 0 || f < 1.0e-8)
764 sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p);
765 else if (m68hc11cpu_set_oscillator (sd, arg,
766 1.0 / (f * 2.0),
767 1.0 / (f * 2.0), LONG_MAX))
768 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
769 break;
771 case OPTION_OSC_CLEAR:
772 if (m68hc11cpu_clear_oscillator (sd, arg) != 0)
773 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
774 break;
776 case OPTION_OSC_INFO:
777 for (i = 0; i < controller->last_oscillator; i++)
779 int64_t t;
780 struct input_osc *osc;
782 osc = &controller->oscillators[i];
783 if (osc->event)
785 int cur_value;
786 int next_value;
787 char freq[32];
789 if (title_printed == 0)
791 title_printed = 1;
792 sim_io_printf (sd, " PORT Frequency Current"
793 " Next Transition time\n");
796 f = (double) (osc->on_time + osc->off_time);
797 f = (double) (m68hc11_cpu->cpu_frequency / 4) / f;
798 t = hw_event_remain_time (m68hc11_cpu->hw_cpu, osc->event);
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 PRINT_TIME | PRINT_CYCLE));
813 else
814 sim_io_printf (sd, " %4.4s %8.8s hz "
815 " %d %d %35.35s\n",
816 osc->name, freq,
817 cur_value, next_value,
818 cycle_to_string (cpu, t,
819 PRINT_TIME | PRINT_CYCLE));
822 break;
825 return SIM_RC_OK;
828 /* generic read/write */
830 static unsigned
831 m68hc11cpu_io_read_buffer (struct hw *me,
832 void *dest,
833 int space,
834 unsigned_word base,
835 unsigned nr_bytes)
837 SIM_DESC sd;
838 struct m68hc11cpu *controller = hw_data (me);
839 sim_cpu *cpu;
840 struct m68hc11_sim_cpu *m68hc11_cpu;
841 unsigned byte = 0;
842 int result;
844 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
846 sd = hw_system (me);
847 cpu = STATE_CPU (sd, 0);
848 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
850 if (base >= m68hc11_cpu->bank_start && base < m68hc11_cpu->bank_end)
852 address_word virt_addr = phys_to_virt (cpu, base);
853 if (virt_addr != base)
854 return sim_core_read_buffer (sd, cpu, space, dest,
855 virt_addr, nr_bytes);
858 /* Handle reads for the sub-devices. */
859 base -= controller->attach_address;
860 result = sim_core_read_buffer (sd, cpu,
861 io_map, dest, base, nr_bytes);
862 if (result > 0)
863 return result;
865 while (nr_bytes)
867 if (base >= controller->attach_size)
868 break;
870 memcpy (dest, &m68hc11_cpu->ios[base], 1);
871 dest = (char*) dest + 1;
872 base++;
873 byte++;
874 nr_bytes--;
876 return byte;
879 void
880 m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
881 unsigned addr, uint8_t val)
883 struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
884 uint8_t mask;
885 uint8_t delta;
886 int check_interrupts = 0;
887 int i;
889 switch (addr)
891 case M6811_PORTA:
892 if (m68hc11_cpu->ios[M6811_PACTL] & M6811_DDRA7)
893 mask = 3;
894 else
895 mask = 0x83;
897 val = val & mask;
898 val |= m68hc11_cpu->ios[M6811_PORTA] & ~mask;
899 delta = val ^ m68hc11_cpu->ios[M6811_PORTA];
900 m68hc11_cpu->ios[M6811_PORTA] = val;
901 if (delta & 0x80)
903 /* Pulse accumulator is enabled. */
904 if ((m68hc11_cpu->ios[M6811_PACTL] & M6811_PAEN)
905 && !(m68hc11_cpu->ios[M6811_PACTL] & M6811_PAMOD))
907 int inc;
909 /* Increment event counter according to rising/falling edge. */
910 if (m68hc11_cpu->ios[M6811_PACTL] & M6811_PEDGE)
911 inc = (val & 0x80) ? 1 : 0;
912 else
913 inc = (val & 0x80) ? 0 : 1;
915 m68hc11_cpu->ios[M6811_PACNT] += inc;
917 /* Event counter overflowed. */
918 if (inc && m68hc11_cpu->ios[M6811_PACNT] == 0)
920 m68hc11_cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
921 check_interrupts = 1;
926 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
927 for (i = 0; i < 3; i++)
929 mask = (1 << i);
931 if (delta & mask)
933 uint8_t edge;
934 int captured;
936 edge = m68hc11_cpu->ios[M6811_TCTL2];
937 edge = (edge >> (2 * i)) & 0x3;
938 switch (edge)
940 case 0:
941 captured = 0;
942 break;
943 case 1:
944 captured = (val & mask) != 0;
945 break;
946 case 2:
947 captured = (val & mask) == 0;
948 break;
949 default:
950 captured = 1;
951 break;
953 if (captured)
955 m68hc11_cpu->ios[M6811_TFLG1] |= (1 << i);
956 hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
957 check_interrupts = 1;
961 break;
963 case M6811_PORTC:
964 mask = m68hc11_cpu->ios[M6811_DDRC];
965 val = val & mask;
966 val |= m68hc11_cpu->ios[M6811_PORTC] & ~mask;
967 m68hc11_cpu->ios[M6811_PORTC] = val;
968 break;
970 case M6811_PORTD:
971 mask = m68hc11_cpu->ios[M6811_DDRD];
972 val = val & mask;
973 val |= m68hc11_cpu->ios[M6811_PORTD] & ~mask;
974 m68hc11_cpu->ios[M6811_PORTD] = val;
975 break;
977 default:
978 break;
981 if (check_interrupts)
982 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
985 static void
986 m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
987 unsigned_word addr, uint8_t val)
989 struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
991 switch (addr)
993 case M6811_PORTA:
994 hw_port_event (me, PORT_A, val);
995 break;
997 case M6811_PIOC:
998 break;
1000 case M6811_PORTC:
1001 hw_port_event (me, PORT_C, val);
1002 break;
1004 case M6811_PORTB:
1005 hw_port_event (me, PORT_B, val);
1006 break;
1008 case M6811_PORTCL:
1009 break;
1011 case M6811_DDRC:
1012 break;
1014 case M6811_PORTD:
1015 hw_port_event (me, PORT_D, val);
1016 break;
1018 case M6811_DDRD:
1019 break;
1021 case M6811_TMSK2:
1023 break;
1025 /* Change the RAM and I/O mapping. */
1026 case M6811_INIT:
1028 uint8_t old_bank = m68hc11_cpu->ios[M6811_INIT];
1030 m68hc11_cpu->ios[M6811_INIT] = val;
1032 /* Update IO mapping. Detach from the old address
1033 and attach to the new one. */
1034 if ((old_bank & 0x0F) != (val & 0x0F))
1036 struct m68hc11cpu *controller = hw_data (me);
1038 hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
1039 controller->attach_space,
1040 controller->attach_address,
1041 controller->attach_size,
1042 me);
1043 controller->attach_address = (val & 0x0F0) << 12;
1044 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
1045 controller->attach_space,
1046 controller->attach_address,
1047 controller->attach_size,
1048 me);
1050 if ((old_bank & 0xF0) != (val & 0xF0))
1054 return;
1057 /* Writing the config is similar to programing the eeprom.
1058 The config register value is the last byte of the EEPROM.
1059 This last byte is not mapped in memory (that's why we have
1060 to add '1' to 'end_addr'). */
1061 case M6811_CONFIG:
1063 return;
1067 /* COP reset. */
1068 case M6811_COPRST:
1069 if (val == 0xAA && m68hc11_cpu->ios[addr] == 0x55)
1071 val = 0;
1072 /* COP reset here. */
1074 break;
1076 default:
1077 break;
1080 m68hc11_cpu->ios[addr] = val;
1083 static unsigned
1084 m68hc11cpu_io_write_buffer (struct hw *me,
1085 const void *source,
1086 int space,
1087 unsigned_word base,
1088 unsigned nr_bytes)
1090 SIM_DESC sd;
1091 struct m68hc11cpu *controller = hw_data (me);
1092 unsigned byte;
1093 sim_cpu *cpu;
1094 struct m68hc11_sim_cpu *m68hc11_cpu;
1095 int result;
1097 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
1099 sd = hw_system (me);
1100 cpu = STATE_CPU (sd, 0);
1101 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
1103 if (base >= m68hc11_cpu->bank_start && base < m68hc11_cpu->bank_end)
1105 address_word virt_addr = phys_to_virt (cpu, base);
1106 if (virt_addr != base)
1107 return sim_core_write_buffer (sd, cpu, space, source,
1108 virt_addr, nr_bytes);
1110 base -= controller->attach_address;
1111 result = sim_core_write_buffer (sd, cpu,
1112 io_map, source, base, nr_bytes);
1113 if (result > 0)
1114 return result;
1116 byte = 0;
1117 while (nr_bytes)
1119 uint8_t val;
1120 if (base >= controller->attach_size)
1121 break;
1123 val = *((uint8_t*) source);
1124 m68hc11cpu_io_write (me, cpu, base, val);
1125 source = (char*) source + 1;
1126 base++;
1127 byte++;
1128 nr_bytes--;
1130 return byte;
1133 const struct hw_descriptor dv_m68hc11_descriptor[] = {
1134 { "m68hc11", m68hc11cpu_finish },
1135 { "m68hc12", m68hc11cpu_finish },
1136 { NULL },