[PATCH 37/57][Arm][OBJDUMP] Add framework for MVE instructions
[binutils-gdb.git] / sim / m68hc11 / dv-m68hc11.c
blob1a0f4a71a4ff0c0fb9fad0d07a84d50cba3bf1a4
1 /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2 Copyright (C) 1999-2019 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/>.
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>
29 /* DEVICE
31 m68hc11cpu - m68hc11 cpu virtual device
32 m68hc12cpu - m68hc12 cpu virtual device
34 DESCRIPTION
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.
41 PROPERTIES
43 reg <base> <size>
45 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
47 clock <hz>
49 Frequency of the quartz used by the processor.
51 mode [single | expanded | bootstrap | test]
53 Cpu operating mode (the MODA and MODB external pins).
56 PORTS
58 reset (input)
60 Reset the cpu and generates a cpu-reset event (used to reset
61 other devices).
63 nmi (input)
65 Deliver a non-maskable interrupt to the processor.
68 set-port-a (input)
69 set-port-c (input)
70 set-pord-d (input)
72 Allow an external device to set the value of port A, C or D inputs.
75 cpu-reset (output)
77 Event generated after the CPU performs a reset.
80 port-a (output)
81 port-b (output)
82 port-c (output)
83 port-d (output)
85 Event generated when the value of the output port A, B, C or D
86 changes.
89 BUGS
91 When delivering an interrupt, this code assumes that there is only
92 one processor (number 0).
96 enum
98 OPTION_OSC_SET = OPTION_START,
99 OPTION_OSC_CLEAR,
100 OPTION_OSC_INFO
103 static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
105 static const OPTION m68hc11_options[] =
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 },
117 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
120 struct input_osc
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;
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];
152 /* input port ID's */
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
171 static const struct hw_port_descriptor m68hc11cpu_ports[] = {
173 /* Interrupt inputs. */
174 { "reset", RESET_PORT, 0, input_port, },
175 { "nmi", NMI_PORT, 0, input_port, },
176 { "irq", IRQ_PORT, 0, input_port, },
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, },
182 { "cpu-write-port", CPU_WRITE_PORT, 0, input_port, },
184 /* Events generated for connection to other devices. */
185 { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
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, },
194 { "capture", CAPTURE, 0, output_port, },
196 { NULL, },
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;
203 /* Finish off the partially created hw device. Attach our local
204 callbacks. Wire up our port names etc. */
206 static hw_port_event_method m68hc11cpu_port_event;
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);
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)
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)));
226 if (space != io_map)
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);
238 else
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);
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)
261 sim_core_detach (hw_system (me), NULL, /*cpu*/
262 level, space, addr);
265 static void
266 m68hc11_delete (struct hw* me)
268 struct m68hc11cpu *controller;
270 controller = hw_data (me);
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);
280 static void
281 attach_m68hc11_regs (struct hw *me,
282 struct m68hc11cpu *controller)
284 SIM_DESC sd;
285 sim_cpu *cpu;
286 reg_property_spec reg;
287 const char *cpu_mode;
289 if (hw_find_property (me, "reg") == NULL)
290 hw_abort (me, "Missing \"reg\" property");
292 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
293 hw_abort (me, "\"reg\" property must contain one addr/size entry");
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);
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);
311 /* Get cpu frequency. */
312 sd = hw_system (me);
313 cpu = STATE_CPU (sd, 0);
314 if (hw_find_property (me, "clock") != NULL)
316 cpu->cpu_frequency = hw_find_integer_property (me, "clock");
318 else
320 cpu->cpu_frequency = 8*1000*1000;
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);
330 cpu_mode = "expanded";
331 if (hw_find_property (me, "mode") != NULL)
332 cpu_mode = hw_find_string_property (me, "mode");
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;
343 controller->last_oscillator = 0;
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);
351 /* port B is output only. */
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);
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);
371 /* Add oscillator commands. */
372 sim_add_option_table (sd, 0, m68hc11_options);
375 static void
376 m68hc11cpu_finish (struct hw *me)
378 struct m68hc11cpu *controller;
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
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;
400 attach_m68hc11_regs (me, controller);
403 /* An event arrives on an interrupt port. */
405 static void
406 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
410 static void
411 make_oscillator (struct m68hc11cpu *controller, const char *name,
412 uint16 addr, uint8 mask)
414 struct input_osc *osc;
416 if (controller->last_oscillator >= NR_OSC)
417 hw_abort (0, "Too many oscillators");
419 osc = &controller->oscillators[controller->last_oscillator];
420 osc->name = name;
421 osc->addr = addr;
422 osc->mask = mask;
423 controller->last_oscillator++;
426 /* Find the oscillator given the input port name. */
427 static struct input_osc *
428 find_oscillator (struct m68hc11cpu *controller, const char *name)
430 int i;
432 for (i = 0; i < controller->last_oscillator; i++)
433 if (strcasecmp (controller->oscillators[i].name, name) == 0)
434 return &controller->oscillators[i];
436 return 0;
439 static void
440 oscillator_handler (struct hw *me, void *data)
442 struct input_osc *osc = (struct input_osc*) data;
443 SIM_DESC sd;
444 sim_cpu *cpu;
445 signed64 dt;
446 uint8 val;
448 sd = hw_system (me);
449 cpu = STATE_CPU (sd, 0);
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);
457 /* Setup event to toggle the bit. */
458 if (osc->value)
459 dt = osc->on_time;
460 else
461 dt = osc->off_time;
463 if (dt && --osc->repeat >= 0)
465 sim_events *events = STATE_EVENTS (sd);
467 dt += events->nr_ticks_to_process;
468 osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc);
470 else
471 osc->event = 0;
474 static void
475 reset_oscillators (struct hw *me)
477 struct m68hc11cpu *controller = hw_data (me);
478 int i;
480 for (i = 0; i < controller->last_oscillator; i++)
482 if (controller->oscillators[i].event)
484 hw_event_queue_deschedule (me, controller->oscillators[i].event);
485 controller->oscillators[i].event = 0;
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)
497 struct m68hc11cpu *controller = hw_data (me);
498 SIM_DESC sd;
499 sim_cpu *cpu;
501 sd = hw_system (me);
502 cpu = STATE_CPU (sd, 0);
503 switch (my_port)
505 case RESET_PORT:
506 HW_TRACE ((me, "port-in reset"));
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;
519 case NMI_PORT:
520 controller->pending_nmi = 1;
521 HW_TRACE ((me, "port-in nmi"));
522 break;
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;
533 case SET_PORT_A:
534 m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
535 break;
537 case SET_PORT_C:
538 m68hc11cpu_set_port (me, cpu, M6811_PORTC, level);
539 break;
541 case SET_PORT_D:
542 m68hc11cpu_set_port (me, cpu, M6811_PORTD, level);
543 break;
545 case CPU_WRITE_PORT:
546 break;
548 default:
549 hw_abort (me, "bad switch");
550 break;
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);
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 }
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 }
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 }
589 static void
590 m68hc11_info (struct hw *me)
592 SIM_DESC sd;
593 uint16 base = 0;
594 sim_cpu *cpu;
595 struct m68hc11sio *controller;
596 uint8 val;
598 sd = hw_system (me);
599 cpu = STATE_CPU (sd, 0);
600 controller = hw_data (me);
602 base = cpu_get_io_base (cpu);
603 sim_io_printf (sd, "M68HC11:\n");
605 val = cpu->ios[M6811_HPRIO];
606 print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
607 switch (cpu->cpu_mode)
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;
623 val = cpu->ios[M6811_CONFIG];
624 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
625 sim_io_printf (sd, "\n");
627 val = cpu->ios[M6811_OPTION];
628 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
629 sim_io_printf (sd, "\n");
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));
638 cpu_info (sd, cpu);
639 interrupts_info (sd, &cpu->cpu_interrupts);
642 static int
643 m68hc11_ioctl (struct hw *me,
644 hw_ioctl_request request,
645 va_list ap)
647 m68hc11_info (me);
648 return 0;
651 /* Setup an oscillator on an input port.
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.
656 The oscillator frequency is therefore 1 / (ton + toff).
658 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
659 stops. */
661 m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
662 double ton, double toff, signed64 repeat)
664 sim_cpu *cpu;
665 struct input_osc *osc;
666 double f;
668 cpu = STATE_CPU (sd, 0);
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;
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;
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;
687 osc->repeat = repeat;
688 if (osc->event)
689 hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
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;
698 /* Clear the oscillator. */
700 m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port)
702 sim_cpu *cpu;
703 struct input_osc *osc;
705 cpu = STATE_CPU (sd, 0);
706 osc = find_oscillator (hw_data (cpu->hw_cpu), port);
707 if (osc == 0)
708 return -1;
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;
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 m68hc11cpu *controller;
743 double f;
744 char *p;
745 int i;
746 int title_printed = 0;
748 if (cpu == 0)
749 cpu = STATE_CPU (sd, 0);
751 controller = hw_data (cpu->hw_cpu);
752 switch (opt)
754 case OPTION_OSC_SET:
755 p = strchr (arg, ',');
756 if (p)
757 *p++ = 0;
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;
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;
774 case OPTION_OSC_INFO:
775 for (i = 0; i < controller->last_oscillator; i++)
777 signed64 t;
778 struct input_osc *osc;
780 osc = &controller->oscillators[i];
781 if (osc->event)
783 double f;
784 int cur_value;
785 int next_value;
786 char freq[32];
788 if (title_printed == 0)
790 title_printed = 1;
791 sim_io_printf (sd, " PORT Frequency Current"
792 " Next Transition time\n");
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);
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));
821 break;
824 return SIM_RC_OK;
827 /* generic read/write */
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)
836 SIM_DESC sd;
837 struct m68hc11cpu *controller = hw_data (me);
838 sim_cpu *cpu;
839 unsigned byte = 0;
840 int result;
842 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
844 sd = hw_system (me);
845 cpu = STATE_CPU (sd, 0);
847 if (base >= cpu->bank_start && base < cpu->bank_end)
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);
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;
862 while (nr_bytes)
864 if (base >= controller->attach_size)
865 break;
867 memcpy (dest, &cpu->ios[base], 1);
868 dest = (char*) dest + 1;
869 base++;
870 byte++;
871 nr_bytes--;
873 return byte;
876 void
877 m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
878 unsigned addr, uint8 val)
880 uint8 mask;
881 uint8 delta;
882 int check_interrupts = 0;
883 int i;
885 switch (addr)
887 case M6811_PORTA:
888 if (cpu->ios[M6811_PACTL] & M6811_DDRA7)
889 mask = 3;
890 else
891 mask = 0x83;
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)
899 /* Pulse accumulator is enabled. */
900 if ((cpu->ios[M6811_PACTL] & M6811_PAEN)
901 && !(cpu->ios[M6811_PACTL] & M6811_PAMOD))
903 int inc;
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;
911 cpu->ios[M6811_PACNT] += inc;
913 /* Event counter overflowed. */
914 if (inc && cpu->ios[M6811_PACNT] == 0)
916 cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
917 check_interrupts = 1;
922 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
923 for (i = 0; i < 3; i++)
925 uint8 mask = (1 << i);
927 if (delta & mask)
929 uint8 edge;
930 int captured;
932 edge = cpu->ios[M6811_TCTL2];
933 edge = (edge >> (2 * i)) & 0x3;
934 switch (edge)
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;
949 if (captured)
951 cpu->ios[M6811_TFLG1] |= (1 << i);
952 hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
953 check_interrupts = 1;
957 break;
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;
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;
973 default:
974 break;
977 if (check_interrupts)
978 interrupts_update_pending (&cpu->cpu_interrupts);
981 static void
982 m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
983 unsigned_word addr, uint8 val)
985 switch (addr)
987 case M6811_PORTA:
988 hw_port_event (me, PORT_A, val);
989 break;
991 case M6811_PIOC:
992 break;
994 case M6811_PORTC:
995 hw_port_event (me, PORT_C, val);
996 break;
998 case M6811_PORTB:
999 hw_port_event (me, PORT_B, val);
1000 break;
1002 case M6811_PORTCL:
1003 break;
1005 case M6811_DDRC:
1006 break;
1008 case M6811_PORTD:
1009 hw_port_event (me, PORT_D, val);
1010 break;
1012 case M6811_DDRD:
1013 break;
1015 case M6811_TMSK2:
1017 break;
1019 /* Change the RAM and I/O mapping. */
1020 case M6811_INIT:
1022 uint8 old_bank = cpu->ios[M6811_INIT];
1024 cpu->ios[M6811_INIT] = val;
1026 /* Update IO mapping. Detach from the old address
1027 and attach to the new one. */
1028 if ((old_bank & 0x0F) != (val & 0x0F))
1030 struct m68hc11cpu *controller = hw_data (me);
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);
1044 if ((old_bank & 0xF0) != (val & 0xF0))
1048 return;
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:
1057 return;
1061 /* COP reset. */
1062 case M6811_COPRST:
1063 if (val == 0xAA && cpu->ios[addr] == 0x55)
1065 val = 0;
1066 /* COP reset here. */
1068 break;
1070 default:
1071 break;
1074 cpu->ios[addr] = val;
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)
1084 SIM_DESC sd;
1085 struct m68hc11cpu *controller = hw_data (me);
1086 unsigned byte;
1087 sim_cpu *cpu;
1088 int result;
1090 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
1092 sd = hw_system (me);
1093 cpu = STATE_CPU (sd, 0);
1095 if (base >= cpu->bank_start && base < cpu->bank_end)
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);
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;
1108 byte = 0;
1109 while (nr_bytes)
1111 uint8 val;
1112 if (base >= controller->attach_size)
1113 break;
1115 val = *((uint8*) source);
1116 m68hc11cpu_io_write (me, cpu, base, val);
1117 source = (char*) source + 1;
1118 base++;
1119 byte++;
1120 nr_bytes--;
1122 return byte;
1125 const struct hw_descriptor dv_m68hc11_descriptor[] = {
1126 { "m68hc11", m68hc11cpu_finish },
1127 { "m68hc12", m68hc11cpu_finish },
1128 { NULL },