2 * QEMU MOS6522 VIA emulation
4 * Copyright (c) 2004-2007 Fabrice Bellard
5 * Copyright (c) 2007 Jocelyn Mayer
6 * Copyright (c) 2018 Mark Cave-Ayland
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include "qemu/osdep.h"
29 #include "hw/misc/mos6522.h"
30 #include "hw/qdev-properties.h"
31 #include "migration/vmstate.h"
32 #include "monitor/monitor.h"
33 #include "monitor/hmp.h"
34 #include "qapi/type-helpers.h"
35 #include "qemu/timer.h"
36 #include "qemu/cutils.h"
38 #include "qemu/module.h"
42 static const char *mos6522_reg_names
[MOS6522_NUM_REGS
] = {
43 "ORB", "ORA", "DDRB", "DDRA", "T1CL", "T1CH", "T1LL", "T1LH",
44 "T2CL", "T2CH", "SR", "ACR", "PCR", "IFR", "IER", "ANH"
47 /* XXX: implement all timer modes */
49 static void mos6522_timer1_update(MOS6522State
*s
, MOS6522Timer
*ti
,
50 int64_t current_time
);
51 static void mos6522_timer2_update(MOS6522State
*s
, MOS6522Timer
*ti
,
52 int64_t current_time
);
54 static void mos6522_update_irq(MOS6522State
*s
)
56 if (s
->ifr
& s
->ier
) {
57 qemu_irq_raise(s
->irq
);
59 qemu_irq_lower(s
->irq
);
63 static void mos6522_set_irq(void *opaque
, int n
, int level
)
65 MOS6522State
*s
= MOS6522(opaque
);
66 int last_level
= !!(s
->last_irq_levels
& (1 << n
));
67 uint8_t last_ifr
= s
->ifr
;
68 bool positive_edge
= true;
72 * SR_INT is managed by mos6522 instances and cleared upon SR
73 * read. It is only the external CA1/2 and CB1/2 lines that
74 * are edge-triggered and latched in IFR
76 if (n
!= SR_INT_BIT
&& level
== last_level
) {
80 /* Detect negative edge trigger */
81 if (last_level
== 1 && level
== 0) {
82 positive_edge
= false;
87 ctrl
= (s
->pcr
& CA2_CTRL_MASK
) >> CA2_CTRL_SHIFT
;
88 if ((positive_edge
&& (ctrl
& C2_POS
)) ||
89 (!positive_edge
&& !(ctrl
& C2_POS
))) {
94 ctrl
= (s
->pcr
& CA1_CTRL_MASK
) >> CA1_CTRL_SHIFT
;
95 if ((positive_edge
&& (ctrl
& C1_POS
)) ||
96 (!positive_edge
&& !(ctrl
& C1_POS
))) {
104 ctrl
= (s
->pcr
& CB2_CTRL_MASK
) >> CB2_CTRL_SHIFT
;
105 if ((positive_edge
&& (ctrl
& C2_POS
)) ||
106 (!positive_edge
&& !(ctrl
& C2_POS
))) {
111 ctrl
= (s
->pcr
& CB1_CTRL_MASK
) >> CB1_CTRL_SHIFT
;
112 if ((positive_edge
&& (ctrl
& C1_POS
)) ||
113 (!positive_edge
&& !(ctrl
& C1_POS
))) {
119 if (s
->ifr
!= last_ifr
) {
120 mos6522_update_irq(s
);
124 s
->last_irq_levels
|= 1 << n
;
126 s
->last_irq_levels
&= ~(1 << n
);
130 static uint64_t get_counter_value(MOS6522State
*s
, MOS6522Timer
*ti
)
132 MOS6522DeviceClass
*mdc
= MOS6522_GET_CLASS(s
);
134 if (ti
->index
== 0) {
135 return mdc
->get_timer1_counter_value(s
, ti
);
137 return mdc
->get_timer2_counter_value(s
, ti
);
141 static uint64_t get_load_time(MOS6522State
*s
, MOS6522Timer
*ti
)
143 MOS6522DeviceClass
*mdc
= MOS6522_GET_CLASS(s
);
145 if (ti
->index
== 0) {
146 return mdc
->get_timer1_load_time(s
, ti
);
148 return mdc
->get_timer2_load_time(s
, ti
);
152 static unsigned int get_counter(MOS6522State
*s
, MOS6522Timer
*ti
)
155 unsigned int counter
;
157 d
= get_counter_value(s
, ti
);
159 if (ti
->index
== 0) {
160 /* the timer goes down from latch to -1 (period of latch + 2) */
161 if (d
<= (ti
->counter_value
+ 1)) {
162 counter
= (ti
->counter_value
- d
) & 0xffff;
164 counter
= (d
- (ti
->counter_value
+ 1)) % (ti
->latch
+ 2);
165 counter
= (ti
->latch
- counter
) & 0xffff;
168 counter
= (ti
->counter_value
- d
) & 0xffff;
173 static void set_counter(MOS6522State
*s
, MOS6522Timer
*ti
, unsigned int val
)
175 trace_mos6522_set_counter(1 + ti
->index
, val
);
176 ti
->load_time
= get_load_time(s
, ti
);
177 ti
->counter_value
= val
;
178 if (ti
->index
== 0) {
179 mos6522_timer1_update(s
, ti
, ti
->load_time
);
181 mos6522_timer2_update(s
, ti
, ti
->load_time
);
185 static int64_t get_next_irq_time(MOS6522State
*s
, MOS6522Timer
*ti
,
186 int64_t current_time
)
188 int64_t d
, next_time
;
189 unsigned int counter
;
191 if (ti
->frequency
== 0) {
195 /* current counter value */
196 d
= muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - ti
->load_time
,
197 ti
->frequency
, NANOSECONDS_PER_SECOND
);
199 /* the timer goes down from latch to -1 (period of latch + 2) */
200 if (d
<= (ti
->counter_value
+ 1)) {
201 counter
= (ti
->counter_value
- d
) & 0xffff;
203 counter
= (d
- (ti
->counter_value
+ 1)) % (ti
->latch
+ 2);
204 counter
= (ti
->latch
- counter
) & 0xffff;
207 /* Note: we consider the irq is raised on 0 */
208 if (counter
== 0xffff) {
209 next_time
= d
+ ti
->latch
+ 1;
210 } else if (counter
== 0) {
211 next_time
= d
+ ti
->latch
+ 2;
213 next_time
= d
+ counter
;
215 trace_mos6522_get_next_irq_time(ti
->latch
, d
, next_time
- d
);
216 next_time
= muldiv64(next_time
, NANOSECONDS_PER_SECOND
, ti
->frequency
) +
219 if (next_time
<= current_time
) {
220 next_time
= current_time
+ 1;
225 static void mos6522_timer1_update(MOS6522State
*s
, MOS6522Timer
*ti
,
226 int64_t current_time
)
231 ti
->next_irq_time
= get_next_irq_time(s
, ti
, current_time
);
232 if ((s
->ier
& T1_INT
) == 0 || (s
->acr
& T1MODE
) != T1MODE_CONT
) {
233 timer_del(ti
->timer
);
235 timer_mod(ti
->timer
, ti
->next_irq_time
);
239 static void mos6522_timer2_update(MOS6522State
*s
, MOS6522Timer
*ti
,
240 int64_t current_time
)
245 ti
->next_irq_time
= get_next_irq_time(s
, ti
, current_time
);
246 if ((s
->ier
& T2_INT
) == 0) {
247 timer_del(ti
->timer
);
249 timer_mod(ti
->timer
, ti
->next_irq_time
);
253 static void mos6522_timer1(void *opaque
)
255 MOS6522State
*s
= opaque
;
256 MOS6522Timer
*ti
= &s
->timers
[0];
258 mos6522_timer1_update(s
, ti
, ti
->next_irq_time
);
260 mos6522_update_irq(s
);
263 static void mos6522_timer2(void *opaque
)
265 MOS6522State
*s
= opaque
;
266 MOS6522Timer
*ti
= &s
->timers
[1];
268 mos6522_timer2_update(s
, ti
, ti
->next_irq_time
);
270 mos6522_update_irq(s
);
273 static uint64_t mos6522_get_counter_value(MOS6522State
*s
, MOS6522Timer
*ti
)
275 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - ti
->load_time
,
276 ti
->frequency
, NANOSECONDS_PER_SECOND
);
279 static uint64_t mos6522_get_load_time(MOS6522State
*s
, MOS6522Timer
*ti
)
281 uint64_t load_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
286 static void mos6522_portA_write(MOS6522State
*s
)
288 qemu_log_mask(LOG_UNIMP
, "portA_write unimplemented\n");
291 static void mos6522_portB_write(MOS6522State
*s
)
293 qemu_log_mask(LOG_UNIMP
, "portB_write unimplemented\n");
296 uint64_t mos6522_read(void *opaque
, hwaddr addr
, unsigned size
)
298 MOS6522State
*s
= opaque
;
301 int64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
303 if (now
>= s
->timers
[0].next_irq_time
) {
304 mos6522_timer1_update(s
, &s
->timers
[0], now
);
307 if (now
>= s
->timers
[1].next_irq_time
) {
308 mos6522_timer2_update(s
, &s
->timers
[1], now
);
314 ctrl
= (s
->pcr
& CB2_CTRL_MASK
) >> CB2_CTRL_SHIFT
;
315 if (!(ctrl
& C2_IND
)) {
319 mos6522_update_irq(s
);
322 qemu_log_mask(LOG_UNIMP
, "Read access to register A with handshake");
326 ctrl
= (s
->pcr
& CA2_CTRL_MASK
) >> CA2_CTRL_SHIFT
;
327 if (!(ctrl
& C2_IND
)) {
331 mos6522_update_irq(s
);
340 val
= get_counter(s
, &s
->timers
[0]) & 0xff;
342 mos6522_update_irq(s
);
345 val
= get_counter(s
, &s
->timers
[0]) >> 8;
346 mos6522_update_irq(s
);
349 val
= s
->timers
[0].latch
& 0xff;
352 /* XXX: check this */
353 val
= (s
->timers
[0].latch
>> 8) & 0xff;
356 val
= get_counter(s
, &s
->timers
[1]) & 0xff;
358 mos6522_update_irq(s
);
361 val
= get_counter(s
, &s
->timers
[1]) >> 8;
366 mos6522_update_irq(s
);
376 if (s
->ifr
& s
->ier
) {
384 g_assert_not_reached();
387 if (addr
!= VIA_REG_IFR
|| val
!= 0) {
388 trace_mos6522_read(addr
, mos6522_reg_names
[addr
], val
);
394 void mos6522_write(void *opaque
, hwaddr addr
, uint64_t val
, unsigned size
)
396 MOS6522State
*s
= opaque
;
397 MOS6522DeviceClass
*mdc
= MOS6522_GET_CLASS(s
);
400 trace_mos6522_write(addr
, mos6522_reg_names
[addr
], val
);
404 s
->b
= (s
->b
& ~s
->dirb
) | (val
& s
->dirb
);
406 ctrl
= (s
->pcr
& CB2_CTRL_MASK
) >> CB2_CTRL_SHIFT
;
407 if (!(ctrl
& C2_IND
)) {
411 mos6522_update_irq(s
);
414 qemu_log_mask(LOG_UNIMP
, "Write access to register A with handshake");
417 s
->a
= (s
->a
& ~s
->dira
) | (val
& s
->dira
);
419 ctrl
= (s
->pcr
& CA2_CTRL_MASK
) >> CA2_CTRL_SHIFT
;
420 if (!(ctrl
& C2_IND
)) {
424 mos6522_update_irq(s
);
433 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff00) | val
;
434 mos6522_timer1_update(s
, &s
->timers
[0],
435 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
438 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff) | (val
<< 8);
440 set_counter(s
, &s
->timers
[0], s
->timers
[0].latch
);
443 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff00) | val
;
444 mos6522_timer1_update(s
, &s
->timers
[0],
445 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
448 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff) | (val
<< 8);
450 mos6522_timer1_update(s
, &s
->timers
[0],
451 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
454 s
->timers
[1].latch
= (s
->timers
[1].latch
& 0xff00) | val
;
457 /* To ensure T2 generates an interrupt on zero crossing with the
458 common timer code, write the value directly from the latch to
460 s
->timers
[1].latch
= (s
->timers
[1].latch
& 0xff) | (val
<< 8);
462 set_counter(s
, &s
->timers
[1], s
->timers
[1].latch
);
469 mos6522_timer1_update(s
, &s
->timers
[0],
470 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
478 mos6522_update_irq(s
);
483 s
->ier
|= val
& 0x7f;
488 mos6522_update_irq(s
);
489 /* if IER is modified starts needed timers */
490 mos6522_timer1_update(s
, &s
->timers
[0],
491 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
492 mos6522_timer2_update(s
, &s
->timers
[1],
493 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
496 g_assert_not_reached();
500 static int qmp_x_query_via_foreach(Object
*obj
, void *opaque
)
502 GString
*buf
= opaque
;
504 if (object_dynamic_cast(obj
, TYPE_MOS6522
)) {
505 MOS6522State
*s
= MOS6522(obj
);
506 int64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
507 uint16_t t1counter
= get_counter(s
, &s
->timers
[0]);
508 uint16_t t2counter
= get_counter(s
, &s
->timers
[1]);
510 g_string_append_printf(buf
, "%s:\n", object_get_typename(obj
));
512 g_string_append_printf(buf
, " Registers:\n");
513 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
514 mos6522_reg_names
[0], s
->b
);
515 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
516 mos6522_reg_names
[1], s
->a
);
517 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
518 mos6522_reg_names
[2], s
->dirb
);
519 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
520 mos6522_reg_names
[3], s
->dira
);
521 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
522 mos6522_reg_names
[4], t1counter
& 0xff);
523 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
524 mos6522_reg_names
[5], t1counter
>> 8);
525 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
526 mos6522_reg_names
[6],
527 s
->timers
[0].latch
& 0xff);
528 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
529 mos6522_reg_names
[7],
530 s
->timers
[0].latch
>> 8);
531 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
532 mos6522_reg_names
[8], t2counter
& 0xff);
533 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
534 mos6522_reg_names
[9], t2counter
>> 8);
535 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
536 mos6522_reg_names
[10], s
->sr
);
537 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
538 mos6522_reg_names
[11], s
->acr
);
539 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
540 mos6522_reg_names
[12], s
->pcr
);
541 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
542 mos6522_reg_names
[13], s
->ifr
);
543 g_string_append_printf(buf
, " %-*s: 0x%x\n", 4,
544 mos6522_reg_names
[14], s
->ier
);
546 g_string_append_printf(buf
, " Timers:\n");
547 g_string_append_printf(buf
, " Using current time now(ns)=%"PRId64
549 g_string_append_printf(buf
, " T1 freq(hz)=%"PRId64
553 " load_time(ns)=%"PRId64
554 " next_irq_time(ns)=%"PRId64
"\n",
555 s
->timers
[0].frequency
,
556 ((s
->acr
& T1MODE
) == T1MODE_CONT
) ? "continuous"
560 s
->timers
[0].load_time
,
561 get_next_irq_time(s
, &s
->timers
[0], now
));
562 g_string_append_printf(buf
, " T2 freq(hz)=%"PRId64
566 " load_time(ns)=%"PRId64
567 " next_irq_time(ns)=%"PRId64
"\n",
568 s
->timers
[1].frequency
,
572 s
->timers
[1].load_time
,
573 get_next_irq_time(s
, &s
->timers
[1], now
));
579 static HumanReadableText
*qmp_x_query_via(Error
**errp
)
581 g_autoptr(GString
) buf
= g_string_new("");
583 object_child_foreach_recursive(object_get_root(),
584 qmp_x_query_via_foreach
, buf
);
586 return human_readable_text_from_str(buf
);
589 void hmp_info_via(Monitor
*mon
, const QDict
*qdict
)
592 g_autoptr(HumanReadableText
) info
= qmp_x_query_via(&err
);
594 if (hmp_handle_error(mon
, err
)) {
597 monitor_puts(mon
, info
->human_readable_text
);
600 static const MemoryRegionOps mos6522_ops
= {
601 .read
= mos6522_read
,
602 .write
= mos6522_write
,
603 .endianness
= DEVICE_NATIVE_ENDIAN
,
605 .min_access_size
= 1,
606 .max_access_size
= 1,
610 static const VMStateDescription vmstate_mos6522_timer
= {
611 .name
= "mos6522_timer",
613 .minimum_version_id
= 0,
614 .fields
= (VMStateField
[]) {
615 VMSTATE_UINT16(latch
, MOS6522Timer
),
616 VMSTATE_UINT16(counter_value
, MOS6522Timer
),
617 VMSTATE_INT64(load_time
, MOS6522Timer
),
618 VMSTATE_INT64(next_irq_time
, MOS6522Timer
),
619 VMSTATE_TIMER_PTR(timer
, MOS6522Timer
),
620 VMSTATE_END_OF_LIST()
624 const VMStateDescription vmstate_mos6522
= {
627 .minimum_version_id
= 1,
628 .fields
= (VMStateField
[]) {
629 VMSTATE_UINT8(a
, MOS6522State
),
630 VMSTATE_UINT8(b
, MOS6522State
),
631 VMSTATE_UINT8(dira
, MOS6522State
),
632 VMSTATE_UINT8(dirb
, MOS6522State
),
633 VMSTATE_UINT8(sr
, MOS6522State
),
634 VMSTATE_UINT8(acr
, MOS6522State
),
635 VMSTATE_UINT8(pcr
, MOS6522State
),
636 VMSTATE_UINT8(ifr
, MOS6522State
),
637 VMSTATE_UINT8(ier
, MOS6522State
),
638 VMSTATE_UINT8(last_irq_levels
, MOS6522State
),
639 VMSTATE_STRUCT_ARRAY(timers
, MOS6522State
, 2, 0,
640 vmstate_mos6522_timer
, MOS6522Timer
),
641 VMSTATE_END_OF_LIST()
645 static void mos6522_reset_hold(Object
*obj
)
647 MOS6522State
*s
= MOS6522(obj
);
658 /* s->ier = T1_INT | SR_INT; */
660 s
->timers
[0].frequency
= s
->frequency
;
661 s
->timers
[0].latch
= 0xffff;
662 set_counter(s
, &s
->timers
[0], 0xffff);
663 timer_del(s
->timers
[0].timer
);
665 s
->timers
[1].frequency
= s
->frequency
;
666 s
->timers
[1].latch
= 0xffff;
667 timer_del(s
->timers
[1].timer
);
670 static void mos6522_init(Object
*obj
)
672 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
673 MOS6522State
*s
= MOS6522(obj
);
676 memory_region_init_io(&s
->mem
, obj
, &mos6522_ops
, s
, "mos6522",
678 sysbus_init_mmio(sbd
, &s
->mem
);
679 sysbus_init_irq(sbd
, &s
->irq
);
681 for (i
= 0; i
< ARRAY_SIZE(s
->timers
); i
++) {
682 s
->timers
[i
].index
= i
;
685 s
->timers
[0].timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, mos6522_timer1
, s
);
686 s
->timers
[1].timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, mos6522_timer2
, s
);
688 qdev_init_gpio_in(DEVICE(obj
), mos6522_set_irq
, VIA_NUM_INTS
);
691 static void mos6522_finalize(Object
*obj
)
693 MOS6522State
*s
= MOS6522(obj
);
695 timer_free(s
->timers
[0].timer
);
696 timer_free(s
->timers
[1].timer
);
699 static Property mos6522_properties
[] = {
700 DEFINE_PROP_UINT64("frequency", MOS6522State
, frequency
, 0),
701 DEFINE_PROP_END_OF_LIST()
704 static void mos6522_class_init(ObjectClass
*oc
, void *data
)
706 DeviceClass
*dc
= DEVICE_CLASS(oc
);
707 ResettableClass
*rc
= RESETTABLE_CLASS(oc
);
708 MOS6522DeviceClass
*mdc
= MOS6522_CLASS(oc
);
710 rc
->phases
.hold
= mos6522_reset_hold
;
711 dc
->vmsd
= &vmstate_mos6522
;
712 device_class_set_props(dc
, mos6522_properties
);
713 mdc
->portB_write
= mos6522_portB_write
;
714 mdc
->portA_write
= mos6522_portA_write
;
715 mdc
->get_timer1_counter_value
= mos6522_get_counter_value
;
716 mdc
->get_timer2_counter_value
= mos6522_get_counter_value
;
717 mdc
->get_timer1_load_time
= mos6522_get_load_time
;
718 mdc
->get_timer2_load_time
= mos6522_get_load_time
;
721 static const TypeInfo mos6522_type_info
= {
722 .name
= TYPE_MOS6522
,
723 .parent
= TYPE_SYS_BUS_DEVICE
,
724 .instance_size
= sizeof(MOS6522State
),
725 .instance_init
= mos6522_init
,
726 .instance_finalize
= mos6522_finalize
,
728 .class_size
= sizeof(MOS6522DeviceClass
),
729 .class_init
= mos6522_class_init
,
732 static void mos6522_register_types(void)
734 type_register_static(&mos6522_type_info
);
737 type_init(mos6522_register_types
)