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