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