]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11.c
* m68hc11_sim.c (cpu_special): Handle call and rtc instructions.
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11.c
CommitLineData
b93775f5 1/* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
827ec39a 2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
e0709f50
AC
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"
827ec39a 24#include "sim-hw.h"
e0709f50 25#include "hw-main.h"
827ec39a
SC
26#include "sim-options.h"
27#include <limits.h>
e0709f50
AC
28
29/* DEVICE
30
31 m68hc11cpu - m68hc11 cpu virtual device
b93775f5 32 m68hc12cpu - m68hc12 cpu virtual device
e0709f50
AC
33
34 DESCRIPTION
35
b93775f5
SC
36 Implements the external m68hc11/68hc12 functionality. This includes
37 the delivery of of interrupts generated from other devices and the
e0709f50
AC
38 handling of device specific registers.
39
40
41 PROPERTIES
42
43 reg <base> <size>
44
b93775f5 45 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
e0709f50
AC
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
827ec39a
SC
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
e0709f50
AC
75 cpu-reset (output)
76
77 Event generated after the CPU performs a reset.
78
79
827ec39a
SC
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
e0709f50
AC
89 BUGS
90
91 When delivering an interrupt, this code assumes that there is only
92 one processor (number 0).
93
94 */
95
827ec39a
SC
96enum
97{
98 OPTION_OSC_SET = OPTION_START,
99 OPTION_OSC_CLEAR,
100 OPTION_OSC_INFO
101};
102
103static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
104
105static 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};
e0709f50 119
827ec39a
SC
120struct 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};
e0709f50 131
827ec39a
SC
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)
e0709f50
AC
137struct 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;
827ec39a
SC
146 int last_oscillator;
147 struct input_osc oscillators[NR_OSC];
e0709f50
AC
148};
149
150
151
152/* input port ID's */
153
154enum {
155 RESET_PORT,
156 NMI_PORT,
157 IRQ_PORT,
827ec39a
SC
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
e0709f50
AC
167};
168
169
170static 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
827ec39a
SC
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
e0709f50
AC
181 /* Events generated for connection to other devices. */
182 { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
183
827ec39a
SC
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
e0709f50
AC
193 { NULL, },
194};
195
196static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
197static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
198static 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
203static hw_port_event_method m68hc11cpu_port_event;
204
827ec39a
SC
205static void make_oscillator (struct m68hc11cpu *controller,
206 const char *id, uint16 addr, uint8 mask);
207static struct input_osc *find_oscillator (struct m68hc11cpu *controller,
208 const char *id);
209static void reset_oscillators (struct hw *me);
e0709f50
AC
210
211static void
212dv_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
250static void
251dv_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
639aa4f7
SC
262static void
263m68hc11_delete (struct hw* me)
264{
265 struct m68hc11cpu *controller;
266
267 controller = hw_data (me);
268
827ec39a 269 reset_oscillators (me);
639aa4f7
SC
270 hw_detach_address (me, M6811_IO_LEVEL,
271 controller->attach_space,
272 controller->attach_address,
273 controller->attach_size, me);
274}
275
e0709f50
AC
276
277static void
278attach_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
63348d04 301 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
302 controller->attach_space,
303 controller->attach_address,
304 controller->attach_size,
305 me);
639aa4f7 306 set_hw_delete (me, m68hc11_delete);
e0709f50
AC
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;
827ec39a
SC
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);
e0709f50
AC
363}
364
365static void
366m68hc11cpu_finish (struct hw *me)
367{
368 struct m68hc11cpu *controller;
369
370 controller = HW_ZALLOC (me, struct m68hc11cpu);
e0709f50
AC
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
e0709f50
AC
393/* An event arrives on an interrupt port. */
394
395static void
396deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
397{
398}
399
827ec39a
SC
400static void
401make_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. */
417static struct input_osc *
418find_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}
e0709f50 428
827ec39a
SC
429static void
430oscillator_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
464static void
465reset_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
e0709f50
AC
480static void
481m68hc11cpu_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);
827ec39a 504 reset_oscillators (me);
e0709f50
AC
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;
827ec39a
SC
522
523 case SET_PORT_A:
524 m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
525 break;
e0709f50 526
827ec39a
SC
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
e0709f50
AC
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
549io_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
557io_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
565io_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
576static void
577m68hc11_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);
86596dc8
SC
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 }
e0709f50
AC
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
629static int
630m68hc11_ioctl (struct hw *me,
631 hw_ioctl_request request,
632 va_list ap)
633{
634 m68hc11_info (me);
635 return 0;
636}
637
827ec39a
SC
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. */
647int
648m68hc11cpu_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. */
686int
687m68hc11cpu_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
704static int
705get_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
725static SIM_RC
726m68hc11_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
e0709f50
AC
812/* generic read/write */
813
814static unsigned
815m68hc11cpu_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
827ec39a 829 sd = hw_system (me);
e0709f50
AC
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 {
b93775f5 841 if (base >= controller->attach_size)
e0709f50
AC
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
827ec39a
SC
853void
854m68hc11cpu_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}
e0709f50
AC
957
958static void
959m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
960 unsigned_word addr, uint8 val)
961{
962 switch (addr)
963 {
964 case M6811_PORTA:
827ec39a 965 hw_port_event (me, PORT_A, val);
e0709f50
AC
966 break;
967
968 case M6811_PIOC:
969 break;
970
971 case M6811_PORTC:
827ec39a 972 hw_port_event (me, PORT_C, val);
e0709f50
AC
973 break;
974
975 case M6811_PORTB:
827ec39a 976 hw_port_event (me, PORT_B, val);
e0709f50
AC
977 break;
978
979 case M6811_PORTCL:
980 break;
981
982 case M6811_DDRC:
983 break;
984
985 case M6811_PORTD:
827ec39a 986 hw_port_event (me, PORT_D, val);
e0709f50
AC
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 & 0xF0) != (val & 0xF0))
1006 {
1007 struct m68hc11cpu *controller = hw_data (me);
1008
63348d04 1009 hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
1010 controller->attach_space,
1011 controller->attach_address,
1012 controller->attach_size,
1013 me);
1014 controller->attach_address = (val & 0x0F0) << 12;
63348d04 1015 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
1016 controller->attach_space,
1017 controller->attach_address,
1018 controller->attach_size,
1019 me);
1020 }
1021 if ((old_bank & 0x0F) != (val & 0x0F))
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
1054static unsigned
1055m68hc11cpu_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;
b93775f5 1081 if (base >= controller->attach_size)
e0709f50
AC
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
1094const struct hw_descriptor dv_m68hc11_descriptor[] = {
b93775f5
SC
1095 { "m68hc11", m68hc11cpu_finish },
1096 { "m68hc12", m68hc11cpu_finish },
e0709f50
AC
1097 { NULL },
1098};
1099