151f233ecSMark Cave-Ayland /* 251f233ecSMark Cave-Ayland * QEMU MOS6522 VIA emulation 351f233ecSMark Cave-Ayland * 451f233ecSMark Cave-Ayland * Copyright (c) 2004-2007 Fabrice Bellard 551f233ecSMark Cave-Ayland * Copyright (c) 2007 Jocelyn Mayer 651f233ecSMark Cave-Ayland * Copyright (c) 2018 Mark Cave-Ayland 751f233ecSMark Cave-Ayland * 851f233ecSMark Cave-Ayland * Permission is hereby granted, free of charge, to any person obtaining a copy 951f233ecSMark Cave-Ayland * of this software and associated documentation files (the "Software"), to deal 1051f233ecSMark Cave-Ayland * in the Software without restriction, including without limitation the rights 1151f233ecSMark Cave-Ayland * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1251f233ecSMark Cave-Ayland * copies of the Software, and to permit persons to whom the Software is 1351f233ecSMark Cave-Ayland * furnished to do so, subject to the following conditions: 1451f233ecSMark Cave-Ayland * 1551f233ecSMark Cave-Ayland * The above copyright notice and this permission notice shall be included in 1651f233ecSMark Cave-Ayland * all copies or substantial portions of the Software. 1751f233ecSMark Cave-Ayland * 1851f233ecSMark Cave-Ayland * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1951f233ecSMark Cave-Ayland * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2051f233ecSMark Cave-Ayland * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2151f233ecSMark Cave-Ayland * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2251f233ecSMark Cave-Ayland * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2351f233ecSMark Cave-Ayland * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2451f233ecSMark Cave-Ayland * THE SOFTWARE. 2551f233ecSMark Cave-Ayland */ 260b8fa32fSMarkus Armbruster 2751f233ecSMark Cave-Ayland #include "qemu/osdep.h" 2851f233ecSMark Cave-Ayland #include "hw/input/adb.h" 2964552b6bSMarkus Armbruster #include "hw/irq.h" 3051f233ecSMark Cave-Ayland #include "hw/misc/mos6522.h" 31a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 32d6454270SMarkus Armbruster #include "migration/vmstate.h" 33409e9f71SMark Cave-Ayland #include "monitor/monitor.h" 34409e9f71SMark Cave-Ayland #include "monitor/hmp.h" 35409e9f71SMark Cave-Ayland #include "qapi/type-helpers.h" 3651f233ecSMark Cave-Ayland #include "qemu/timer.h" 3751f233ecSMark Cave-Ayland #include "qemu/cutils.h" 3851f233ecSMark Cave-Ayland #include "qemu/log.h" 390b8fa32fSMarkus Armbruster #include "qemu/module.h" 4051f233ecSMark Cave-Ayland #include "trace.h" 4151f233ecSMark Cave-Ayland 426c726698SMark Cave-Ayland 436c726698SMark Cave-Ayland static const char *mos6522_reg_names[MOS6522_NUM_REGS] = { 446c726698SMark Cave-Ayland "ORB", "ORA", "DDRB", "DDRA", "T1CL", "T1CH", "T1LL", "T1LH", 456c726698SMark Cave-Ayland "T2CL", "T2CH", "SR", "ACR", "PCR", "IFR", "IER", "ANH" 466c726698SMark Cave-Ayland }; 476c726698SMark Cave-Ayland 4851f233ecSMark Cave-Ayland /* XXX: implement all timer modes */ 4951f233ecSMark Cave-Ayland 50cd8843ffSLaurent Vivier static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti, 51cd8843ffSLaurent Vivier int64_t current_time); 52cd8843ffSLaurent Vivier static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti, 5351f233ecSMark Cave-Ayland int64_t current_time); 5451f233ecSMark Cave-Ayland 5551f233ecSMark Cave-Ayland static void mos6522_update_irq(MOS6522State *s) 5651f233ecSMark Cave-Ayland { 5732a8c27bSMark Cave-Ayland if (s->ifr & s->ier) { 5851f233ecSMark Cave-Ayland qemu_irq_raise(s->irq); 5951f233ecSMark Cave-Ayland } else { 6051f233ecSMark Cave-Ayland qemu_irq_lower(s->irq); 6151f233ecSMark Cave-Ayland } 6251f233ecSMark Cave-Ayland } 6351f233ecSMark Cave-Ayland 64ebe5bca2SMark Cave-Ayland static void mos6522_set_irq(void *opaque, int n, int level) 65ebe5bca2SMark Cave-Ayland { 66ebe5bca2SMark Cave-Ayland MOS6522State *s = MOS6522(opaque); 67b793b4efSMark Cave-Ayland int last_level = !!(s->last_irq_levels & (1 << n)); 68b793b4efSMark Cave-Ayland uint8_t last_ifr = s->ifr; 69b793b4efSMark Cave-Ayland bool positive_edge = true; 70b793b4efSMark Cave-Ayland int ctrl; 71ebe5bca2SMark Cave-Ayland 72b793b4efSMark Cave-Ayland /* 73b793b4efSMark Cave-Ayland * SR_INT is managed by mos6522 instances and cleared upon SR 74b793b4efSMark Cave-Ayland * read. It is only the external CA1/2 and CB1/2 lines that 75b793b4efSMark Cave-Ayland * are edge-triggered and latched in IFR 76b793b4efSMark Cave-Ayland */ 77b793b4efSMark Cave-Ayland if (n != SR_INT_BIT && level == last_level) { 78b793b4efSMark Cave-Ayland return; 79ebe5bca2SMark Cave-Ayland } 80ebe5bca2SMark Cave-Ayland 81b793b4efSMark Cave-Ayland /* Detect negative edge trigger */ 82b793b4efSMark Cave-Ayland if (last_level == 1 && level == 0) { 83b793b4efSMark Cave-Ayland positive_edge = false; 84b793b4efSMark Cave-Ayland } 85b793b4efSMark Cave-Ayland 86b793b4efSMark Cave-Ayland switch (n) { 87b793b4efSMark Cave-Ayland case CA2_INT_BIT: 88b793b4efSMark Cave-Ayland ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT; 89b793b4efSMark Cave-Ayland if ((positive_edge && (ctrl & C2_POS)) || 90b793b4efSMark Cave-Ayland (!positive_edge && !(ctrl & C2_POS))) { 91b793b4efSMark Cave-Ayland s->ifr |= 1 << n; 92b793b4efSMark Cave-Ayland } 93b793b4efSMark Cave-Ayland break; 94b793b4efSMark Cave-Ayland case CA1_INT_BIT: 95b793b4efSMark Cave-Ayland ctrl = (s->pcr & CA1_CTRL_MASK) >> CA1_CTRL_SHIFT; 96b793b4efSMark Cave-Ayland if ((positive_edge && (ctrl & C1_POS)) || 97b793b4efSMark Cave-Ayland (!positive_edge && !(ctrl & C1_POS))) { 98b793b4efSMark Cave-Ayland s->ifr |= 1 << n; 99b793b4efSMark Cave-Ayland } 100b793b4efSMark Cave-Ayland break; 101b793b4efSMark Cave-Ayland case SR_INT_BIT: 102b793b4efSMark Cave-Ayland s->ifr |= 1 << n; 103b793b4efSMark Cave-Ayland break; 104b793b4efSMark Cave-Ayland case CB2_INT_BIT: 105b793b4efSMark Cave-Ayland ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT; 106b793b4efSMark Cave-Ayland if ((positive_edge && (ctrl & C2_POS)) || 107b793b4efSMark Cave-Ayland (!positive_edge && !(ctrl & C2_POS))) { 108b793b4efSMark Cave-Ayland s->ifr |= 1 << n; 109b793b4efSMark Cave-Ayland } 110b793b4efSMark Cave-Ayland break; 111b793b4efSMark Cave-Ayland case CB1_INT_BIT: 112b793b4efSMark Cave-Ayland ctrl = (s->pcr & CB1_CTRL_MASK) >> CB1_CTRL_SHIFT; 113b793b4efSMark Cave-Ayland if ((positive_edge && (ctrl & C1_POS)) || 114b793b4efSMark Cave-Ayland (!positive_edge && !(ctrl & C1_POS))) { 115b793b4efSMark Cave-Ayland s->ifr |= 1 << n; 116b793b4efSMark Cave-Ayland } 117b793b4efSMark Cave-Ayland break; 118b793b4efSMark Cave-Ayland } 119b793b4efSMark Cave-Ayland 120b793b4efSMark Cave-Ayland if (s->ifr != last_ifr) { 121ebe5bca2SMark Cave-Ayland mos6522_update_irq(s); 122b793b4efSMark Cave-Ayland } 123d4454e41SMark Cave-Ayland 124d4454e41SMark Cave-Ayland if (level) { 125d4454e41SMark Cave-Ayland s->last_irq_levels |= 1 << n; 126d4454e41SMark Cave-Ayland } else { 127d4454e41SMark Cave-Ayland s->last_irq_levels &= ~(1 << n); 128d4454e41SMark Cave-Ayland } 129ebe5bca2SMark Cave-Ayland } 130ebe5bca2SMark Cave-Ayland 13151f233ecSMark Cave-Ayland static uint64_t get_counter_value(MOS6522State *s, MOS6522Timer *ti) 13251f233ecSMark Cave-Ayland { 1339db70dacSEduardo Habkost MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s); 13451f233ecSMark Cave-Ayland 13551f233ecSMark Cave-Ayland if (ti->index == 0) { 13651f233ecSMark Cave-Ayland return mdc->get_timer1_counter_value(s, ti); 13751f233ecSMark Cave-Ayland } else { 13851f233ecSMark Cave-Ayland return mdc->get_timer2_counter_value(s, ti); 13951f233ecSMark Cave-Ayland } 14051f233ecSMark Cave-Ayland } 14151f233ecSMark Cave-Ayland 14251f233ecSMark Cave-Ayland static uint64_t get_load_time(MOS6522State *s, MOS6522Timer *ti) 14351f233ecSMark Cave-Ayland { 1449db70dacSEduardo Habkost MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s); 14551f233ecSMark Cave-Ayland 14651f233ecSMark Cave-Ayland if (ti->index == 0) { 14751f233ecSMark Cave-Ayland return mdc->get_timer1_load_time(s, ti); 14851f233ecSMark Cave-Ayland } else { 14951f233ecSMark Cave-Ayland return mdc->get_timer2_load_time(s, ti); 15051f233ecSMark Cave-Ayland } 15151f233ecSMark Cave-Ayland } 15251f233ecSMark Cave-Ayland 15351f233ecSMark Cave-Ayland static unsigned int get_counter(MOS6522State *s, MOS6522Timer *ti) 15451f233ecSMark Cave-Ayland { 15551f233ecSMark Cave-Ayland int64_t d; 15651f233ecSMark Cave-Ayland unsigned int counter; 15751f233ecSMark Cave-Ayland 15851f233ecSMark Cave-Ayland d = get_counter_value(s, ti); 15951f233ecSMark Cave-Ayland 16051f233ecSMark Cave-Ayland if (ti->index == 0) { 16151f233ecSMark Cave-Ayland /* the timer goes down from latch to -1 (period of latch + 2) */ 16251f233ecSMark Cave-Ayland if (d <= (ti->counter_value + 1)) { 16351f233ecSMark Cave-Ayland counter = (ti->counter_value - d) & 0xffff; 16451f233ecSMark Cave-Ayland } else { 16551f233ecSMark Cave-Ayland counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); 16651f233ecSMark Cave-Ayland counter = (ti->latch - counter) & 0xffff; 16751f233ecSMark Cave-Ayland } 16851f233ecSMark Cave-Ayland } else { 16951f233ecSMark Cave-Ayland counter = (ti->counter_value - d) & 0xffff; 17051f233ecSMark Cave-Ayland } 17151f233ecSMark Cave-Ayland return counter; 17251f233ecSMark Cave-Ayland } 17351f233ecSMark Cave-Ayland 17451f233ecSMark Cave-Ayland static void set_counter(MOS6522State *s, MOS6522Timer *ti, unsigned int val) 17551f233ecSMark Cave-Ayland { 17651f233ecSMark Cave-Ayland trace_mos6522_set_counter(1 + ti->index, val); 17751f233ecSMark Cave-Ayland ti->load_time = get_load_time(s, ti); 17851f233ecSMark Cave-Ayland ti->counter_value = val; 179cd8843ffSLaurent Vivier if (ti->index == 0) { 180cd8843ffSLaurent Vivier mos6522_timer1_update(s, ti, ti->load_time); 181cd8843ffSLaurent Vivier } else { 182cd8843ffSLaurent Vivier mos6522_timer2_update(s, ti, ti->load_time); 183cd8843ffSLaurent Vivier } 18451f233ecSMark Cave-Ayland } 18551f233ecSMark Cave-Ayland 18651f233ecSMark Cave-Ayland static int64_t get_next_irq_time(MOS6522State *s, MOS6522Timer *ti, 18751f233ecSMark Cave-Ayland int64_t current_time) 18851f233ecSMark Cave-Ayland { 18951f233ecSMark Cave-Ayland int64_t d, next_time; 19051f233ecSMark Cave-Ayland unsigned int counter; 19151f233ecSMark Cave-Ayland 1926cf80f90SLaurent Vivier if (ti->frequency == 0) { 1936cf80f90SLaurent Vivier return INT64_MAX; 1946cf80f90SLaurent Vivier } 1956cf80f90SLaurent Vivier 19651f233ecSMark Cave-Ayland /* current counter value */ 19751f233ecSMark Cave-Ayland d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time, 19851f233ecSMark Cave-Ayland ti->frequency, NANOSECONDS_PER_SECOND); 19951f233ecSMark Cave-Ayland 20051f233ecSMark Cave-Ayland /* the timer goes down from latch to -1 (period of latch + 2) */ 20151f233ecSMark Cave-Ayland if (d <= (ti->counter_value + 1)) { 20251f233ecSMark Cave-Ayland counter = (ti->counter_value - d) & 0xffff; 20351f233ecSMark Cave-Ayland } else { 20451f233ecSMark Cave-Ayland counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); 20551f233ecSMark Cave-Ayland counter = (ti->latch - counter) & 0xffff; 20651f233ecSMark Cave-Ayland } 20751f233ecSMark Cave-Ayland 20851f233ecSMark Cave-Ayland /* Note: we consider the irq is raised on 0 */ 20951f233ecSMark Cave-Ayland if (counter == 0xffff) { 21051f233ecSMark Cave-Ayland next_time = d + ti->latch + 1; 21151f233ecSMark Cave-Ayland } else if (counter == 0) { 21251f233ecSMark Cave-Ayland next_time = d + ti->latch + 2; 21351f233ecSMark Cave-Ayland } else { 21451f233ecSMark Cave-Ayland next_time = d + counter; 21551f233ecSMark Cave-Ayland } 21651f233ecSMark Cave-Ayland trace_mos6522_get_next_irq_time(ti->latch, d, next_time - d); 21751f233ecSMark Cave-Ayland next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, ti->frequency) + 21851f233ecSMark Cave-Ayland ti->load_time; 219cd8843ffSLaurent Vivier 22051f233ecSMark Cave-Ayland if (next_time <= current_time) { 22151f233ecSMark Cave-Ayland next_time = current_time + 1; 22251f233ecSMark Cave-Ayland } 22351f233ecSMark Cave-Ayland return next_time; 22451f233ecSMark Cave-Ayland } 22551f233ecSMark Cave-Ayland 226cd8843ffSLaurent Vivier static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti, 22751f233ecSMark Cave-Ayland int64_t current_time) 22851f233ecSMark Cave-Ayland { 22951f233ecSMark Cave-Ayland if (!ti->timer) { 23051f233ecSMark Cave-Ayland return; 23151f233ecSMark Cave-Ayland } 2326cf80f90SLaurent Vivier ti->next_irq_time = get_next_irq_time(s, ti, current_time); 233cd8843ffSLaurent Vivier if ((s->ier & T1_INT) == 0 || (s->acr & T1MODE) != T1MODE_CONT) { 234cd8843ffSLaurent Vivier timer_del(ti->timer); 235cd8843ffSLaurent Vivier } else { 236cd8843ffSLaurent Vivier timer_mod(ti->timer, ti->next_irq_time); 237cd8843ffSLaurent Vivier } 238cd8843ffSLaurent Vivier } 239cd8843ffSLaurent Vivier 240cd8843ffSLaurent Vivier static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti, 241cd8843ffSLaurent Vivier int64_t current_time) 242cd8843ffSLaurent Vivier { 243cd8843ffSLaurent Vivier if (!ti->timer) { 244cd8843ffSLaurent Vivier return; 245cd8843ffSLaurent Vivier } 2466cf80f90SLaurent Vivier ti->next_irq_time = get_next_irq_time(s, ti, current_time); 247cd8843ffSLaurent Vivier if ((s->ier & T2_INT) == 0) { 24851f233ecSMark Cave-Ayland timer_del(ti->timer); 24951f233ecSMark Cave-Ayland } else { 25051f233ecSMark Cave-Ayland timer_mod(ti->timer, ti->next_irq_time); 25151f233ecSMark Cave-Ayland } 25251f233ecSMark Cave-Ayland } 25351f233ecSMark Cave-Ayland 25451f233ecSMark Cave-Ayland static void mos6522_timer1(void *opaque) 25551f233ecSMark Cave-Ayland { 25651f233ecSMark Cave-Ayland MOS6522State *s = opaque; 25751f233ecSMark Cave-Ayland MOS6522Timer *ti = &s->timers[0]; 25851f233ecSMark Cave-Ayland 259cd8843ffSLaurent Vivier mos6522_timer1_update(s, ti, ti->next_irq_time); 26051f233ecSMark Cave-Ayland s->ifr |= T1_INT; 26151f233ecSMark Cave-Ayland mos6522_update_irq(s); 26251f233ecSMark Cave-Ayland } 26351f233ecSMark Cave-Ayland 26451f233ecSMark Cave-Ayland static void mos6522_timer2(void *opaque) 26551f233ecSMark Cave-Ayland { 26651f233ecSMark Cave-Ayland MOS6522State *s = opaque; 26751f233ecSMark Cave-Ayland MOS6522Timer *ti = &s->timers[1]; 26851f233ecSMark Cave-Ayland 269cd8843ffSLaurent Vivier mos6522_timer2_update(s, ti, ti->next_irq_time); 27051f233ecSMark Cave-Ayland s->ifr |= T2_INT; 27151f233ecSMark Cave-Ayland mos6522_update_irq(s); 27251f233ecSMark Cave-Ayland } 27351f233ecSMark Cave-Ayland 27451f233ecSMark Cave-Ayland static uint64_t mos6522_get_counter_value(MOS6522State *s, MOS6522Timer *ti) 27551f233ecSMark Cave-Ayland { 2764a4ff4c5SLaurent Vivier return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time, 27751f233ecSMark Cave-Ayland ti->frequency, NANOSECONDS_PER_SECOND); 27851f233ecSMark Cave-Ayland } 27951f233ecSMark Cave-Ayland 28051f233ecSMark Cave-Ayland static uint64_t mos6522_get_load_time(MOS6522State *s, MOS6522Timer *ti) 28151f233ecSMark Cave-Ayland { 28251f233ecSMark Cave-Ayland uint64_t load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 28351f233ecSMark Cave-Ayland 28451f233ecSMark Cave-Ayland return load_time; 28551f233ecSMark Cave-Ayland } 28651f233ecSMark Cave-Ayland 28751f233ecSMark Cave-Ayland static void mos6522_portA_write(MOS6522State *s) 28851f233ecSMark Cave-Ayland { 289c9bca798SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "portA_write unimplemented\n"); 29051f233ecSMark Cave-Ayland } 29151f233ecSMark Cave-Ayland 29251f233ecSMark Cave-Ayland static void mos6522_portB_write(MOS6522State *s) 29351f233ecSMark Cave-Ayland { 294c9bca798SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "portB_write unimplemented\n"); 29551f233ecSMark Cave-Ayland } 29651f233ecSMark Cave-Ayland 29751f233ecSMark Cave-Ayland uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size) 29851f233ecSMark Cave-Ayland { 29951f233ecSMark Cave-Ayland MOS6522State *s = opaque; 30051f233ecSMark Cave-Ayland uint32_t val; 301b793b4efSMark Cave-Ayland int ctrl; 302cd8843ffSLaurent Vivier int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 30351f233ecSMark Cave-Ayland 304cd8843ffSLaurent Vivier if (now >= s->timers[0].next_irq_time) { 305cd8843ffSLaurent Vivier mos6522_timer1_update(s, &s->timers[0], now); 306cd8843ffSLaurent Vivier s->ifr |= T1_INT; 307cd8843ffSLaurent Vivier } 308cd8843ffSLaurent Vivier if (now >= s->timers[1].next_irq_time) { 309cd8843ffSLaurent Vivier mos6522_timer2_update(s, &s->timers[1], now); 310cd8843ffSLaurent Vivier s->ifr |= T2_INT; 311cd8843ffSLaurent Vivier } 31251f233ecSMark Cave-Ayland switch (addr) { 31351f233ecSMark Cave-Ayland case VIA_REG_B: 31451f233ecSMark Cave-Ayland val = s->b; 315b793b4efSMark Cave-Ayland ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT; 316b793b4efSMark Cave-Ayland if (!(ctrl & C2_IND)) { 317b793b4efSMark Cave-Ayland s->ifr &= ~CB2_INT; 318b793b4efSMark Cave-Ayland } 319b793b4efSMark Cave-Ayland s->ifr &= ~CB1_INT; 320b793b4efSMark Cave-Ayland mos6522_update_irq(s); 32151f233ecSMark Cave-Ayland break; 32251f233ecSMark Cave-Ayland case VIA_REG_A: 323068fe58cSLaurent Vivier qemu_log_mask(LOG_UNIMP, "Read access to register A with handshake"); 324068fe58cSLaurent Vivier /* fall through */ 325068fe58cSLaurent Vivier case VIA_REG_ANH: 32651f233ecSMark Cave-Ayland val = s->a; 327b793b4efSMark Cave-Ayland ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT; 328b793b4efSMark Cave-Ayland if (!(ctrl & C2_IND)) { 329b793b4efSMark Cave-Ayland s->ifr &= ~CA2_INT; 330b793b4efSMark Cave-Ayland } 331b793b4efSMark Cave-Ayland s->ifr &= ~CA1_INT; 332b793b4efSMark Cave-Ayland mos6522_update_irq(s); 33351f233ecSMark Cave-Ayland break; 33451f233ecSMark Cave-Ayland case VIA_REG_DIRB: 33551f233ecSMark Cave-Ayland val = s->dirb; 33651f233ecSMark Cave-Ayland break; 33751f233ecSMark Cave-Ayland case VIA_REG_DIRA: 33851f233ecSMark Cave-Ayland val = s->dira; 33951f233ecSMark Cave-Ayland break; 34051f233ecSMark Cave-Ayland case VIA_REG_T1CL: 34151f233ecSMark Cave-Ayland val = get_counter(s, &s->timers[0]) & 0xff; 34251f233ecSMark Cave-Ayland s->ifr &= ~T1_INT; 34351f233ecSMark Cave-Ayland mos6522_update_irq(s); 34451f233ecSMark Cave-Ayland break; 34551f233ecSMark Cave-Ayland case VIA_REG_T1CH: 34651f233ecSMark Cave-Ayland val = get_counter(s, &s->timers[0]) >> 8; 34751f233ecSMark Cave-Ayland mos6522_update_irq(s); 34851f233ecSMark Cave-Ayland break; 34951f233ecSMark Cave-Ayland case VIA_REG_T1LL: 35051f233ecSMark Cave-Ayland val = s->timers[0].latch & 0xff; 35151f233ecSMark Cave-Ayland break; 35251f233ecSMark Cave-Ayland case VIA_REG_T1LH: 35351f233ecSMark Cave-Ayland /* XXX: check this */ 35451f233ecSMark Cave-Ayland val = (s->timers[0].latch >> 8) & 0xff; 35551f233ecSMark Cave-Ayland break; 35651f233ecSMark Cave-Ayland case VIA_REG_T2CL: 35751f233ecSMark Cave-Ayland val = get_counter(s, &s->timers[1]) & 0xff; 35851f233ecSMark Cave-Ayland s->ifr &= ~T2_INT; 35951f233ecSMark Cave-Ayland mos6522_update_irq(s); 36051f233ecSMark Cave-Ayland break; 36151f233ecSMark Cave-Ayland case VIA_REG_T2CH: 36251f233ecSMark Cave-Ayland val = get_counter(s, &s->timers[1]) >> 8; 36351f233ecSMark Cave-Ayland break; 36451f233ecSMark Cave-Ayland case VIA_REG_SR: 36551f233ecSMark Cave-Ayland val = s->sr; 3667f5d6517SMark Cave-Ayland s->ifr &= ~SR_INT; 36751f233ecSMark Cave-Ayland mos6522_update_irq(s); 36851f233ecSMark Cave-Ayland break; 36951f233ecSMark Cave-Ayland case VIA_REG_ACR: 37051f233ecSMark Cave-Ayland val = s->acr; 37151f233ecSMark Cave-Ayland break; 37251f233ecSMark Cave-Ayland case VIA_REG_PCR: 37351f233ecSMark Cave-Ayland val = s->pcr; 37451f233ecSMark Cave-Ayland break; 37551f233ecSMark Cave-Ayland case VIA_REG_IFR: 37651f233ecSMark Cave-Ayland val = s->ifr; 37751f233ecSMark Cave-Ayland if (s->ifr & s->ier) { 37851f233ecSMark Cave-Ayland val |= 0x80; 37951f233ecSMark Cave-Ayland } 38051f233ecSMark Cave-Ayland break; 38151f233ecSMark Cave-Ayland case VIA_REG_IER: 38251f233ecSMark Cave-Ayland val = s->ier | 0x80; 38351f233ecSMark Cave-Ayland break; 38451f233ecSMark Cave-Ayland default: 385068fe58cSLaurent Vivier g_assert_not_reached(); 38651f233ecSMark Cave-Ayland } 38751f233ecSMark Cave-Ayland 38851f233ecSMark Cave-Ayland if (addr != VIA_REG_IFR || val != 0) { 3896c726698SMark Cave-Ayland trace_mos6522_read(addr, mos6522_reg_names[addr], val); 39051f233ecSMark Cave-Ayland } 39151f233ecSMark Cave-Ayland 39251f233ecSMark Cave-Ayland return val; 39351f233ecSMark Cave-Ayland } 39451f233ecSMark Cave-Ayland 39551f233ecSMark Cave-Ayland void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 39651f233ecSMark Cave-Ayland { 39751f233ecSMark Cave-Ayland MOS6522State *s = opaque; 3989db70dacSEduardo Habkost MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s); 399b793b4efSMark Cave-Ayland int ctrl; 40051f233ecSMark Cave-Ayland 4016c726698SMark Cave-Ayland trace_mos6522_write(addr, mos6522_reg_names[addr], val); 40251f233ecSMark Cave-Ayland 40351f233ecSMark Cave-Ayland switch (addr) { 40451f233ecSMark Cave-Ayland case VIA_REG_B: 40551f233ecSMark Cave-Ayland s->b = (s->b & ~s->dirb) | (val & s->dirb); 40651f233ecSMark Cave-Ayland mdc->portB_write(s); 407b793b4efSMark Cave-Ayland ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT; 408b793b4efSMark Cave-Ayland if (!(ctrl & C2_IND)) { 409b793b4efSMark Cave-Ayland s->ifr &= ~CB2_INT; 410b793b4efSMark Cave-Ayland } 411b793b4efSMark Cave-Ayland s->ifr &= ~CB1_INT; 412b793b4efSMark Cave-Ayland mos6522_update_irq(s); 41351f233ecSMark Cave-Ayland break; 41451f233ecSMark Cave-Ayland case VIA_REG_A: 415068fe58cSLaurent Vivier qemu_log_mask(LOG_UNIMP, "Write access to register A with handshake"); 416068fe58cSLaurent Vivier /* fall through */ 417068fe58cSLaurent Vivier case VIA_REG_ANH: 41851f233ecSMark Cave-Ayland s->a = (s->a & ~s->dira) | (val & s->dira); 41951f233ecSMark Cave-Ayland mdc->portA_write(s); 420b793b4efSMark Cave-Ayland ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT; 421b793b4efSMark Cave-Ayland if (!(ctrl & C2_IND)) { 422b793b4efSMark Cave-Ayland s->ifr &= ~CA2_INT; 423b793b4efSMark Cave-Ayland } 424b793b4efSMark Cave-Ayland s->ifr &= ~CA1_INT; 425b793b4efSMark Cave-Ayland mos6522_update_irq(s); 42651f233ecSMark Cave-Ayland break; 42751f233ecSMark Cave-Ayland case VIA_REG_DIRB: 42851f233ecSMark Cave-Ayland s->dirb = val; 42951f233ecSMark Cave-Ayland break; 43051f233ecSMark Cave-Ayland case VIA_REG_DIRA: 43151f233ecSMark Cave-Ayland s->dira = val; 43251f233ecSMark Cave-Ayland break; 43351f233ecSMark Cave-Ayland case VIA_REG_T1CL: 43451f233ecSMark Cave-Ayland s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; 435cd8843ffSLaurent Vivier mos6522_timer1_update(s, &s->timers[0], 43651f233ecSMark Cave-Ayland qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 43751f233ecSMark Cave-Ayland break; 43851f233ecSMark Cave-Ayland case VIA_REG_T1CH: 43951f233ecSMark Cave-Ayland s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); 44051f233ecSMark Cave-Ayland s->ifr &= ~T1_INT; 44151f233ecSMark Cave-Ayland set_counter(s, &s->timers[0], s->timers[0].latch); 44251f233ecSMark Cave-Ayland break; 44351f233ecSMark Cave-Ayland case VIA_REG_T1LL: 44451f233ecSMark Cave-Ayland s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; 445cd8843ffSLaurent Vivier mos6522_timer1_update(s, &s->timers[0], 44651f233ecSMark Cave-Ayland qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 44751f233ecSMark Cave-Ayland break; 44851f233ecSMark Cave-Ayland case VIA_REG_T1LH: 44951f233ecSMark Cave-Ayland s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); 45051f233ecSMark Cave-Ayland s->ifr &= ~T1_INT; 451cd8843ffSLaurent Vivier mos6522_timer1_update(s, &s->timers[0], 45251f233ecSMark Cave-Ayland qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 45351f233ecSMark Cave-Ayland break; 45451f233ecSMark Cave-Ayland case VIA_REG_T2CL: 45551f233ecSMark Cave-Ayland s->timers[1].latch = (s->timers[1].latch & 0xff00) | val; 45651f233ecSMark Cave-Ayland break; 45751f233ecSMark Cave-Ayland case VIA_REG_T2CH: 45851f233ecSMark Cave-Ayland /* To ensure T2 generates an interrupt on zero crossing with the 45951f233ecSMark Cave-Ayland common timer code, write the value directly from the latch to 46051f233ecSMark Cave-Ayland the counter */ 46151f233ecSMark Cave-Ayland s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8); 46251f233ecSMark Cave-Ayland s->ifr &= ~T2_INT; 46351f233ecSMark Cave-Ayland set_counter(s, &s->timers[1], s->timers[1].latch); 46451f233ecSMark Cave-Ayland break; 46551f233ecSMark Cave-Ayland case VIA_REG_SR: 46651f233ecSMark Cave-Ayland s->sr = val; 46751f233ecSMark Cave-Ayland break; 46851f233ecSMark Cave-Ayland case VIA_REG_ACR: 46951f233ecSMark Cave-Ayland s->acr = val; 470cd8843ffSLaurent Vivier mos6522_timer1_update(s, &s->timers[0], 47151f233ecSMark Cave-Ayland qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 47251f233ecSMark Cave-Ayland break; 47351f233ecSMark Cave-Ayland case VIA_REG_PCR: 47451f233ecSMark Cave-Ayland s->pcr = val; 47551f233ecSMark Cave-Ayland break; 47651f233ecSMark Cave-Ayland case VIA_REG_IFR: 47751f233ecSMark Cave-Ayland /* reset bits */ 47851f233ecSMark Cave-Ayland s->ifr &= ~val; 47951f233ecSMark Cave-Ayland mos6522_update_irq(s); 48051f233ecSMark Cave-Ayland break; 48151f233ecSMark Cave-Ayland case VIA_REG_IER: 48251f233ecSMark Cave-Ayland if (val & IER_SET) { 48351f233ecSMark Cave-Ayland /* set bits */ 48451f233ecSMark Cave-Ayland s->ier |= val & 0x7f; 48551f233ecSMark Cave-Ayland } else { 48651f233ecSMark Cave-Ayland /* reset bits */ 48751f233ecSMark Cave-Ayland s->ier &= ~val; 48851f233ecSMark Cave-Ayland } 48951f233ecSMark Cave-Ayland mos6522_update_irq(s); 490cd8843ffSLaurent Vivier /* if IER is modified starts needed timers */ 491cd8843ffSLaurent Vivier mos6522_timer1_update(s, &s->timers[0], 492cd8843ffSLaurent Vivier qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 493cd8843ffSLaurent Vivier mos6522_timer2_update(s, &s->timers[1], 494cd8843ffSLaurent Vivier qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 49551f233ecSMark Cave-Ayland break; 49651f233ecSMark Cave-Ayland default: 497068fe58cSLaurent Vivier g_assert_not_reached(); 49851f233ecSMark Cave-Ayland } 49951f233ecSMark Cave-Ayland } 50051f233ecSMark Cave-Ayland 501409e9f71SMark Cave-Ayland static int qmp_x_query_via_foreach(Object *obj, void *opaque) 502409e9f71SMark Cave-Ayland { 503409e9f71SMark Cave-Ayland GString *buf = opaque; 504409e9f71SMark Cave-Ayland 505409e9f71SMark Cave-Ayland if (object_dynamic_cast(obj, TYPE_MOS6522)) { 506409e9f71SMark Cave-Ayland MOS6522State *s = MOS6522(obj); 507409e9f71SMark Cave-Ayland int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 508409e9f71SMark Cave-Ayland uint16_t t1counter = get_counter(s, &s->timers[0]); 509409e9f71SMark Cave-Ayland uint16_t t2counter = get_counter(s, &s->timers[1]); 510409e9f71SMark Cave-Ayland 511409e9f71SMark Cave-Ayland g_string_append_printf(buf, "%s:\n", object_get_typename(obj)); 512409e9f71SMark Cave-Ayland 513409e9f71SMark Cave-Ayland g_string_append_printf(buf, " Registers:\n"); 514409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 515409e9f71SMark Cave-Ayland mos6522_reg_names[0], s->b); 516409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 517409e9f71SMark Cave-Ayland mos6522_reg_names[1], s->a); 518409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 519409e9f71SMark Cave-Ayland mos6522_reg_names[2], s->dirb); 520409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 521409e9f71SMark Cave-Ayland mos6522_reg_names[3], s->dira); 522409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 523409e9f71SMark Cave-Ayland mos6522_reg_names[4], t1counter & 0xff); 524409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 525409e9f71SMark Cave-Ayland mos6522_reg_names[5], t1counter >> 8); 526409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 527409e9f71SMark Cave-Ayland mos6522_reg_names[6], 528409e9f71SMark Cave-Ayland s->timers[0].latch & 0xff); 529409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 530409e9f71SMark Cave-Ayland mos6522_reg_names[7], 531409e9f71SMark Cave-Ayland s->timers[0].latch >> 8); 532409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 533409e9f71SMark Cave-Ayland mos6522_reg_names[8], t2counter & 0xff); 534409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 535409e9f71SMark Cave-Ayland mos6522_reg_names[9], t2counter >> 8); 536409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 537409e9f71SMark Cave-Ayland mos6522_reg_names[10], s->sr); 538409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 539409e9f71SMark Cave-Ayland mos6522_reg_names[11], s->acr); 540409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 541409e9f71SMark Cave-Ayland mos6522_reg_names[12], s->pcr); 542409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 543409e9f71SMark Cave-Ayland mos6522_reg_names[13], s->ifr); 544409e9f71SMark Cave-Ayland g_string_append_printf(buf, " %-*s: 0x%x\n", 4, 545409e9f71SMark Cave-Ayland mos6522_reg_names[14], s->ier); 546409e9f71SMark Cave-Ayland 547409e9f71SMark Cave-Ayland g_string_append_printf(buf, " Timers:\n"); 548409e9f71SMark Cave-Ayland g_string_append_printf(buf, " Using current time now(ns)=%"PRId64 549409e9f71SMark Cave-Ayland "\n", now); 550409e9f71SMark Cave-Ayland g_string_append_printf(buf, " T1 freq(hz)=%"PRId64 551409e9f71SMark Cave-Ayland " mode=%s" 552409e9f71SMark Cave-Ayland " counter=0x%x" 553409e9f71SMark Cave-Ayland " latch=0x%x\n" 554409e9f71SMark Cave-Ayland " load_time(ns)=%"PRId64 555409e9f71SMark Cave-Ayland " next_irq_time(ns)=%"PRId64 "\n", 556409e9f71SMark Cave-Ayland s->timers[0].frequency, 557409e9f71SMark Cave-Ayland ((s->acr & T1MODE) == T1MODE_CONT) ? "continuous" 558409e9f71SMark Cave-Ayland : "one-shot", 559409e9f71SMark Cave-Ayland t1counter, 560409e9f71SMark Cave-Ayland s->timers[0].latch, 561409e9f71SMark Cave-Ayland s->timers[0].load_time, 562409e9f71SMark Cave-Ayland get_next_irq_time(s, &s->timers[0], now)); 563409e9f71SMark Cave-Ayland g_string_append_printf(buf, " T2 freq(hz)=%"PRId64 564409e9f71SMark Cave-Ayland " mode=%s" 565409e9f71SMark Cave-Ayland " counter=0x%x" 566409e9f71SMark Cave-Ayland " latch=0x%x\n" 567409e9f71SMark Cave-Ayland " load_time(ns)=%"PRId64 568409e9f71SMark Cave-Ayland " next_irq_time(ns)=%"PRId64 "\n", 569409e9f71SMark Cave-Ayland s->timers[1].frequency, 570409e9f71SMark Cave-Ayland "one-shot", 571409e9f71SMark Cave-Ayland t2counter, 572409e9f71SMark Cave-Ayland s->timers[1].latch, 573409e9f71SMark Cave-Ayland s->timers[1].load_time, 574409e9f71SMark Cave-Ayland get_next_irq_time(s, &s->timers[1], now)); 575409e9f71SMark Cave-Ayland } 576409e9f71SMark Cave-Ayland 577409e9f71SMark Cave-Ayland return 0; 578409e9f71SMark Cave-Ayland } 579409e9f71SMark Cave-Ayland 580409e9f71SMark Cave-Ayland static HumanReadableText *qmp_x_query_via(Error **errp) 581409e9f71SMark Cave-Ayland { 582409e9f71SMark Cave-Ayland g_autoptr(GString) buf = g_string_new(""); 583409e9f71SMark Cave-Ayland 584409e9f71SMark Cave-Ayland object_child_foreach_recursive(object_get_root(), 585409e9f71SMark Cave-Ayland qmp_x_query_via_foreach, buf); 586409e9f71SMark Cave-Ayland 587409e9f71SMark Cave-Ayland return human_readable_text_from_str(buf); 588409e9f71SMark Cave-Ayland } 589409e9f71SMark Cave-Ayland 590409e9f71SMark Cave-Ayland void hmp_info_via(Monitor *mon, const QDict *qdict) 591409e9f71SMark Cave-Ayland { 592409e9f71SMark Cave-Ayland Error *err = NULL; 593409e9f71SMark Cave-Ayland g_autoptr(HumanReadableText) info = qmp_x_query_via(&err); 594409e9f71SMark Cave-Ayland 595409e9f71SMark Cave-Ayland if (hmp_handle_error(mon, err)) { 596409e9f71SMark Cave-Ayland return; 597409e9f71SMark Cave-Ayland } 598bf0c50d4SAlex Bennée monitor_puts(mon, info->human_readable_text); 599409e9f71SMark Cave-Ayland } 600409e9f71SMark Cave-Ayland 60151f233ecSMark Cave-Ayland static const MemoryRegionOps mos6522_ops = { 60251f233ecSMark Cave-Ayland .read = mos6522_read, 60351f233ecSMark Cave-Ayland .write = mos6522_write, 60451f233ecSMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 60551f233ecSMark Cave-Ayland .valid = { 60651f233ecSMark Cave-Ayland .min_access_size = 1, 60751f233ecSMark Cave-Ayland .max_access_size = 1, 60851f233ecSMark Cave-Ayland }, 60951f233ecSMark Cave-Ayland }; 61051f233ecSMark Cave-Ayland 61151f233ecSMark Cave-Ayland static const VMStateDescription vmstate_mos6522_timer = { 61251f233ecSMark Cave-Ayland .name = "mos6522_timer", 61351f233ecSMark Cave-Ayland .version_id = 0, 61451f233ecSMark Cave-Ayland .minimum_version_id = 0, 61551f233ecSMark Cave-Ayland .fields = (VMStateField[]) { 61651f233ecSMark Cave-Ayland VMSTATE_UINT16(latch, MOS6522Timer), 61751f233ecSMark Cave-Ayland VMSTATE_UINT16(counter_value, MOS6522Timer), 61851f233ecSMark Cave-Ayland VMSTATE_INT64(load_time, MOS6522Timer), 61951f233ecSMark Cave-Ayland VMSTATE_INT64(next_irq_time, MOS6522Timer), 6203431bdf5SMark Cave-Ayland VMSTATE_TIMER_PTR(timer, MOS6522Timer), 62151f233ecSMark Cave-Ayland VMSTATE_END_OF_LIST() 62251f233ecSMark Cave-Ayland } 62351f233ecSMark Cave-Ayland }; 62451f233ecSMark Cave-Ayland 6252e3e5c7eSMark Cave-Ayland const VMStateDescription vmstate_mos6522 = { 62651f233ecSMark Cave-Ayland .name = "mos6522", 627d4454e41SMark Cave-Ayland .version_id = 1, 628d4454e41SMark Cave-Ayland .minimum_version_id = 1, 62951f233ecSMark Cave-Ayland .fields = (VMStateField[]) { 63051f233ecSMark Cave-Ayland VMSTATE_UINT8(a, MOS6522State), 63151f233ecSMark Cave-Ayland VMSTATE_UINT8(b, MOS6522State), 63251f233ecSMark Cave-Ayland VMSTATE_UINT8(dira, MOS6522State), 63351f233ecSMark Cave-Ayland VMSTATE_UINT8(dirb, MOS6522State), 63451f233ecSMark Cave-Ayland VMSTATE_UINT8(sr, MOS6522State), 63551f233ecSMark Cave-Ayland VMSTATE_UINT8(acr, MOS6522State), 63651f233ecSMark Cave-Ayland VMSTATE_UINT8(pcr, MOS6522State), 63751f233ecSMark Cave-Ayland VMSTATE_UINT8(ifr, MOS6522State), 63851f233ecSMark Cave-Ayland VMSTATE_UINT8(ier, MOS6522State), 639d4454e41SMark Cave-Ayland VMSTATE_UINT8(last_irq_levels, MOS6522State), 64072ee08cfSMark Cave-Ayland VMSTATE_STRUCT_ARRAY(timers, MOS6522State, 2, 0, 64151f233ecSMark Cave-Ayland vmstate_mos6522_timer, MOS6522Timer), 64251f233ecSMark Cave-Ayland VMSTATE_END_OF_LIST() 64351f233ecSMark Cave-Ayland } 64451f233ecSMark Cave-Ayland }; 64551f233ecSMark Cave-Ayland 646*8bdaed0fSPeter Maydell static void mos6522_reset_hold(Object *obj) 64751f233ecSMark Cave-Ayland { 648*8bdaed0fSPeter Maydell MOS6522State *s = MOS6522(obj); 64951f233ecSMark Cave-Ayland 65051f233ecSMark Cave-Ayland s->b = 0; 65151f233ecSMark Cave-Ayland s->a = 0; 65251f233ecSMark Cave-Ayland s->dirb = 0xff; 65351f233ecSMark Cave-Ayland s->dira = 0; 65451f233ecSMark Cave-Ayland s->sr = 0; 65551f233ecSMark Cave-Ayland s->acr = 0; 65651f233ecSMark Cave-Ayland s->pcr = 0; 65751f233ecSMark Cave-Ayland s->ifr = 0; 65851f233ecSMark Cave-Ayland s->ier = 0; 65951f233ecSMark Cave-Ayland /* s->ier = T1_INT | SR_INT; */ 66051f233ecSMark Cave-Ayland 661d638fd5cSMark Cave-Ayland s->timers[0].frequency = s->frequency; 66251f233ecSMark Cave-Ayland s->timers[0].latch = 0xffff; 66351f233ecSMark Cave-Ayland set_counter(s, &s->timers[0], 0xffff); 664cd8843ffSLaurent Vivier timer_del(s->timers[0].timer); 66551f233ecSMark Cave-Ayland 66651f233ecSMark Cave-Ayland s->timers[1].frequency = s->frequency; 667d638fd5cSMark Cave-Ayland s->timers[1].latch = 0xffff; 668cd8843ffSLaurent Vivier timer_del(s->timers[1].timer); 66951f233ecSMark Cave-Ayland } 67051f233ecSMark Cave-Ayland 67151f233ecSMark Cave-Ayland static void mos6522_init(Object *obj) 67251f233ecSMark Cave-Ayland { 67351f233ecSMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 67451f233ecSMark Cave-Ayland MOS6522State *s = MOS6522(obj); 67551f233ecSMark Cave-Ayland int i; 67651f233ecSMark Cave-Ayland 6776c726698SMark Cave-Ayland memory_region_init_io(&s->mem, obj, &mos6522_ops, s, "mos6522", 6786c726698SMark Cave-Ayland MOS6522_NUM_REGS); 67951f233ecSMark Cave-Ayland sysbus_init_mmio(sbd, &s->mem); 68051f233ecSMark Cave-Ayland sysbus_init_irq(sbd, &s->irq); 68151f233ecSMark Cave-Ayland 68251f233ecSMark Cave-Ayland for (i = 0; i < ARRAY_SIZE(s->timers); i++) { 68351f233ecSMark Cave-Ayland s->timers[i].index = i; 68451f233ecSMark Cave-Ayland } 68551f233ecSMark Cave-Ayland 68651f233ecSMark Cave-Ayland s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer1, s); 68751f233ecSMark Cave-Ayland s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer2, s); 688ebe5bca2SMark Cave-Ayland 689ebe5bca2SMark Cave-Ayland qdev_init_gpio_in(DEVICE(obj), mos6522_set_irq, VIA_NUM_INTS); 69051f233ecSMark Cave-Ayland } 69151f233ecSMark Cave-Ayland 6923d64fddeSGan Qixin static void mos6522_finalize(Object *obj) 6933d64fddeSGan Qixin { 6943d64fddeSGan Qixin MOS6522State *s = MOS6522(obj); 6953d64fddeSGan Qixin 6963d64fddeSGan Qixin timer_free(s->timers[0].timer); 6973d64fddeSGan Qixin timer_free(s->timers[1].timer); 6983d64fddeSGan Qixin } 6993d64fddeSGan Qixin 70051f233ecSMark Cave-Ayland static Property mos6522_properties[] = { 70151f233ecSMark Cave-Ayland DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0), 70251f233ecSMark Cave-Ayland DEFINE_PROP_END_OF_LIST() 70351f233ecSMark Cave-Ayland }; 70451f233ecSMark Cave-Ayland 70551f233ecSMark Cave-Ayland static void mos6522_class_init(ObjectClass *oc, void *data) 70651f233ecSMark Cave-Ayland { 70751f233ecSMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(oc); 708*8bdaed0fSPeter Maydell ResettableClass *rc = RESETTABLE_CLASS(oc); 7099db70dacSEduardo Habkost MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); 71051f233ecSMark Cave-Ayland 711*8bdaed0fSPeter Maydell rc->phases.hold = mos6522_reset_hold; 71251f233ecSMark Cave-Ayland dc->vmsd = &vmstate_mos6522; 7134f67d30bSMarc-André Lureau device_class_set_props(dc, mos6522_properties); 71451f233ecSMark Cave-Ayland mdc->portB_write = mos6522_portB_write; 71551f233ecSMark Cave-Ayland mdc->portA_write = mos6522_portA_write; 71651f233ecSMark Cave-Ayland mdc->get_timer1_counter_value = mos6522_get_counter_value; 71751f233ecSMark Cave-Ayland mdc->get_timer2_counter_value = mos6522_get_counter_value; 71851f233ecSMark Cave-Ayland mdc->get_timer1_load_time = mos6522_get_load_time; 71951f233ecSMark Cave-Ayland mdc->get_timer2_load_time = mos6522_get_load_time; 72051f233ecSMark Cave-Ayland } 72151f233ecSMark Cave-Ayland 72251f233ecSMark Cave-Ayland static const TypeInfo mos6522_type_info = { 72351f233ecSMark Cave-Ayland .name = TYPE_MOS6522, 72451f233ecSMark Cave-Ayland .parent = TYPE_SYS_BUS_DEVICE, 72551f233ecSMark Cave-Ayland .instance_size = sizeof(MOS6522State), 72651f233ecSMark Cave-Ayland .instance_init = mos6522_init, 7273d64fddeSGan Qixin .instance_finalize = mos6522_finalize, 72851f233ecSMark Cave-Ayland .abstract = true, 72951f233ecSMark Cave-Ayland .class_size = sizeof(MOS6522DeviceClass), 73051f233ecSMark Cave-Ayland .class_init = mos6522_class_init, 73151f233ecSMark Cave-Ayland }; 73251f233ecSMark Cave-Ayland 73351f233ecSMark Cave-Ayland static void mos6522_register_types(void) 73451f233ecSMark Cave-Ayland { 73551f233ecSMark Cave-Ayland type_register_static(&mos6522_type_info); 73651f233ecSMark Cave-Ayland } 73751f233ecSMark Cave-Ayland 73851f233ecSMark Cave-Ayland type_init(mos6522_register_types) 739