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