qemu/hw/misc/mos6522.c
<<
>>
Prefs
   1/*
   2 * QEMU MOS6522 VIA emulation
   3 *
   4 * Copyright (c) 2004-2007 Fabrice Bellard
   5 * Copyright (c) 2007 Jocelyn Mayer
   6 * Copyright (c) 2018 Mark Cave-Ayland
   7 *
   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:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  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
  24 * THE SOFTWARE.
  25 */
  26
  27#include "qemu/osdep.h"
  28#include "hw/input/adb.h"
  29#include "hw/irq.h"
  30#include "hw/misc/mos6522.h"
  31#include "hw/qdev-properties.h"
  32#include "migration/vmstate.h"
  33#include "monitor/monitor.h"
  34#include "monitor/hmp.h"
  35#include "qapi/type-helpers.h"
  36#include "qemu/timer.h"
  37#include "qemu/cutils.h"
  38#include "qemu/log.h"
  39#include "qemu/module.h"
  40#include "trace.h"
  41
  42
  43static const char *mos6522_reg_names[MOS6522_NUM_REGS] = {
  44    "ORB", "ORA", "DDRB", "DDRA", "T1CL", "T1CH", "T1LL", "T1LH",
  45    "T2CL", "T2CH", "SR", "ACR", "PCR", "IFR", "IER", "ANH"
  46};
  47
  48/* XXX: implement all timer modes */
  49
  50static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti,
  51                                  int64_t current_time);
  52static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti,
  53                                  int64_t current_time);
  54
  55static void mos6522_update_irq(MOS6522State *s)
  56{
  57    if (s->ifr & s->ier) {
  58        qemu_irq_raise(s->irq);
  59    } else {
  60        qemu_irq_lower(s->irq);
  61    }
  62}
  63
  64static void mos6522_set_irq(void *opaque, int n, int level)
  65{
  66    MOS6522State *s = MOS6522(opaque);
  67    int last_level = !!(s->last_irq_levels & (1 << n));
  68    uint8_t last_ifr = s->ifr;
  69    bool positive_edge = true;
  70    int ctrl;
  71
  72    /*
  73     * SR_INT is managed by mos6522 instances and cleared upon SR
  74     * read. It is only the external CA1/2 and CB1/2 lines that
  75     * are edge-triggered and latched in IFR
  76     */
  77    if (n != SR_INT_BIT && level == last_level) {
  78        return;
  79    }
  80
  81    /* Detect negative edge trigger */
  82    if (last_level == 1 && level == 0) {
  83        positive_edge = false;
  84    }
  85
  86    switch (n) {
  87    case CA2_INT_BIT:
  88        ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT;
  89        if ((positive_edge && (ctrl & C2_POS)) ||
  90             (!positive_edge && !(ctrl & C2_POS))) {
  91            s->ifr |= 1 << n;
  92        }
  93        break;
  94    case CA1_INT_BIT:
  95        ctrl = (s->pcr & CA1_CTRL_MASK) >> CA1_CTRL_SHIFT;
  96        if ((positive_edge && (ctrl & C1_POS)) ||
  97             (!positive_edge && !(ctrl & C1_POS))) {
  98            s->ifr |= 1 << n;
  99        }
 100        break;
 101    case SR_INT_BIT:
 102        s->ifr |= 1 << n;
 103        break;
 104    case CB2_INT_BIT:
 105        ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT;
 106        if ((positive_edge && (ctrl & C2_POS)) ||
 107             (!positive_edge && !(ctrl & C2_POS))) {
 108            s->ifr |= 1 << n;
 109        }
 110        break;
 111    case CB1_INT_BIT:
 112        ctrl = (s->pcr & CB1_CTRL_MASK) >> CB1_CTRL_SHIFT;
 113        if ((positive_edge && (ctrl & C1_POS)) ||
 114             (!positive_edge && !(ctrl & C1_POS))) {
 115            s->ifr |= 1 << n;
 116        }
 117        break;
 118    }
 119
 120    if (s->ifr != last_ifr) {
 121        mos6522_update_irq(s);
 122    }
 123
 124    if (level) {
 125        s->last_irq_levels |= 1 << n;
 126    } else {
 127        s->last_irq_levels &= ~(1 << n);
 128    }
 129}
 130
 131static uint64_t get_counter_value(MOS6522State *s, MOS6522Timer *ti)
 132{
 133    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
 134
 135    if (ti->index == 0) {
 136        return mdc->get_timer1_counter_value(s, ti);
 137    } else {
 138        return mdc->get_timer2_counter_value(s, ti);
 139    }
 140}
 141
 142static uint64_t get_load_time(MOS6522State *s, MOS6522Timer *ti)
 143{
 144    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
 145
 146    if (ti->index == 0) {
 147        return mdc->get_timer1_load_time(s, ti);
 148    } else {
 149        return mdc->get_timer2_load_time(s, ti);
 150    }
 151}
 152
 153static unsigned int get_counter(MOS6522State *s, MOS6522Timer *ti)
 154{
 155    int64_t d;
 156    unsigned int counter;
 157
 158    d = get_counter_value(s, ti);
 159
 160    if (ti->index == 0) {
 161        /* the timer goes down from latch to -1 (period of latch + 2) */
 162        if (d <= (ti->counter_value + 1)) {
 163            counter = (ti->counter_value - d) & 0xffff;
 164        } else {
 165            counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
 166            counter = (ti->latch - counter) & 0xffff;
 167        }
 168    } else {
 169        counter = (ti->counter_value - d) & 0xffff;
 170    }
 171    return counter;
 172}
 173
 174static void set_counter(MOS6522State *s, MOS6522Timer *ti, unsigned int val)
 175{
 176    trace_mos6522_set_counter(1 + ti->index, val);
 177    ti->load_time = get_load_time(s, ti);
 178    ti->counter_value = val;
 179    if (ti->index == 0) {
 180        mos6522_timer1_update(s, ti, ti->load_time);
 181    } else {
 182        mos6522_timer2_update(s, ti, ti->load_time);
 183    }
 184}
 185
 186static int64_t get_next_irq_time(MOS6522State *s, MOS6522Timer *ti,
 187                                 int64_t current_time)
 188{
 189    int64_t d, next_time;
 190    unsigned int counter;
 191
 192    if (ti->frequency == 0) {
 193        return INT64_MAX;
 194    }
 195
 196    /* current counter value */
 197    d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
 198                 ti->frequency, NANOSECONDS_PER_SECOND);
 199
 200    /* the timer goes down from latch to -1 (period of latch + 2) */
 201    if (d <= (ti->counter_value + 1)) {
 202        counter = (ti->counter_value - d) & 0xffff;
 203    } else {
 204        counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
 205        counter = (ti->latch - counter) & 0xffff;
 206    }
 207
 208    /* Note: we consider the irq is raised on 0 */
 209    if (counter == 0xffff) {
 210        next_time = d + ti->latch + 1;
 211    } else if (counter == 0) {
 212        next_time = d + ti->latch + 2;
 213    } else {
 214        next_time = d + counter;
 215    }
 216    trace_mos6522_get_next_irq_time(ti->latch, d, next_time - d);
 217    next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, ti->frequency) +
 218                         ti->load_time;
 219
 220    if (next_time <= current_time) {
 221        next_time = current_time + 1;
 222    }
 223    return next_time;
 224}
 225
 226static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti,
 227                                 int64_t current_time)
 228{
 229    if (!ti->timer) {
 230        return;
 231    }
 232    ti->next_irq_time = get_next_irq_time(s, ti, current_time);
 233    if ((s->ier & T1_INT) == 0 || (s->acr & T1MODE) != T1MODE_CONT) {
 234        timer_del(ti->timer);
 235    } else {
 236        timer_mod(ti->timer, ti->next_irq_time);
 237    }
 238}
 239
 240static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti,
 241                                 int64_t current_time)
 242{
 243    if (!ti->timer) {
 244        return;
 245    }
 246    ti->next_irq_time = get_next_irq_time(s, ti, current_time);
 247    if ((s->ier & T2_INT) == 0) {
 248        timer_del(ti->timer);
 249    } else {
 250        timer_mod(ti->timer, ti->next_irq_time);
 251    }
 252}
 253
 254static void mos6522_timer1(void *opaque)
 255{
 256    MOS6522State *s = opaque;
 257    MOS6522Timer *ti = &s->timers[0];
 258
 259    mos6522_timer1_update(s, ti, ti->next_irq_time);
 260    s->ifr |= T1_INT;
 261    mos6522_update_irq(s);
 262}
 263
 264static void mos6522_timer2(void *opaque)
 265{
 266    MOS6522State *s = opaque;
 267    MOS6522Timer *ti = &s->timers[1];
 268
 269    mos6522_timer2_update(s, ti, ti->next_irq_time);
 270    s->ifr |= T2_INT;
 271    mos6522_update_irq(s);
 272}
 273
 274static uint64_t mos6522_get_counter_value(MOS6522State *s, MOS6522Timer *ti)
 275{
 276    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
 277                    ti->frequency, NANOSECONDS_PER_SECOND);
 278}
 279
 280static uint64_t mos6522_get_load_time(MOS6522State *s, MOS6522Timer *ti)
 281{
 282    uint64_t load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 283
 284    return load_time;
 285}
 286
 287static void mos6522_portA_write(MOS6522State *s)
 288{
 289    qemu_log_mask(LOG_UNIMP, "portA_write unimplemented\n");
 290}
 291
 292static void mos6522_portB_write(MOS6522State *s)
 293{
 294    qemu_log_mask(LOG_UNIMP, "portB_write unimplemented\n");
 295}
 296
 297uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
 298{
 299    MOS6522State *s = opaque;
 300    uint32_t val;
 301    int ctrl;
 302    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 303
 304    if (now >= s->timers[0].next_irq_time) {
 305        mos6522_timer1_update(s, &s->timers[0], now);
 306        s->ifr |= T1_INT;
 307    }
 308    if (now >= s->timers[1].next_irq_time) {
 309        mos6522_timer2_update(s, &s->timers[1], now);
 310        s->ifr |= T2_INT;
 311    }
 312    switch (addr) {
 313    case VIA_REG_B:
 314        val = s->b;
 315        ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT;
 316        if (!(ctrl & C2_IND)) {
 317            s->ifr &= ~CB2_INT;
 318        }
 319        s->ifr &= ~CB1_INT;
 320        mos6522_update_irq(s);
 321        break;
 322    case VIA_REG_A:
 323       qemu_log_mask(LOG_UNIMP, "Read access to register A with handshake");
 324       /* fall through */
 325    case VIA_REG_ANH:
 326        val = s->a;
 327        ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT;
 328        if (!(ctrl & C2_IND)) {
 329            s->ifr &= ~CA2_INT;
 330        }
 331        s->ifr &= ~CA1_INT;
 332        mos6522_update_irq(s);
 333        break;
 334    case VIA_REG_DIRB:
 335        val = s->dirb;
 336        break;
 337    case VIA_REG_DIRA:
 338        val = s->dira;
 339        break;
 340    case VIA_REG_T1CL:
 341        val = get_counter(s, &s->timers[0]) & 0xff;
 342        s->ifr &= ~T1_INT;
 343        mos6522_update_irq(s);
 344        break;
 345    case VIA_REG_T1CH:
 346        val = get_counter(s, &s->timers[0]) >> 8;
 347        mos6522_update_irq(s);
 348        break;
 349    case VIA_REG_T1LL:
 350        val = s->timers[0].latch & 0xff;
 351        break;
 352    case VIA_REG_T1LH:
 353        /* XXX: check this */
 354        val = (s->timers[0].latch >> 8) & 0xff;
 355        break;
 356    case VIA_REG_T2CL:
 357        val = get_counter(s, &s->timers[1]) & 0xff;
 358        s->ifr &= ~T2_INT;
 359        mos6522_update_irq(s);
 360        break;
 361    case VIA_REG_T2CH:
 362        val = get_counter(s, &s->timers[1]) >> 8;
 363        break;
 364    case VIA_REG_SR:
 365        val = s->sr;
 366        s->ifr &= ~SR_INT;
 367        mos6522_update_irq(s);
 368        break;
 369    case VIA_REG_ACR:
 370        val = s->acr;
 371        break;
 372    case VIA_REG_PCR:
 373        val = s->pcr;
 374        break;
 375    case VIA_REG_IFR:
 376        val = s->ifr;
 377        if (s->ifr & s->ier) {
 378            val |= 0x80;
 379        }
 380        break;
 381    case VIA_REG_IER:
 382        val = s->ier | 0x80;
 383        break;
 384    default:
 385        g_assert_not_reached();
 386    }
 387
 388    if (addr != VIA_REG_IFR || val != 0) {
 389        trace_mos6522_read(addr, mos6522_reg_names[addr], val);
 390    }
 391
 392    return val;
 393}
 394
 395void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
 396{
 397    MOS6522State *s = opaque;
 398    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
 399    int ctrl;
 400
 401    trace_mos6522_write(addr, mos6522_reg_names[addr], val);
 402
 403    switch (addr) {
 404    case VIA_REG_B:
 405        s->b = (s->b & ~s->dirb) | (val & s->dirb);
 406        mdc->portB_write(s);
 407        ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT;
 408        if (!(ctrl & C2_IND)) {
 409            s->ifr &= ~CB2_INT;
 410        }
 411        s->ifr &= ~CB1_INT;
 412        mos6522_update_irq(s);
 413        break;
 414    case VIA_REG_A:
 415       qemu_log_mask(LOG_UNIMP, "Write access to register A with handshake");
 416       /* fall through */
 417    case VIA_REG_ANH:
 418        s->a = (s->a & ~s->dira) | (val & s->dira);
 419        mdc->portA_write(s);
 420        ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT;
 421        if (!(ctrl & C2_IND)) {
 422            s->ifr &= ~CA2_INT;
 423        }
 424        s->ifr &= ~CA1_INT;
 425        mos6522_update_irq(s);
 426        break;
 427    case VIA_REG_DIRB:
 428        s->dirb = val;
 429        break;
 430    case VIA_REG_DIRA:
 431        s->dira = val;
 432        break;
 433    case VIA_REG_T1CL:
 434        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
 435        mos6522_timer1_update(s, &s->timers[0],
 436                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 437        break;
 438    case VIA_REG_T1CH:
 439        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
 440        s->ifr &= ~T1_INT;
 441        set_counter(s, &s->timers[0], s->timers[0].latch);
 442        break;
 443    case VIA_REG_T1LL:
 444        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
 445        mos6522_timer1_update(s, &s->timers[0],
 446                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 447        break;
 448    case VIA_REG_T1LH:
 449        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
 450        s->ifr &= ~T1_INT;
 451        mos6522_timer1_update(s, &s->timers[0],
 452                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 453        break;
 454    case VIA_REG_T2CL:
 455        s->timers[1].latch = (s->timers[1].latch & 0xff00) | val;
 456        break;
 457    case VIA_REG_T2CH:
 458        /* To ensure T2 generates an interrupt on zero crossing with the
 459           common timer code, write the value directly from the latch to
 460           the counter */
 461        s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8);
 462        s->ifr &= ~T2_INT;
 463        set_counter(s, &s->timers[1], s->timers[1].latch);
 464        break;
 465    case VIA_REG_SR:
 466        s->sr = val;
 467        break;
 468    case VIA_REG_ACR:
 469        s->acr = val;
 470        mos6522_timer1_update(s, &s->timers[0],
 471                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 472        break;
 473    case VIA_REG_PCR:
 474        s->pcr = val;
 475        break;
 476    case VIA_REG_IFR:
 477        /* reset bits */
 478        s->ifr &= ~val;
 479        mos6522_update_irq(s);
 480        break;
 481    case VIA_REG_IER:
 482        if (val & IER_SET) {
 483            /* set bits */
 484            s->ier |= val & 0x7f;
 485        } else {
 486            /* reset bits */
 487            s->ier &= ~val;
 488        }
 489        mos6522_update_irq(s);
 490        /* if IER is modified starts needed timers */
 491        mos6522_timer1_update(s, &s->timers[0],
 492                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 493        mos6522_timer2_update(s, &s->timers[1],
 494                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 495        break;
 496    default:
 497        g_assert_not_reached();
 498    }
 499}
 500
 501static int qmp_x_query_via_foreach(Object *obj, void *opaque)
 502{
 503    GString *buf = opaque;
 504
 505    if (object_dynamic_cast(obj, TYPE_MOS6522)) {
 506        MOS6522State *s = MOS6522(obj);
 507        int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 508        uint16_t t1counter = get_counter(s, &s->timers[0]);
 509        uint16_t t2counter = get_counter(s, &s->timers[1]);
 510
 511        g_string_append_printf(buf, "%s:\n", object_get_typename(obj));
 512
 513        g_string_append_printf(buf, "  Registers:\n");
 514        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 515                               mos6522_reg_names[0], s->b);
 516        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 517                               mos6522_reg_names[1], s->a);
 518        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 519                               mos6522_reg_names[2], s->dirb);
 520        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 521                               mos6522_reg_names[3], s->dira);
 522        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 523                               mos6522_reg_names[4], t1counter & 0xff);
 524        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 525                               mos6522_reg_names[5], t1counter >> 8);
 526        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 527                               mos6522_reg_names[6],
 528                               s->timers[0].latch & 0xff);
 529        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 530                               mos6522_reg_names[7],
 531                               s->timers[0].latch >> 8);
 532        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 533                               mos6522_reg_names[8], t2counter & 0xff);
 534        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 535                               mos6522_reg_names[9], t2counter >> 8);
 536        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 537                               mos6522_reg_names[10], s->sr);
 538        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 539                               mos6522_reg_names[11], s->acr);
 540        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 541                               mos6522_reg_names[12], s->pcr);
 542        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 543                               mos6522_reg_names[13], s->ifr);
 544        g_string_append_printf(buf, "    %-*s:    0x%x\n", 4,
 545                               mos6522_reg_names[14], s->ier);
 546
 547        g_string_append_printf(buf, "  Timers:\n");
 548        g_string_append_printf(buf, "    Using current time now(ns)=%"PRId64
 549                                    "\n", now);
 550        g_string_append_printf(buf, "    T1 freq(hz)=%"PRId64
 551                               " mode=%s"
 552                               " counter=0x%x"
 553                               " latch=0x%x\n"
 554                               "       load_time(ns)=%"PRId64
 555                               " next_irq_time(ns)=%"PRId64 "\n",
 556                               s->timers[0].frequency,
 557                               ((s->acr & T1MODE) == T1MODE_CONT) ? "continuous"
 558                                                                  : "one-shot",
 559                               t1counter,
 560                               s->timers[0].latch,
 561                               s->timers[0].load_time,
 562                               get_next_irq_time(s, &s->timers[0], now));
 563        g_string_append_printf(buf, "    T2 freq(hz)=%"PRId64
 564                               " mode=%s"
 565                               " counter=0x%x"
 566                               " latch=0x%x\n"
 567                               "       load_time(ns)=%"PRId64
 568                               " next_irq_time(ns)=%"PRId64 "\n",
 569                               s->timers[1].frequency,
 570                               "one-shot",
 571                               t2counter,
 572                               s->timers[1].latch,
 573                               s->timers[1].load_time,
 574                               get_next_irq_time(s, &s->timers[1], now));
 575    }
 576
 577    return 0;
 578}
 579
 580static HumanReadableText *qmp_x_query_via(Error **errp)
 581{
 582    g_autoptr(GString) buf = g_string_new("");
 583
 584    object_child_foreach_recursive(object_get_root(),
 585                                   qmp_x_query_via_foreach, buf);
 586
 587    return human_readable_text_from_str(buf);
 588}
 589
 590void hmp_info_via(Monitor *mon, const QDict *qdict)
 591{
 592    Error *err = NULL;
 593    g_autoptr(HumanReadableText) info = qmp_x_query_via(&err);
 594
 595    if (hmp_handle_error(mon, err)) {
 596        return;
 597    }
 598    monitor_printf(mon, "%s", info->human_readable_text);
 599}
 600
 601static const MemoryRegionOps mos6522_ops = {
 602    .read = mos6522_read,
 603    .write = mos6522_write,
 604    .endianness = DEVICE_NATIVE_ENDIAN,
 605    .valid = {
 606        .min_access_size = 1,
 607        .max_access_size = 1,
 608    },
 609};
 610
 611static const VMStateDescription vmstate_mos6522_timer = {
 612    .name = "mos6522_timer",
 613    .version_id = 0,
 614    .minimum_version_id = 0,
 615    .fields = (VMStateField[]) {
 616        VMSTATE_UINT16(latch, MOS6522Timer),
 617        VMSTATE_UINT16(counter_value, MOS6522Timer),
 618        VMSTATE_INT64(load_time, MOS6522Timer),
 619        VMSTATE_INT64(next_irq_time, MOS6522Timer),
 620        VMSTATE_TIMER_PTR(timer, MOS6522Timer),
 621        VMSTATE_END_OF_LIST()
 622    }
 623};
 624
 625const VMStateDescription vmstate_mos6522 = {
 626    .name = "mos6522",
 627    .version_id = 1,
 628    .minimum_version_id = 1,
 629    .fields = (VMStateField[]) {
 630        VMSTATE_UINT8(a, MOS6522State),
 631        VMSTATE_UINT8(b, MOS6522State),
 632        VMSTATE_UINT8(dira, MOS6522State),
 633        VMSTATE_UINT8(dirb, MOS6522State),
 634        VMSTATE_UINT8(sr, MOS6522State),
 635        VMSTATE_UINT8(acr, MOS6522State),
 636        VMSTATE_UINT8(pcr, MOS6522State),
 637        VMSTATE_UINT8(ifr, MOS6522State),
 638        VMSTATE_UINT8(ier, MOS6522State),
 639        VMSTATE_UINT8(last_irq_levels, MOS6522State),
 640        VMSTATE_STRUCT_ARRAY(timers, MOS6522State, 2, 0,
 641                             vmstate_mos6522_timer, MOS6522Timer),
 642        VMSTATE_END_OF_LIST()
 643    }
 644};
 645
 646static void mos6522_reset(DeviceState *dev)
 647{
 648    MOS6522State *s = MOS6522(dev);
 649
 650    s->b = 0;
 651    s->a = 0;
 652    s->dirb = 0xff;
 653    s->dira = 0;
 654    s->sr = 0;
 655    s->acr = 0;
 656    s->pcr = 0;
 657    s->ifr = 0;
 658    s->ier = 0;
 659    /* s->ier = T1_INT | SR_INT; */
 660
 661    s->timers[0].frequency = s->frequency;
 662    s->timers[0].latch = 0xffff;
 663    set_counter(s, &s->timers[0], 0xffff);
 664    timer_del(s->timers[0].timer);
 665
 666    s->timers[1].frequency = s->frequency;
 667    s->timers[1].latch = 0xffff;
 668    timer_del(s->timers[1].timer);
 669}
 670
 671static void mos6522_init(Object *obj)
 672{
 673    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 674    MOS6522State *s = MOS6522(obj);
 675    int i;
 676
 677    memory_region_init_io(&s->mem, obj, &mos6522_ops, s, "mos6522",
 678                          MOS6522_NUM_REGS);
 679    sysbus_init_mmio(sbd, &s->mem);
 680    sysbus_init_irq(sbd, &s->irq);
 681
 682    for (i = 0; i < ARRAY_SIZE(s->timers); i++) {
 683        s->timers[i].index = i;
 684    }
 685
 686    s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer1, s);
 687    s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer2, s);
 688
 689    qdev_init_gpio_in(DEVICE(obj), mos6522_set_irq, VIA_NUM_INTS);
 690}
 691
 692static void mos6522_finalize(Object *obj)
 693{
 694    MOS6522State *s = MOS6522(obj);
 695
 696    timer_free(s->timers[0].timer);
 697    timer_free(s->timers[1].timer);
 698}
 699
 700static Property mos6522_properties[] = {
 701    DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0),
 702    DEFINE_PROP_END_OF_LIST()
 703};
 704
 705static void mos6522_class_init(ObjectClass *oc, void *data)
 706{
 707    DeviceClass *dc = DEVICE_CLASS(oc);
 708    MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
 709
 710    dc->reset = mos6522_reset;
 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;
 719}
 720
 721static 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,
 727    .abstract = true,
 728    .class_size = sizeof(MOS6522DeviceClass),
 729    .class_init = mos6522_class_init,
 730};
 731
 732static void mos6522_register_types(void)
 733{
 734    type_register_static(&mos6522_type_info);
 735}
 736
 737type_init(mos6522_register_types)
 738