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"
28 #include "hw/input/adb.h"
30 #include "hw/misc/mos6522.h"
31 #include "hw/qdev-properties.h"
32 #include "migration/vmstate.h"
33 #include "qemu/timer.h"
34 #include "qemu/cutils.h"
36 #include "qemu/module.h"
39 /* XXX: implement all timer modes */
41 static void mos6522_timer1_update(MOS6522State
*s
, MOS6522Timer
*ti
,
42 int64_t current_time
);
43 static void mos6522_timer2_update(MOS6522State
*s
, MOS6522Timer
*ti
,
44 int64_t current_time
);
46 static void mos6522_update_irq(MOS6522State
*s
)
48 if (s
->ifr
& s
->ier
) {
49 qemu_irq_raise(s
->irq
);
51 qemu_irq_lower(s
->irq
);
55 static uint64_t get_counter_value(MOS6522State
*s
, MOS6522Timer
*ti
)
57 MOS6522DeviceClass
*mdc
= MOS6522_GET_CLASS(s
);
60 return mdc
->get_timer1_counter_value(s
, ti
);
62 return mdc
->get_timer2_counter_value(s
, ti
);
66 static uint64_t get_load_time(MOS6522State
*s
, MOS6522Timer
*ti
)
68 MOS6522DeviceClass
*mdc
= MOS6522_GET_CLASS(s
);
71 return mdc
->get_timer1_load_time(s
, ti
);
73 return mdc
->get_timer2_load_time(s
, ti
);
77 static unsigned int get_counter(MOS6522State
*s
, MOS6522Timer
*ti
)
82 d
= get_counter_value(s
, ti
);
85 /* the timer goes down from latch to -1 (period of latch + 2) */
86 if (d
<= (ti
->counter_value
+ 1)) {
87 counter
= (ti
->counter_value
- d
) & 0xffff;
89 counter
= (d
- (ti
->counter_value
+ 1)) % (ti
->latch
+ 2);
90 counter
= (ti
->latch
- counter
) & 0xffff;
93 counter
= (ti
->counter_value
- d
) & 0xffff;
98 static void set_counter(MOS6522State
*s
, MOS6522Timer
*ti
, unsigned int val
)
100 trace_mos6522_set_counter(1 + ti
->index
, val
);
101 ti
->load_time
= get_load_time(s
, ti
);
102 ti
->counter_value
= val
;
103 if (ti
->index
== 0) {
104 mos6522_timer1_update(s
, ti
, ti
->load_time
);
106 mos6522_timer2_update(s
, ti
, ti
->load_time
);
110 static int64_t get_next_irq_time(MOS6522State
*s
, MOS6522Timer
*ti
,
111 int64_t current_time
)
113 int64_t d
, next_time
;
114 unsigned int counter
;
116 if (ti
->frequency
== 0) {
120 /* current counter value */
121 d
= muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - ti
->load_time
,
122 ti
->frequency
, NANOSECONDS_PER_SECOND
);
124 /* the timer goes down from latch to -1 (period of latch + 2) */
125 if (d
<= (ti
->counter_value
+ 1)) {
126 counter
= (ti
->counter_value
- d
) & 0xffff;
128 counter
= (d
- (ti
->counter_value
+ 1)) % (ti
->latch
+ 2);
129 counter
= (ti
->latch
- counter
) & 0xffff;
132 /* Note: we consider the irq is raised on 0 */
133 if (counter
== 0xffff) {
134 next_time
= d
+ ti
->latch
+ 1;
135 } else if (counter
== 0) {
136 next_time
= d
+ ti
->latch
+ 2;
138 next_time
= d
+ counter
;
140 trace_mos6522_get_next_irq_time(ti
->latch
, d
, next_time
- d
);
141 next_time
= muldiv64(next_time
, NANOSECONDS_PER_SECOND
, ti
->frequency
) +
144 if (next_time
<= current_time
) {
145 next_time
= current_time
+ 1;
150 static void mos6522_timer1_update(MOS6522State
*s
, MOS6522Timer
*ti
,
151 int64_t current_time
)
156 ti
->next_irq_time
= get_next_irq_time(s
, ti
, current_time
);
157 if ((s
->ier
& T1_INT
) == 0 || (s
->acr
& T1MODE
) != T1MODE_CONT
) {
158 timer_del(ti
->timer
);
160 timer_mod(ti
->timer
, ti
->next_irq_time
);
164 static void mos6522_timer2_update(MOS6522State
*s
, MOS6522Timer
*ti
,
165 int64_t current_time
)
170 ti
->next_irq_time
= get_next_irq_time(s
, ti
, current_time
);
171 if ((s
->ier
& T2_INT
) == 0) {
172 timer_del(ti
->timer
);
174 timer_mod(ti
->timer
, ti
->next_irq_time
);
178 static void mos6522_timer1(void *opaque
)
180 MOS6522State
*s
= opaque
;
181 MOS6522Timer
*ti
= &s
->timers
[0];
183 mos6522_timer1_update(s
, ti
, ti
->next_irq_time
);
185 mos6522_update_irq(s
);
188 static void mos6522_timer2(void *opaque
)
190 MOS6522State
*s
= opaque
;
191 MOS6522Timer
*ti
= &s
->timers
[1];
193 mos6522_timer2_update(s
, ti
, ti
->next_irq_time
);
195 mos6522_update_irq(s
);
198 static void mos6522_set_sr_int(MOS6522State
*s
)
200 trace_mos6522_set_sr_int();
202 mos6522_update_irq(s
);
205 static uint64_t mos6522_get_counter_value(MOS6522State
*s
, MOS6522Timer
*ti
)
207 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - ti
->load_time
,
208 ti
->frequency
, NANOSECONDS_PER_SECOND
);
211 static uint64_t mos6522_get_load_time(MOS6522State
*s
, MOS6522Timer
*ti
)
213 uint64_t load_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
218 static void mos6522_portA_write(MOS6522State
*s
)
220 qemu_log_mask(LOG_UNIMP
, "portA_write unimplemented\n");
223 static void mos6522_portB_write(MOS6522State
*s
)
225 qemu_log_mask(LOG_UNIMP
, "portB_write unimplemented\n");
228 uint64_t mos6522_read(void *opaque
, hwaddr addr
, unsigned size
)
230 MOS6522State
*s
= opaque
;
232 int64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
234 if (now
>= s
->timers
[0].next_irq_time
) {
235 mos6522_timer1_update(s
, &s
->timers
[0], now
);
238 if (now
>= s
->timers
[1].next_irq_time
) {
239 mos6522_timer2_update(s
, &s
->timers
[1], now
);
247 qemu_log_mask(LOG_UNIMP
, "Read access to register A with handshake");
259 val
= get_counter(s
, &s
->timers
[0]) & 0xff;
261 mos6522_update_irq(s
);
264 val
= get_counter(s
, &s
->timers
[0]) >> 8;
265 mos6522_update_irq(s
);
268 val
= s
->timers
[0].latch
& 0xff;
271 /* XXX: check this */
272 val
= (s
->timers
[0].latch
>> 8) & 0xff;
275 val
= get_counter(s
, &s
->timers
[1]) & 0xff;
277 mos6522_update_irq(s
);
280 val
= get_counter(s
, &s
->timers
[1]) >> 8;
285 mos6522_update_irq(s
);
295 if (s
->ifr
& s
->ier
) {
303 g_assert_not_reached();
306 if (addr
!= VIA_REG_IFR
|| val
!= 0) {
307 trace_mos6522_read(addr
, val
);
313 void mos6522_write(void *opaque
, hwaddr addr
, uint64_t val
, unsigned size
)
315 MOS6522State
*s
= opaque
;
316 MOS6522DeviceClass
*mdc
= MOS6522_GET_CLASS(s
);
318 trace_mos6522_write(addr
, val
);
322 s
->b
= (s
->b
& ~s
->dirb
) | (val
& s
->dirb
);
326 qemu_log_mask(LOG_UNIMP
, "Write access to register A with handshake");
329 s
->a
= (s
->a
& ~s
->dira
) | (val
& s
->dira
);
339 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff00) | val
;
340 mos6522_timer1_update(s
, &s
->timers
[0],
341 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
344 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff) | (val
<< 8);
346 set_counter(s
, &s
->timers
[0], s
->timers
[0].latch
);
349 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff00) | val
;
350 mos6522_timer1_update(s
, &s
->timers
[0],
351 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
354 s
->timers
[0].latch
= (s
->timers
[0].latch
& 0xff) | (val
<< 8);
356 mos6522_timer1_update(s
, &s
->timers
[0],
357 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
360 s
->timers
[1].latch
= (s
->timers
[1].latch
& 0xff00) | val
;
363 /* To ensure T2 generates an interrupt on zero crossing with the
364 common timer code, write the value directly from the latch to
366 s
->timers
[1].latch
= (s
->timers
[1].latch
& 0xff) | (val
<< 8);
368 set_counter(s
, &s
->timers
[1], s
->timers
[1].latch
);
375 mos6522_timer1_update(s
, &s
->timers
[0],
376 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
384 mos6522_update_irq(s
);
389 s
->ier
|= val
& 0x7f;
394 mos6522_update_irq(s
);
395 /* if IER is modified starts needed timers */
396 mos6522_timer1_update(s
, &s
->timers
[0],
397 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
398 mos6522_timer2_update(s
, &s
->timers
[1],
399 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
402 g_assert_not_reached();
406 static const MemoryRegionOps mos6522_ops
= {
407 .read
= mos6522_read
,
408 .write
= mos6522_write
,
409 .endianness
= DEVICE_NATIVE_ENDIAN
,
411 .min_access_size
= 1,
412 .max_access_size
= 1,
416 static const VMStateDescription vmstate_mos6522_timer
= {
417 .name
= "mos6522_timer",
419 .minimum_version_id
= 0,
420 .fields
= (VMStateField
[]) {
421 VMSTATE_UINT16(latch
, MOS6522Timer
),
422 VMSTATE_UINT16(counter_value
, MOS6522Timer
),
423 VMSTATE_INT64(load_time
, MOS6522Timer
),
424 VMSTATE_INT64(next_irq_time
, MOS6522Timer
),
425 VMSTATE_TIMER_PTR(timer
, MOS6522Timer
),
426 VMSTATE_END_OF_LIST()
430 const VMStateDescription vmstate_mos6522
= {
433 .minimum_version_id
= 0,
434 .fields
= (VMStateField
[]) {
435 VMSTATE_UINT8(a
, MOS6522State
),
436 VMSTATE_UINT8(b
, MOS6522State
),
437 VMSTATE_UINT8(dira
, MOS6522State
),
438 VMSTATE_UINT8(dirb
, MOS6522State
),
439 VMSTATE_UINT8(sr
, MOS6522State
),
440 VMSTATE_UINT8(acr
, MOS6522State
),
441 VMSTATE_UINT8(pcr
, MOS6522State
),
442 VMSTATE_UINT8(ifr
, MOS6522State
),
443 VMSTATE_UINT8(ier
, MOS6522State
),
444 VMSTATE_STRUCT_ARRAY(timers
, MOS6522State
, 2, 0,
445 vmstate_mos6522_timer
, MOS6522Timer
),
446 VMSTATE_END_OF_LIST()
450 static void mos6522_reset(DeviceState
*dev
)
452 MOS6522State
*s
= MOS6522(dev
);
463 /* s->ier = T1_INT | SR_INT; */
465 s
->timers
[0].frequency
= s
->frequency
;
466 s
->timers
[0].latch
= 0xffff;
467 set_counter(s
, &s
->timers
[0], 0xffff);
468 timer_del(s
->timers
[0].timer
);
470 s
->timers
[1].frequency
= s
->frequency
;
471 s
->timers
[1].latch
= 0xffff;
472 timer_del(s
->timers
[1].timer
);
475 static void mos6522_init(Object
*obj
)
477 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
478 MOS6522State
*s
= MOS6522(obj
);
481 memory_region_init_io(&s
->mem
, obj
, &mos6522_ops
, s
, "mos6522", 0x10);
482 sysbus_init_mmio(sbd
, &s
->mem
);
483 sysbus_init_irq(sbd
, &s
->irq
);
485 for (i
= 0; i
< ARRAY_SIZE(s
->timers
); i
++) {
486 s
->timers
[i
].index
= i
;
489 s
->timers
[0].timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, mos6522_timer1
, s
);
490 s
->timers
[1].timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, mos6522_timer2
, s
);
493 static Property mos6522_properties
[] = {
494 DEFINE_PROP_UINT64("frequency", MOS6522State
, frequency
, 0),
495 DEFINE_PROP_END_OF_LIST()
498 static void mos6522_class_init(ObjectClass
*oc
, void *data
)
500 DeviceClass
*dc
= DEVICE_CLASS(oc
);
501 MOS6522DeviceClass
*mdc
= MOS6522_CLASS(oc
);
503 dc
->reset
= mos6522_reset
;
504 dc
->vmsd
= &vmstate_mos6522
;
505 device_class_set_props(dc
, mos6522_properties
);
506 mdc
->parent_reset
= dc
->reset
;
507 mdc
->set_sr_int
= mos6522_set_sr_int
;
508 mdc
->portB_write
= mos6522_portB_write
;
509 mdc
->portA_write
= mos6522_portA_write
;
510 mdc
->update_irq
= mos6522_update_irq
;
511 mdc
->get_timer1_counter_value
= mos6522_get_counter_value
;
512 mdc
->get_timer2_counter_value
= mos6522_get_counter_value
;
513 mdc
->get_timer1_load_time
= mos6522_get_load_time
;
514 mdc
->get_timer2_load_time
= mos6522_get_load_time
;
517 static const TypeInfo mos6522_type_info
= {
518 .name
= TYPE_MOS6522
,
519 .parent
= TYPE_SYS_BUS_DEVICE
,
520 .instance_size
= sizeof(MOS6522State
),
521 .instance_init
= mos6522_init
,
523 .class_size
= sizeof(MOS6522DeviceClass
),
524 .class_init
= mos6522_class_init
,
527 static void mos6522_register_types(void)
529 type_register_static(&mos6522_type_info
);
532 type_init(mos6522_register_types
)