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