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