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