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