]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/m68hc11/dv-m68hc11.c
sim: m68hc11: move arch-specific settings to internal header
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11.c
1 /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2 Copyright (C) 1999-2022 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 /* This must come before any other includes. */
22 #include "defs.h"
23
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>
31
32 #include "m68hc11-sim.h"
33
34 /* DEVICE
35
36 m68hc11cpu - m68hc11 cpu virtual device
37 m68hc12cpu - m68hc12 cpu virtual device
38
39 DESCRIPTION
40
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.
44
45
46 PROPERTIES
47
48 reg <base> <size>
49
50 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
51
52 clock <hz>
53
54 Frequency of the quartz used by the processor.
55
56 mode [single | expanded | bootstrap | test]
57
58 Cpu operating mode (the MODA and MODB external pins).
59
60
61 PORTS
62
63 reset (input)
64
65 Reset the cpu and generates a cpu-reset event (used to reset
66 other devices).
67
68 nmi (input)
69
70 Deliver a non-maskable interrupt to the processor.
71
72
73 set-port-a (input)
74 set-port-c (input)
75 set-pord-d (input)
76
77 Allow an external device to set the value of port A, C or D inputs.
78
79
80 cpu-reset (output)
81
82 Event generated after the CPU performs a reset.
83
84
85 port-a (output)
86 port-b (output)
87 port-c (output)
88 port-d (output)
89
90 Event generated when the value of the output port A, B, C or D
91 changes.
92
93
94 BUGS
95
96 When delivering an interrupt, this code assumes that there is only
97 one processor (number 0).
98
99 */
100
101 enum
102 {
103 OPTION_OSC_SET = OPTION_START,
104 OPTION_OSC_CLEAR,
105 OPTION_OSC_INFO
106 };
107
108 static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
109
110 static const OPTION m68hc11_options[] =
111 {
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 },
121
122 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
123 };
124
125 struct input_osc
126 {
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;
135 };
136
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];
153 };
154
155
156
157 /* input port ID's */
158
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
173 };
174
175
176 static const struct hw_port_descriptor m68hc11cpu_ports[] = {
177
178 /* Interrupt inputs. */
179 { "reset", RESET_PORT, 0, input_port, },
180 { "nmi", NMI_PORT, 0, input_port, },
181 { "irq", IRQ_PORT, 0, input_port, },
182
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, },
186
187 { "cpu-write-port", CPU_WRITE_PORT, 0, input_port, },
188
189 /* Events generated for connection to other devices. */
190 { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
191
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, },
198
199 { "capture", CAPTURE, 0, output_port, },
200
201 { NULL, },
202 };
203
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;
207
208 /* Finish off the partially created hw device. Attach our local
209 callbacks. Wire up our port names etc. */
210
211 static hw_port_event_method m68hc11cpu_port_event;
212
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);
218
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)
226 {
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)));
230
231 if (space != io_map)
232 {
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);
242 }
243 else
244 {
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);
255 }
256 }
257
258 static void
259 m68hc11_delete (struct hw* me)
260 {
261 struct m68hc11cpu *controller;
262
263 controller = hw_data (me);
264
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);
270 }
271
272
273 static void
274 attach_m68hc11_regs (struct hw *me,
275 struct m68hc11cpu *controller)
276 {
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;
282
283 if (hw_find_property (me, "reg") == NULL)
284 hw_abort (me, "Missing \"reg\" property");
285
286 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
287 hw_abort (me, "\"reg\" property must contain one addr/size entry");
288
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);
297
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);
304
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)
310 {
311 m68hc11_cpu->cpu_frequency = hw_find_integer_property (me, "clock");
312 }
313 else
314 {
315 m68hc11_cpu->cpu_frequency = 8*1000*1000;
316 }
317
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);
324
325 cpu_mode = "expanded";
326 if (hw_find_property (me, "mode") != NULL)
327 cpu_mode = hw_find_string_property (me, "mode");
328
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;
337
338 controller->last_oscillator = 0;
339
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);
345
346 /* port B is output only. */
347
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);
357
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);
365
366 /* Add oscillator commands. */
367 sim_add_option_table (sd, 0, m68hc11_options);
368 }
369
370 static void
371 m68hc11cpu_finish (struct hw *me)
372 {
373 struct m68hc11cpu *controller;
374
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
387
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;
393
394 attach_m68hc11_regs (me, controller);
395 }
396
397 /* An event arrives on an interrupt port. */
398
399 static void
400 deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
401 {
402 }
403
404 static void
405 make_oscillator (struct m68hc11cpu *controller, const char *name,
406 uint16_t addr, uint8_t mask)
407 {
408 struct input_osc *osc;
409
410 if (controller->last_oscillator >= NR_OSC)
411 hw_abort (0, "Too many oscillators");
412
413 osc = &controller->oscillators[controller->last_oscillator];
414 osc->name = name;
415 osc->addr = addr;
416 osc->mask = mask;
417 controller->last_oscillator++;
418 }
419
420 /* Find the oscillator given the input port name. */
421 static struct input_osc *
422 find_oscillator (struct m68hc11cpu *controller, const char *name)
423 {
424 int i;
425
426 for (i = 0; i < controller->last_oscillator; i++)
427 if (strcasecmp (controller->oscillators[i].name, name) == 0)
428 return &controller->oscillators[i];
429
430 return 0;
431 }
432
433 static void
434 oscillator_handler (struct hw *me, void *data)
435 {
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;
442
443 sd = hw_system (me);
444 cpu = STATE_CPU (sd, 0);
445 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
446
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);
452
453 /* Setup event to toggle the bit. */
454 if (osc->value)
455 dt = osc->on_time;
456 else
457 dt = osc->off_time;
458
459 if (dt && --osc->repeat >= 0)
460 {
461 sim_events *events = STATE_EVENTS (sd);
462
463 dt += events->nr_ticks_to_process;
464 osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc);
465 }
466 else
467 osc->event = 0;
468 }
469
470 static void
471 reset_oscillators (struct hw *me)
472 {
473 struct m68hc11cpu *controller = hw_data (me);
474 int i;
475
476 for (i = 0; i < controller->last_oscillator; i++)
477 {
478 if (controller->oscillators[i].event)
479 {
480 hw_event_queue_deschedule (me, controller->oscillators[i].event);
481 controller->oscillators[i].event = 0;
482 }
483 }
484 }
485
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)
492 {
493 struct m68hc11cpu *controller = hw_data (me);
494 SIM_DESC sd;
495 sim_cpu *cpu;
496
497 sd = hw_system (me);
498 cpu = STATE_CPU (sd, 0);
499 switch (my_port)
500 {
501 case RESET_PORT:
502 HW_TRACE ((me, "port-in reset"));
503
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;
514
515 case NMI_PORT:
516 controller->pending_nmi = 1;
517 HW_TRACE ((me, "port-in nmi"));
518 break;
519
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;
528
529 case SET_PORT_A:
530 m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
531 break;
532
533 case SET_PORT_C:
534 m68hc11cpu_set_port (me, cpu, M6811_PORTC, level);
535 break;
536
537 case SET_PORT_D:
538 m68hc11cpu_set_port (me, cpu, M6811_PORTD, level);
539 break;
540
541 case CPU_WRITE_PORT:
542 break;
543
544 default:
545 hw_abort (me, "bad switch");
546 break;
547 }
548
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);
555 }
556
557
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 }
564 };
565
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 }
572 };
573
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 }
583 };
584
585 static void
586 m68hc11_info (struct hw *me)
587 {
588 SIM_DESC sd;
589 uint16_t base = 0;
590 sim_cpu *cpu;
591 struct m68hc11_sim_cpu *m68hc11_cpu;
592 struct m68hc11sio *controller;
593 uint8_t val;
594
595 sd = hw_system (me);
596 cpu = STATE_CPU (sd, 0);
597 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
598 controller = hw_data (me);
599
600 base = cpu_get_io_base (cpu);
601 sim_io_printf (sd, "M68HC11:\n");
602
603 val = m68hc11_cpu->ios[M6811_HPRIO];
604 print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
605 switch (m68hc11_cpu->cpu_mode)
606 {
607 case M6811_MDA | M6811_SMOD:
608 sim_io_printf (sd, "[test]\n");
609 break;
610 case M6811_SMOD:
611 sim_io_printf (sd, "[bootstrap]\n");
612 break;
613 case M6811_MDA:
614 sim_io_printf (sd, "[extended]\n");
615 break;
616 default:
617 sim_io_printf (sd, "[single]\n");
618 break;
619 }
620
621 val = m68hc11_cpu->ios[M6811_CONFIG];
622 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
623 sim_io_printf (sd, "\n");
624
625 val = m68hc11_cpu->ios[M6811_OPTION];
626 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
627 sim_io_printf (sd, "\n");
628
629 val = m68hc11_cpu->ios[M6811_INIT];
630 print_io_byte (sd, "INIT ", 0, val, base + M6811_INIT);
631 sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
632 (((uint16_t) (val & 0xF0)) << 8),
633 (((uint16_t) (val & 0x0F)) << 12));
634
635
636 cpu_info (sd, cpu);
637 interrupts_info (sd, &m68hc11_cpu->cpu_interrupts);
638 }
639
640 static int
641 m68hc11_ioctl (struct hw *me,
642 hw_ioctl_request request,
643 va_list ap)
644 {
645 m68hc11_info (me);
646 return 0;
647 }
648
649 /* Setup an oscillator on an input port.
650
651 TON represents the time in seconds that the input port should be set to 1.
652 TOFF is the time in seconds for the input port to be set to 0.
653
654 The oscillator frequency is therefore 1 / (ton + toff).
655
656 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
657 stops. */
658 int
659 m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
660 double ton, double toff, int64_t repeat)
661 {
662 sim_cpu *cpu;
663 struct m68hc11_sim_cpu *m68hc11_cpu;
664 struct input_osc *osc;
665 double f;
666
667 cpu = STATE_CPU (sd, 0);
668 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
669
670 /* Find oscillator that corresponds to the input port. */
671 osc = find_oscillator (hw_data (m68hc11_cpu->hw_cpu), port);
672 if (osc == 0)
673 return -1;
674
675 /* Compute the ON time in cpu cycles. */
676 f = (double) (m68hc11_cpu->cpu_frequency) * ton;
677 osc->on_time = (int64_t) (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) (m68hc11_cpu->cpu_frequency) * toff;
683 osc->off_time = (int64_t) (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 (m68hc11_cpu->hw_cpu, osc->event);
690
691 osc->event = hw_event_queue_schedule (m68hc11_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 m68hc11_sim_cpu *m68hc11_cpu;
704 struct input_osc *osc;
705
706 cpu = STATE_CPU (sd, 0);
707 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
708 osc = find_oscillator (hw_data (m68hc11_cpu->hw_cpu), port);
709 if (osc == 0)
710 return -1;
711
712 if (osc->event)
713 hw_event_queue_deschedule (m68hc11_cpu->hw_cpu, osc->event);
714 osc->event = 0;
715 osc->repeat = 0;
716 return 0;
717 }
718
719 static int
720 get_frequency (const char *s, double *f)
721 {
722 char *p;
723
724 *f = strtod (s, &p);
725 if (s == p)
726 return -1;
727
728 if (*p)
729 {
730 if (strcasecmp (p, "khz") == 0)
731 *f = *f * 1000.0;
732 else if (strcasecmp (p, "mhz") == 0)
733 *f = *f * 1000000.0;
734 else if (strcasecmp (p, "hz") != 0)
735 return -1;
736 }
737 return 0;
738 }
739
740 static SIM_RC
741 m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu,
742 int opt, char *arg, int is_command)
743 {
744 struct m68hc11_sim_cpu *m68hc11_cpu;
745 struct m68hc11cpu *controller;
746 double f;
747 char *p;
748 int i;
749 int title_printed = 0;
750
751 if (cpu == 0)
752 cpu = STATE_CPU (sd, 0);
753 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
754
755 controller = hw_data (m68hc11_cpu->hw_cpu);
756 switch (opt)
757 {
758 case OPTION_OSC_SET:
759 p = strchr (arg, ',');
760 if (p)
761 *p++ = 0;
762
763 if (p == 0)
764 sim_io_eprintf (sd, "No frequency specified\n");
765 else if (get_frequency (p, &f) < 0 || f < 1.0e-8)
766 sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p);
767 else if (m68hc11cpu_set_oscillator (sd, arg,
768 1.0 / (f * 2.0),
769 1.0 / (f * 2.0), LONG_MAX))
770 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
771 break;
772
773 case OPTION_OSC_CLEAR:
774 if (m68hc11cpu_clear_oscillator (sd, arg) != 0)
775 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
776 break;
777
778 case OPTION_OSC_INFO:
779 for (i = 0; i < controller->last_oscillator; i++)
780 {
781 int64_t t;
782 struct input_osc *osc;
783
784 osc = &controller->oscillators[i];
785 if (osc->event)
786 {
787 double f;
788 int cur_value;
789 int next_value;
790 char freq[32];
791
792 if (title_printed == 0)
793 {
794 title_printed = 1;
795 sim_io_printf (sd, " PORT Frequency Current"
796 " Next Transition time\n");
797 }
798
799 f = (double) (osc->on_time + osc->off_time);
800 f = (double) (m68hc11_cpu->cpu_frequency / 4) / f;
801 t = hw_event_remain_time (m68hc11_cpu->hw_cpu, osc->event);
802
803 if (f > 10000.0)
804 sprintf (freq, "%6.2f", f / 1000.0);
805 else
806 sprintf (freq, "%6.2f", f);
807 cur_value = osc->value ? 1 : 0;
808 next_value = osc->value ? 0 : 1;
809 if (f > 10000.0)
810 sim_io_printf (sd, " %4.4s %8.8s khz"
811 " %d %d %35.35s\n",
812 osc->name, freq,
813 cur_value, next_value,
814 cycle_to_string (cpu, t,
815 PRINT_TIME | PRINT_CYCLE));
816 else
817 sim_io_printf (sd, " %4.4s %8.8s hz "
818 " %d %d %35.35s\n",
819 osc->name, freq,
820 cur_value, next_value,
821 cycle_to_string (cpu, t,
822 PRINT_TIME | PRINT_CYCLE));
823 }
824 }
825 break;
826 }
827
828 return SIM_RC_OK;
829 }
830
831 /* generic read/write */
832
833 static unsigned
834 m68hc11cpu_io_read_buffer (struct hw *me,
835 void *dest,
836 int space,
837 unsigned_word base,
838 unsigned nr_bytes)
839 {
840 SIM_DESC sd;
841 struct m68hc11cpu *controller = hw_data (me);
842 sim_cpu *cpu;
843 struct m68hc11_sim_cpu *m68hc11_cpu;
844 unsigned byte = 0;
845 int result;
846
847 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
848
849 sd = hw_system (me);
850 cpu = STATE_CPU (sd, 0);
851 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
852
853 if (base >= m68hc11_cpu->bank_start && base < m68hc11_cpu->bank_end)
854 {
855 address_word virt_addr = phys_to_virt (cpu, base);
856 if (virt_addr != base)
857 return sim_core_read_buffer (sd, cpu, space, dest,
858 virt_addr, nr_bytes);
859 }
860
861 /* Handle reads for the sub-devices. */
862 base -= controller->attach_address;
863 result = sim_core_read_buffer (sd, cpu,
864 io_map, dest, base, nr_bytes);
865 if (result > 0)
866 return result;
867
868 while (nr_bytes)
869 {
870 if (base >= controller->attach_size)
871 break;
872
873 memcpy (dest, &m68hc11_cpu->ios[base], 1);
874 dest = (char*) dest + 1;
875 base++;
876 byte++;
877 nr_bytes--;
878 }
879 return byte;
880 }
881
882 void
883 m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
884 unsigned addr, uint8_t val)
885 {
886 struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
887 uint8_t mask;
888 uint8_t delta;
889 int check_interrupts = 0;
890 int i;
891
892 switch (addr)
893 {
894 case M6811_PORTA:
895 if (m68hc11_cpu->ios[M6811_PACTL] & M6811_DDRA7)
896 mask = 3;
897 else
898 mask = 0x83;
899
900 val = val & mask;
901 val |= m68hc11_cpu->ios[M6811_PORTA] & ~mask;
902 delta = val ^ m68hc11_cpu->ios[M6811_PORTA];
903 m68hc11_cpu->ios[M6811_PORTA] = val;
904 if (delta & 0x80)
905 {
906 /* Pulse accumulator is enabled. */
907 if ((m68hc11_cpu->ios[M6811_PACTL] & M6811_PAEN)
908 && !(m68hc11_cpu->ios[M6811_PACTL] & M6811_PAMOD))
909 {
910 int inc;
911
912 /* Increment event counter according to rising/falling edge. */
913 if (m68hc11_cpu->ios[M6811_PACTL] & M6811_PEDGE)
914 inc = (val & 0x80) ? 1 : 0;
915 else
916 inc = (val & 0x80) ? 0 : 1;
917
918 m68hc11_cpu->ios[M6811_PACNT] += inc;
919
920 /* Event counter overflowed. */
921 if (inc && m68hc11_cpu->ios[M6811_PACNT] == 0)
922 {
923 m68hc11_cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
924 check_interrupts = 1;
925 }
926 }
927 }
928
929 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
930 for (i = 0; i < 3; i++)
931 {
932 uint8_t mask = (1 << i);
933
934 if (delta & mask)
935 {
936 uint8_t edge;
937 int captured;
938
939 edge = m68hc11_cpu->ios[M6811_TCTL2];
940 edge = (edge >> (2 * i)) & 0x3;
941 switch (edge)
942 {
943 case 0:
944 captured = 0;
945 break;
946 case 1:
947 captured = (val & mask) != 0;
948 break;
949 case 2:
950 captured = (val & mask) == 0;
951 break;
952 default:
953 captured = 1;
954 break;
955 }
956 if (captured)
957 {
958 m68hc11_cpu->ios[M6811_TFLG1] |= (1 << i);
959 hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
960 check_interrupts = 1;
961 }
962 }
963 }
964 break;
965
966 case M6811_PORTC:
967 mask = m68hc11_cpu->ios[M6811_DDRC];
968 val = val & mask;
969 val |= m68hc11_cpu->ios[M6811_PORTC] & ~mask;
970 m68hc11_cpu->ios[M6811_PORTC] = val;
971 break;
972
973 case M6811_PORTD:
974 mask = m68hc11_cpu->ios[M6811_DDRD];
975 val = val & mask;
976 val |= m68hc11_cpu->ios[M6811_PORTD] & ~mask;
977 m68hc11_cpu->ios[M6811_PORTD] = val;
978 break;
979
980 default:
981 break;
982 }
983
984 if (check_interrupts)
985 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
986 }
987
988 static void
989 m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
990 unsigned_word addr, uint8_t val)
991 {
992 struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
993
994 switch (addr)
995 {
996 case M6811_PORTA:
997 hw_port_event (me, PORT_A, val);
998 break;
999
1000 case M6811_PIOC:
1001 break;
1002
1003 case M6811_PORTC:
1004 hw_port_event (me, PORT_C, val);
1005 break;
1006
1007 case M6811_PORTB:
1008 hw_port_event (me, PORT_B, val);
1009 break;
1010
1011 case M6811_PORTCL:
1012 break;
1013
1014 case M6811_DDRC:
1015 break;
1016
1017 case M6811_PORTD:
1018 hw_port_event (me, PORT_D, val);
1019 break;
1020
1021 case M6811_DDRD:
1022 break;
1023
1024 case M6811_TMSK2:
1025
1026 break;
1027
1028 /* Change the RAM and I/O mapping. */
1029 case M6811_INIT:
1030 {
1031 uint8_t old_bank = m68hc11_cpu->ios[M6811_INIT];
1032
1033 m68hc11_cpu->ios[M6811_INIT] = val;
1034
1035 /* Update IO mapping. Detach from the old address
1036 and attach to the new one. */
1037 if ((old_bank & 0x0F) != (val & 0x0F))
1038 {
1039 struct m68hc11cpu *controller = hw_data (me);
1040
1041 hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
1042 controller->attach_space,
1043 controller->attach_address,
1044 controller->attach_size,
1045 me);
1046 controller->attach_address = (val & 0x0F0) << 12;
1047 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
1048 controller->attach_space,
1049 controller->attach_address,
1050 controller->attach_size,
1051 me);
1052 }
1053 if ((old_bank & 0xF0) != (val & 0xF0))
1054 {
1055 ;
1056 }
1057 return;
1058 }
1059
1060 /* Writing the config is similar to programing the eeprom.
1061 The config register value is the last byte of the EEPROM.
1062 This last byte is not mapped in memory (that's why we have
1063 to add '1' to 'end_addr'). */
1064 case M6811_CONFIG:
1065 {
1066 return;
1067 }
1068
1069
1070 /* COP reset. */
1071 case M6811_COPRST:
1072 if (val == 0xAA && m68hc11_cpu->ios[addr] == 0x55)
1073 {
1074 val = 0;
1075 /* COP reset here. */
1076 }
1077 break;
1078
1079 default:
1080 break;
1081
1082 }
1083 m68hc11_cpu->ios[addr] = val;
1084 }
1085
1086 static unsigned
1087 m68hc11cpu_io_write_buffer (struct hw *me,
1088 const void *source,
1089 int space,
1090 unsigned_word base,
1091 unsigned nr_bytes)
1092 {
1093 SIM_DESC sd;
1094 struct m68hc11cpu *controller = hw_data (me);
1095 unsigned byte;
1096 sim_cpu *cpu;
1097 struct m68hc11_sim_cpu *m68hc11_cpu;
1098 int result;
1099
1100 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
1101
1102 sd = hw_system (me);
1103 cpu = STATE_CPU (sd, 0);
1104 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
1105
1106 if (base >= m68hc11_cpu->bank_start && base < m68hc11_cpu->bank_end)
1107 {
1108 address_word virt_addr = phys_to_virt (cpu, base);
1109 if (virt_addr != base)
1110 return sim_core_write_buffer (sd, cpu, space, source,
1111 virt_addr, nr_bytes);
1112 }
1113 base -= controller->attach_address;
1114 result = sim_core_write_buffer (sd, cpu,
1115 io_map, source, base, nr_bytes);
1116 if (result > 0)
1117 return result;
1118
1119 byte = 0;
1120 while (nr_bytes)
1121 {
1122 uint8_t val;
1123 if (base >= controller->attach_size)
1124 break;
1125
1126 val = *((uint8_t*) source);
1127 m68hc11cpu_io_write (me, cpu, base, val);
1128 source = (char*) source + 1;
1129 base++;
1130 byte++;
1131 nr_bytes--;
1132 }
1133 return byte;
1134 }
1135
1136 const struct hw_descriptor dv_m68hc11_descriptor[] = {
1137 { "m68hc11", m68hc11cpu_finish },
1138 { "m68hc12", m68hc11cpu_finish },
1139 { NULL },
1140 };
1141