]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11.c
* interp.c (sim_hw_configure): Save the HW cpu pointer in the
[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);
594 sim_io_printf (sd, "\n");
595
596 val = cpu->ios[M6811_CONFIG];
597 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
598 sim_io_printf (sd, "\n");
599
600 val = cpu->ios[M6811_OPTION];
601 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
602 sim_io_printf (sd, "\n");
603
604 val = cpu->ios[M6811_INIT];
605 print_io_byte (sd, "INIT ", 0, val, base + M6811_INIT);
606 sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
607 (((uint16) (val & 0xF0)) << 8),
608 (((uint16) (val & 0x0F)) << 12));
609
610
611 cpu_info (sd, cpu);
612 interrupts_info (sd, &cpu->cpu_interrupts);
613}
614
615static int
616m68hc11_ioctl (struct hw *me,
617 hw_ioctl_request request,
618 va_list ap)
619{
620 m68hc11_info (me);
621 return 0;
622}
623
827ec39a
SC
624/* Setup an oscillator on an input port.
625
626 TON represents the time in seconds that the input port should be set to 1.
627 TOFF is the time in seconds for the input port to be set to 0.
628
629 The oscillator frequency is therefore 1 / (ton + toff).
630
631 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
632 stops. */
633int
634m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
635 double ton, double toff, signed64 repeat)
636{
637 sim_cpu *cpu;
638 struct input_osc *osc;
639 double f;
640
641 cpu = STATE_CPU (sd, 0);
642
643 /* Find oscillator that corresponds to the input port. */
644 osc = find_oscillator (hw_data (cpu->hw_cpu), port);
645 if (osc == 0)
646 return -1;
647
648 /* Compute the ON time in cpu cycles. */
649 f = (double) (cpu->cpu_frequency) * ton;
650 osc->on_time = (signed64) (f / 4.0);
651 if (osc->on_time < 1)
652 osc->on_time = 1;
653
654 /* Compute the OFF time in cpu cycles. */
655 f = (double) (cpu->cpu_frequency) * toff;
656 osc->off_time = (signed64) (f / 4.0);
657 if (osc->off_time < 1)
658 osc->off_time = 1;
659
660 osc->repeat = repeat;
661 if (osc->event)
662 hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
663
664 osc->event = hw_event_queue_schedule (cpu->hw_cpu,
665 osc->value ? osc->on_time
666 : osc->off_time,
667 oscillator_handler, osc);
668 return 0;
669}
670
671/* Clear the oscillator. */
672int
673m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port)
674{
675 sim_cpu *cpu;
676 struct input_osc *osc;
677
678 cpu = STATE_CPU (sd, 0);
679 osc = find_oscillator (hw_data (cpu->hw_cpu), port);
680 if (osc == 0)
681 return -1;
682
683 if (osc->event)
684 hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
685 osc->event = 0;
686 osc->repeat = 0;
687 return 0;
688}
689
690static int
691get_frequency (const char *s, double *f)
692{
693 char *p;
694
695 *f = strtod (s, &p);
696 if (s == p)
697 return -1;
698
699 if (*p)
700 {
701 if (strcasecmp (p, "khz") == 0)
702 *f = *f * 1000.0;
703 else if (strcasecmp (p, "mhz") == 0)
704 *f = *f * 1000000.0;
705 else if (strcasecmp (p, "hz") != 0)
706 return -1;
707 }
708 return 0;
709}
710
711static SIM_RC
712m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu,
713 int opt, char *arg, int is_command)
714{
715 struct m68hc11cpu *controller;
716 double f;
717 char *p;
718 int i;
719 int title_printed = 0;
720
721 if (cpu == 0)
722 cpu = STATE_CPU (sd, 0);
723
724 controller = hw_data (cpu->hw_cpu);
725 switch (opt)
726 {
727 case OPTION_OSC_SET:
728 p = strchr (arg, ',');
729 if (p)
730 *p++ = 0;
731
732 if (p == 0)
733 sim_io_eprintf (sd, "No frequency specified\n");
734 else if (get_frequency (p, &f) < 0 || f < 1.0e-8)
735 sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p);
736 else if (m68hc11cpu_set_oscillator (sd, arg,
737 1.0 / (f * 2.0),
738 1.0 / (f * 2.0), LONG_MAX))
739 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
740 break;
741
742 case OPTION_OSC_CLEAR:
743 if (m68hc11cpu_clear_oscillator (sd, arg) != 0)
744 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
745 break;
746
747 case OPTION_OSC_INFO:
748 for (i = 0; i < controller->last_oscillator; i++)
749 {
750 signed64 t;
751 struct input_osc *osc;
752
753 osc = &controller->oscillators[i];
754 if (osc->event)
755 {
756 double f;
757 int cur_value;
758 int next_value;
759 char freq[32];
760
761 if (title_printed == 0)
762 {
763 title_printed = 1;
764 sim_io_printf (sd, " PORT Frequency Current"
765 " Next Transition time\n");
766 }
767
768 f = (double) (osc->on_time + osc->off_time);
769 f = (double) (cpu->cpu_frequency / 4) / f;
770 t = hw_event_remain_time (cpu->hw_cpu, osc->event);
771
772 if (f > 10000.0)
773 sprintf (freq, "%6.2f", f / 1000.0);
774 else
775 sprintf (freq, "%6.2f", f);
776 cur_value = osc->value ? 1 : 0;
777 next_value = osc->value ? 0 : 1;
778 if (f > 10000.0)
779 sim_io_printf (sd, " %4.4s %8.8s khz"
780 " %d %d %35.35s\n",
781 osc->name, freq,
782 cur_value, next_value,
783 cycle_to_string (cpu, t));
784 else
785 sim_io_printf (sd, " %4.4s %8.8s hz "
786 " %d %d %35.35s\n",
787 osc->name, freq,
788 cur_value, next_value,
789 cycle_to_string (cpu, t));
790 }
791 }
792 break;
793 }
794
795 return SIM_RC_OK;
796}
797
e0709f50
AC
798/* generic read/write */
799
800static unsigned
801m68hc11cpu_io_read_buffer (struct hw *me,
802 void *dest,
803 int space,
804 unsigned_word base,
805 unsigned nr_bytes)
806{
807 SIM_DESC sd;
808 struct m68hc11cpu *controller = hw_data (me);
809 sim_cpu *cpu;
810 unsigned byte = 0;
811 int result;
812
813 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
814
827ec39a 815 sd = hw_system (me);
e0709f50
AC
816 cpu = STATE_CPU (sd, 0);
817
818 /* Handle reads for the sub-devices. */
819 base -= controller->attach_address;
820 result = sim_core_read_buffer (sd, cpu,
821 io_map, dest, base, nr_bytes);
822 if (result > 0)
823 return result;
824
825 while (nr_bytes)
826 {
b93775f5 827 if (base >= controller->attach_size)
e0709f50
AC
828 break;
829
830 memcpy (dest, &cpu->ios[base], 1);
831 dest++;
832 base++;
833 byte++;
834 nr_bytes--;
835 }
836 return byte;
837}
838
827ec39a
SC
839void
840m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
841 unsigned addr, uint8 val)
842{
843 uint8 mask;
844 uint8 delta;
845 int check_interrupts = 0;
846 int i;
847
848 switch (addr)
849 {
850 case M6811_PORTA:
851 if (cpu->ios[M6811_PACTL] & M6811_DDRA7)
852 mask = 3;
853 else
854 mask = 0x83;
855
856 val = val & mask;
857 val |= cpu->ios[M6811_PORTA] & ~mask;
858 delta = val ^ cpu->ios[M6811_PORTA];
859 cpu->ios[M6811_PORTA] = val;
860 if (delta & 0x80)
861 {
862 /* Pulse accumulator is enabled. */
863 if ((cpu->ios[M6811_PACTL] & M6811_PAEN)
864 && !(cpu->ios[M6811_PACTL] & M6811_PAMOD))
865 {
866 int inc;
867
868 /* Increment event counter according to rising/falling edge. */
869 if (cpu->ios[M6811_PACTL] & M6811_PEDGE)
870 inc = (val & 0x80) ? 1 : 0;
871 else
872 inc = (val & 0x80) ? 0 : 1;
873
874 cpu->ios[M6811_PACNT] += inc;
875
876 /* Event counter overflowed. */
877 if (inc && cpu->ios[M6811_PACNT] == 0)
878 {
879 cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
880 check_interrupts = 1;
881 }
882 }
883 }
884
885 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
886 for (i = 0; i < 3; i++)
887 {
888 uint8 mask = (1 << i);
889
890 if (delta & mask)
891 {
892 uint8 edge;
893 int captured;
894
895 edge = cpu->ios[M6811_TCTL2];
896 edge = (edge >> (2 * i)) & 0x3;
897 switch (edge)
898 {
899 case 0:
900 captured = 0;
901 break;
902 case 1:
903 captured = (val & mask) != 0;
904 break;
905 case 2:
906 captured = (val & mask) == 0;
907 break;
908 default:
909 captured = 1;
910 break;
911 }
912 if (captured)
913 {
914 cpu->ios[M6811_TFLG1] |= (1 << i);
915 hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
916 check_interrupts = 1;
917 }
918 }
919 }
920 break;
921
922 case M6811_PORTC:
923 mask = cpu->ios[M6811_DDRC];
924 val = val & mask;
925 val |= cpu->ios[M6811_PORTC] & ~mask;
926 cpu->ios[M6811_PORTC] = val;
927 break;
928
929 case M6811_PORTD:
930 mask = cpu->ios[M6811_DDRD];
931 val = val & mask;
932 val |= cpu->ios[M6811_PORTD] & ~mask;
933 cpu->ios[M6811_PORTD] = val;
934 break;
935
936 default:
937 break;
938 }
939
940 if (check_interrupts)
941 interrupts_update_pending (&cpu->cpu_interrupts);
942}
e0709f50
AC
943
944static void
945m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
946 unsigned_word addr, uint8 val)
947{
948 switch (addr)
949 {
950 case M6811_PORTA:
827ec39a 951 hw_port_event (me, PORT_A, val);
e0709f50
AC
952 break;
953
954 case M6811_PIOC:
955 break;
956
957 case M6811_PORTC:
827ec39a 958 hw_port_event (me, PORT_C, val);
e0709f50
AC
959 break;
960
961 case M6811_PORTB:
827ec39a 962 hw_port_event (me, PORT_B, val);
e0709f50
AC
963 break;
964
965 case M6811_PORTCL:
966 break;
967
968 case M6811_DDRC:
969 break;
970
971 case M6811_PORTD:
827ec39a 972 hw_port_event (me, PORT_D, val);
e0709f50
AC
973 break;
974
975 case M6811_DDRD:
976 break;
977
978 case M6811_TMSK2:
979
980 break;
981
982 /* Change the RAM and I/O mapping. */
983 case M6811_INIT:
984 {
985 uint8 old_bank = cpu->ios[M6811_INIT];
986
987 cpu->ios[M6811_INIT] = val;
988
989 /* Update IO mapping. Detach from the old address
990 and attach to the new one. */
991 if ((old_bank & 0xF0) != (val & 0xF0))
992 {
993 struct m68hc11cpu *controller = hw_data (me);
994
63348d04 995 hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
996 controller->attach_space,
997 controller->attach_address,
998 controller->attach_size,
999 me);
1000 controller->attach_address = (val & 0x0F0) << 12;
63348d04 1001 hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
e0709f50
AC
1002 controller->attach_space,
1003 controller->attach_address,
1004 controller->attach_size,
1005 me);
1006 }
1007 if ((old_bank & 0x0F) != (val & 0x0F))
1008 {
1009 ;
1010 }
1011 return;
1012 }
1013
1014 /* Writing the config is similar to programing the eeprom.
1015 The config register value is the last byte of the EEPROM.
1016 This last byte is not mapped in memory (that's why we have
1017 to add '1' to 'end_addr'). */
1018 case M6811_CONFIG:
1019 {
1020 return;
1021 }
1022
1023
1024 /* COP reset. */
1025 case M6811_COPRST:
1026 if (val == 0xAA && cpu->ios[addr] == 0x55)
1027 {
1028 val = 0;
1029 /* COP reset here. */
1030 }
1031 break;
1032
1033 default:
1034 break;
1035
1036 }
1037 cpu->ios[addr] = val;
1038}
1039
1040static unsigned
1041m68hc11cpu_io_write_buffer (struct hw *me,
1042 const void *source,
1043 int space,
1044 unsigned_word base,
1045 unsigned nr_bytes)
1046{
1047 SIM_DESC sd;
1048 struct m68hc11cpu *controller = hw_data (me);
1049 unsigned byte;
1050 sim_cpu *cpu;
1051 int result;
1052
1053 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
1054
1055 sd = hw_system (me);
1056 cpu = STATE_CPU (sd, 0);
1057 base -= controller->attach_address;
1058 result = sim_core_write_buffer (sd, cpu,
1059 io_map, source, base, nr_bytes);
1060 if (result > 0)
1061 return result;
1062
1063 byte = 0;
1064 while (nr_bytes)
1065 {
1066 uint8 val;
b93775f5 1067 if (base >= controller->attach_size)
e0709f50
AC
1068 break;
1069
1070 val = *((uint8*) source);
1071 m68hc11cpu_io_write (me, cpu, base, val);
1072 source++;
1073 base++;
1074 byte++;
1075 nr_bytes--;
1076 }
1077 return byte;
1078}
1079
1080const struct hw_descriptor dv_m68hc11_descriptor[] = {
b93775f5
SC
1081 { "m68hc11", m68hc11cpu_finish },
1082 { "m68hc12", m68hc11cpu_finish },
e0709f50
AC
1083 { NULL },
1084};
1085