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/hw.h" 29 #include "hw/input/adb.h" 30 #include "hw/misc/mos6522.h" 31 #include "qemu/timer.h" 32 #include "sysemu/sysemu.h" 33 #include "qemu/cutils.h" 34 #include "qemu/log.h" 35 #include "qemu/module.h" 36 #include "trace.h" 37 38 /* XXX: implement all timer modes */ 39 40 static void mos6522_timer_update(MOS6522State *s, MOS6522Timer *ti, 41 int64_t current_time); 42 43 static void mos6522_update_irq(MOS6522State *s) 44 { 45 if (s->ifr & s->ier) { 46 qemu_irq_raise(s->irq); 47 } else { 48 qemu_irq_lower(s->irq); 49 } 50 } 51 52 static uint64_t get_counter_value(MOS6522State *s, MOS6522Timer *ti) 53 { 54 MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); 55 56 if (ti->index == 0) { 57 return mdc->get_timer1_counter_value(s, ti); 58 } else { 59 return mdc->get_timer2_counter_value(s, ti); 60 } 61 } 62 63 static uint64_t get_load_time(MOS6522State *s, MOS6522Timer *ti) 64 { 65 MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); 66 67 if (ti->index == 0) { 68 return mdc->get_timer1_load_time(s, ti); 69 } else { 70 return mdc->get_timer2_load_time(s, ti); 71 } 72 } 73 74 static unsigned int get_counter(MOS6522State *s, MOS6522Timer *ti) 75 { 76 int64_t d; 77 unsigned int counter; 78 79 d = get_counter_value(s, ti); 80 81 if (ti->index == 0) { 82 /* the timer goes down from latch to -1 (period of latch + 2) */ 83 if (d <= (ti->counter_value + 1)) { 84 counter = (ti->counter_value - d) & 0xffff; 85 } else { 86 counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); 87 counter = (ti->latch - counter) & 0xffff; 88 } 89 } else { 90 counter = (ti->counter_value - d) & 0xffff; 91 } 92 return counter; 93 } 94 95 static void set_counter(MOS6522State *s, MOS6522Timer *ti, unsigned int val) 96 { 97 trace_mos6522_set_counter(1 + ti->index, val); 98 ti->load_time = get_load_time(s, ti); 99 ti->counter_value = val; 100 mos6522_timer_update(s, ti, ti->load_time); 101 } 102 103 static int64_t get_next_irq_time(MOS6522State *s, MOS6522Timer *ti, 104 int64_t current_time) 105 { 106 int64_t d, next_time; 107 unsigned int counter; 108 109 /* current counter value */ 110 d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time, 111 ti->frequency, NANOSECONDS_PER_SECOND); 112 113 /* the timer goes down from latch to -1 (period of latch + 2) */ 114 if (d <= (ti->counter_value + 1)) { 115 counter = (ti->counter_value - d) & 0xffff; 116 } else { 117 counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); 118 counter = (ti->latch - counter) & 0xffff; 119 } 120 121 /* Note: we consider the irq is raised on 0 */ 122 if (counter == 0xffff) { 123 next_time = d + ti->latch + 1; 124 } else if (counter == 0) { 125 next_time = d + ti->latch + 2; 126 } else { 127 next_time = d + counter; 128 } 129 trace_mos6522_get_next_irq_time(ti->latch, d, next_time - d); 130 next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, ti->frequency) + 131 ti->load_time; 132 if (next_time <= current_time) { 133 next_time = current_time + 1; 134 } 135 return next_time; 136 } 137 138 static void mos6522_timer_update(MOS6522State *s, MOS6522Timer *ti, 139 int64_t current_time) 140 { 141 if (!ti->timer) { 142 return; 143 } 144 if (ti->index == 0 && (s->acr & T1MODE) != T1MODE_CONT) { 145 timer_del(ti->timer); 146 } else { 147 ti->next_irq_time = get_next_irq_time(s, ti, current_time); 148 timer_mod(ti->timer, ti->next_irq_time); 149 } 150 } 151 152 static void mos6522_timer1(void *opaque) 153 { 154 MOS6522State *s = opaque; 155 MOS6522Timer *ti = &s->timers[0]; 156 157 mos6522_timer_update(s, ti, ti->next_irq_time); 158 s->ifr |= T1_INT; 159 mos6522_update_irq(s); 160 } 161 162 static void mos6522_timer2(void *opaque) 163 { 164 MOS6522State *s = opaque; 165 MOS6522Timer *ti = &s->timers[1]; 166 167 mos6522_timer_update(s, ti, ti->next_irq_time); 168 s->ifr |= T2_INT; 169 mos6522_update_irq(s); 170 } 171 172 static void mos6522_set_sr_int(MOS6522State *s) 173 { 174 trace_mos6522_set_sr_int(); 175 s->ifr |= SR_INT; 176 mos6522_update_irq(s); 177 } 178 179 static uint64_t mos6522_get_counter_value(MOS6522State *s, MOS6522Timer *ti) 180 { 181 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time, 182 ti->frequency, NANOSECONDS_PER_SECOND); 183 } 184 185 static uint64_t mos6522_get_load_time(MOS6522State *s, MOS6522Timer *ti) 186 { 187 uint64_t load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 188 189 return load_time; 190 } 191 192 static void mos6522_portA_write(MOS6522State *s) 193 { 194 qemu_log_mask(LOG_UNIMP, "portA_write unimplemented\n"); 195 } 196 197 static void mos6522_portB_write(MOS6522State *s) 198 { 199 qemu_log_mask(LOG_UNIMP, "portB_write unimplemented\n"); 200 } 201 202 uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size) 203 { 204 MOS6522State *s = opaque; 205 uint32_t val; 206 207 switch (addr) { 208 case VIA_REG_B: 209 val = s->b; 210 break; 211 case VIA_REG_A: 212 val = s->a; 213 break; 214 case VIA_REG_DIRB: 215 val = s->dirb; 216 break; 217 case VIA_REG_DIRA: 218 val = s->dira; 219 break; 220 case VIA_REG_T1CL: 221 val = get_counter(s, &s->timers[0]) & 0xff; 222 s->ifr &= ~T1_INT; 223 mos6522_update_irq(s); 224 break; 225 case VIA_REG_T1CH: 226 val = get_counter(s, &s->timers[0]) >> 8; 227 mos6522_update_irq(s); 228 break; 229 case VIA_REG_T1LL: 230 val = s->timers[0].latch & 0xff; 231 break; 232 case VIA_REG_T1LH: 233 /* XXX: check this */ 234 val = (s->timers[0].latch >> 8) & 0xff; 235 break; 236 case VIA_REG_T2CL: 237 val = get_counter(s, &s->timers[1]) & 0xff; 238 s->ifr &= ~T2_INT; 239 mos6522_update_irq(s); 240 break; 241 case VIA_REG_T2CH: 242 val = get_counter(s, &s->timers[1]) >> 8; 243 break; 244 case VIA_REG_SR: 245 val = s->sr; 246 s->ifr &= ~SR_INT; 247 mos6522_update_irq(s); 248 break; 249 case VIA_REG_ACR: 250 val = s->acr; 251 break; 252 case VIA_REG_PCR: 253 val = s->pcr; 254 break; 255 case VIA_REG_IFR: 256 val = s->ifr; 257 if (s->ifr & s->ier) { 258 val |= 0x80; 259 } 260 break; 261 case VIA_REG_IER: 262 val = s->ier | 0x80; 263 break; 264 default: 265 case VIA_REG_ANH: 266 val = s->anh; 267 break; 268 } 269 270 if (addr != VIA_REG_IFR || val != 0) { 271 trace_mos6522_read(addr, val); 272 } 273 274 return val; 275 } 276 277 void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 278 { 279 MOS6522State *s = opaque; 280 MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); 281 282 trace_mos6522_write(addr, val); 283 284 switch (addr) { 285 case VIA_REG_B: 286 s->b = (s->b & ~s->dirb) | (val & s->dirb); 287 mdc->portB_write(s); 288 break; 289 case VIA_REG_A: 290 s->a = (s->a & ~s->dira) | (val & s->dira); 291 mdc->portA_write(s); 292 break; 293 case VIA_REG_DIRB: 294 s->dirb = val; 295 break; 296 case VIA_REG_DIRA: 297 s->dira = val; 298 break; 299 case VIA_REG_T1CL: 300 s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; 301 mos6522_timer_update(s, &s->timers[0], 302 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 303 break; 304 case VIA_REG_T1CH: 305 s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); 306 s->ifr &= ~T1_INT; 307 set_counter(s, &s->timers[0], s->timers[0].latch); 308 break; 309 case VIA_REG_T1LL: 310 s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; 311 mos6522_timer_update(s, &s->timers[0], 312 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 313 break; 314 case VIA_REG_T1LH: 315 s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); 316 s->ifr &= ~T1_INT; 317 mos6522_timer_update(s, &s->timers[0], 318 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 319 break; 320 case VIA_REG_T2CL: 321 s->timers[1].latch = (s->timers[1].latch & 0xff00) | val; 322 break; 323 case VIA_REG_T2CH: 324 /* To ensure T2 generates an interrupt on zero crossing with the 325 common timer code, write the value directly from the latch to 326 the counter */ 327 s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8); 328 s->ifr &= ~T2_INT; 329 set_counter(s, &s->timers[1], s->timers[1].latch); 330 break; 331 case VIA_REG_SR: 332 s->sr = val; 333 break; 334 case VIA_REG_ACR: 335 s->acr = val; 336 mos6522_timer_update(s, &s->timers[0], 337 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 338 break; 339 case VIA_REG_PCR: 340 s->pcr = val; 341 break; 342 case VIA_REG_IFR: 343 /* reset bits */ 344 s->ifr &= ~val; 345 mos6522_update_irq(s); 346 break; 347 case VIA_REG_IER: 348 if (val & IER_SET) { 349 /* set bits */ 350 s->ier |= val & 0x7f; 351 } else { 352 /* reset bits */ 353 s->ier &= ~val; 354 } 355 mos6522_update_irq(s); 356 break; 357 default: 358 case VIA_REG_ANH: 359 s->anh = val; 360 break; 361 } 362 } 363 364 static const MemoryRegionOps mos6522_ops = { 365 .read = mos6522_read, 366 .write = mos6522_write, 367 .endianness = DEVICE_NATIVE_ENDIAN, 368 .valid = { 369 .min_access_size = 1, 370 .max_access_size = 1, 371 }, 372 }; 373 374 static const VMStateDescription vmstate_mos6522_timer = { 375 .name = "mos6522_timer", 376 .version_id = 0, 377 .minimum_version_id = 0, 378 .fields = (VMStateField[]) { 379 VMSTATE_UINT16(latch, MOS6522Timer), 380 VMSTATE_UINT16(counter_value, MOS6522Timer), 381 VMSTATE_INT64(load_time, MOS6522Timer), 382 VMSTATE_INT64(next_irq_time, MOS6522Timer), 383 VMSTATE_TIMER_PTR(timer, MOS6522Timer), 384 VMSTATE_END_OF_LIST() 385 } 386 }; 387 388 const VMStateDescription vmstate_mos6522 = { 389 .name = "mos6522", 390 .version_id = 0, 391 .minimum_version_id = 0, 392 .fields = (VMStateField[]) { 393 VMSTATE_UINT8(a, MOS6522State), 394 VMSTATE_UINT8(b, MOS6522State), 395 VMSTATE_UINT8(dira, MOS6522State), 396 VMSTATE_UINT8(dirb, MOS6522State), 397 VMSTATE_UINT8(sr, MOS6522State), 398 VMSTATE_UINT8(acr, MOS6522State), 399 VMSTATE_UINT8(pcr, MOS6522State), 400 VMSTATE_UINT8(ifr, MOS6522State), 401 VMSTATE_UINT8(ier, MOS6522State), 402 VMSTATE_UINT8(anh, MOS6522State), 403 VMSTATE_STRUCT_ARRAY(timers, MOS6522State, 2, 0, 404 vmstate_mos6522_timer, MOS6522Timer), 405 VMSTATE_END_OF_LIST() 406 } 407 }; 408 409 static void mos6522_reset(DeviceState *dev) 410 { 411 MOS6522State *s = MOS6522(dev); 412 413 s->b = 0; 414 s->a = 0; 415 s->dirb = 0xff; 416 s->dira = 0; 417 s->sr = 0; 418 s->acr = 0; 419 s->pcr = 0; 420 s->ifr = 0; 421 s->ier = 0; 422 /* s->ier = T1_INT | SR_INT; */ 423 s->anh = 0; 424 425 s->timers[0].frequency = s->frequency; 426 s->timers[0].latch = 0xffff; 427 set_counter(s, &s->timers[0], 0xffff); 428 429 s->timers[1].frequency = s->frequency; 430 s->timers[1].latch = 0xffff; 431 } 432 433 static void mos6522_init(Object *obj) 434 { 435 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 436 MOS6522State *s = MOS6522(obj); 437 int i; 438 439 memory_region_init_io(&s->mem, obj, &mos6522_ops, s, "mos6522", 0x10); 440 sysbus_init_mmio(sbd, &s->mem); 441 sysbus_init_irq(sbd, &s->irq); 442 443 for (i = 0; i < ARRAY_SIZE(s->timers); i++) { 444 s->timers[i].index = i; 445 } 446 447 s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer1, s); 448 s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer2, s); 449 } 450 451 static Property mos6522_properties[] = { 452 DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0), 453 DEFINE_PROP_END_OF_LIST() 454 }; 455 456 static void mos6522_class_init(ObjectClass *oc, void *data) 457 { 458 DeviceClass *dc = DEVICE_CLASS(oc); 459 MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc); 460 461 dc->reset = mos6522_reset; 462 dc->vmsd = &vmstate_mos6522; 463 dc->props = mos6522_properties; 464 mdc->parent_reset = dc->reset; 465 mdc->set_sr_int = mos6522_set_sr_int; 466 mdc->portB_write = mos6522_portB_write; 467 mdc->portA_write = mos6522_portA_write; 468 mdc->update_irq = mos6522_update_irq; 469 mdc->get_timer1_counter_value = mos6522_get_counter_value; 470 mdc->get_timer2_counter_value = mos6522_get_counter_value; 471 mdc->get_timer1_load_time = mos6522_get_load_time; 472 mdc->get_timer2_load_time = mos6522_get_load_time; 473 } 474 475 static const TypeInfo mos6522_type_info = { 476 .name = TYPE_MOS6522, 477 .parent = TYPE_SYS_BUS_DEVICE, 478 .instance_size = sizeof(MOS6522State), 479 .instance_init = mos6522_init, 480 .abstract = true, 481 .class_size = sizeof(MOS6522DeviceClass), 482 .class_init = mos6522_class_init, 483 }; 484 485 static void mos6522_register_types(void) 486 { 487 type_register_static(&mos6522_type_info); 488 } 489 490 type_init(mos6522_register_types) 491