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