xref: /openbmc/qemu/hw/misc/mos6522.c (revision 988717b46b6424907618cb845ace9d69062703af)
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 "qemu/timer.h"
34  #include "qemu/cutils.h"
35  #include "qemu/log.h"
36  #include "qemu/module.h"
37  #include "trace.h"
38  
39  /* XXX: implement all timer modes */
40  
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);
45  
46  static void mos6522_update_irq(MOS6522State *s)
47  {
48      if (s->ifr & s->ier) {
49          qemu_irq_raise(s->irq);
50      } else {
51          qemu_irq_lower(s->irq);
52      }
53  }
54  
55  static uint64_t get_counter_value(MOS6522State *s, MOS6522Timer *ti)
56  {
57      MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s);
58  
59      if (ti->index == 0) {
60          return mdc->get_timer1_counter_value(s, ti);
61      } else {
62          return mdc->get_timer2_counter_value(s, ti);
63      }
64  }
65  
66  static uint64_t get_load_time(MOS6522State *s, MOS6522Timer *ti)
67  {
68      MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s);
69  
70      if (ti->index == 0) {
71          return mdc->get_timer1_load_time(s, ti);
72      } else {
73          return mdc->get_timer2_load_time(s, ti);
74      }
75  }
76  
77  static unsigned int get_counter(MOS6522State *s, MOS6522Timer *ti)
78  {
79      int64_t d;
80      unsigned int counter;
81  
82      d = get_counter_value(s, ti);
83  
84      if (ti->index == 0) {
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;
88          } else {
89              counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
90              counter = (ti->latch - counter) & 0xffff;
91          }
92      } else {
93          counter = (ti->counter_value - d) & 0xffff;
94      }
95      return counter;
96  }
97  
98  static void set_counter(MOS6522State *s, MOS6522Timer *ti, unsigned int val)
99  {
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);
105      } else {
106          mos6522_timer2_update(s, ti, ti->load_time);
107      }
108  }
109  
110  static int64_t get_next_irq_time(MOS6522State *s, MOS6522Timer *ti,
111                                   int64_t current_time)
112  {
113      int64_t d, next_time;
114      unsigned int counter;
115  
116      if (ti->frequency == 0) {
117          return INT64_MAX;
118      }
119  
120      /* current counter value */
121      d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
122                   ti->frequency, NANOSECONDS_PER_SECOND);
123  
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;
127      } else {
128          counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
129          counter = (ti->latch - counter) & 0xffff;
130      }
131  
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;
137      } else {
138          next_time = d + counter;
139      }
140      trace_mos6522_get_next_irq_time(ti->latch, d, next_time - d);
141      next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, ti->frequency) +
142                           ti->load_time;
143  
144      if (next_time <= current_time) {
145          next_time = current_time + 1;
146      }
147      return next_time;
148  }
149  
150  static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti,
151                                   int64_t current_time)
152  {
153      if (!ti->timer) {
154          return;
155      }
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);
159      } else {
160          timer_mod(ti->timer, ti->next_irq_time);
161      }
162  }
163  
164  static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti,
165                                   int64_t current_time)
166  {
167      if (!ti->timer) {
168          return;
169      }
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);
173      } else {
174          timer_mod(ti->timer, ti->next_irq_time);
175      }
176  }
177  
178  static void mos6522_timer1(void *opaque)
179  {
180      MOS6522State *s = opaque;
181      MOS6522Timer *ti = &s->timers[0];
182  
183      mos6522_timer1_update(s, ti, ti->next_irq_time);
184      s->ifr |= T1_INT;
185      mos6522_update_irq(s);
186  }
187  
188  static void mos6522_timer2(void *opaque)
189  {
190      MOS6522State *s = opaque;
191      MOS6522Timer *ti = &s->timers[1];
192  
193      mos6522_timer2_update(s, ti, ti->next_irq_time);
194      s->ifr |= T2_INT;
195      mos6522_update_irq(s);
196  }
197  
198  static void mos6522_set_sr_int(MOS6522State *s)
199  {
200      trace_mos6522_set_sr_int();
201      s->ifr |= SR_INT;
202      mos6522_update_irq(s);
203  }
204  
205  static uint64_t mos6522_get_counter_value(MOS6522State *s, MOS6522Timer *ti)
206  {
207      return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
208                      ti->frequency, NANOSECONDS_PER_SECOND);
209  }
210  
211  static uint64_t mos6522_get_load_time(MOS6522State *s, MOS6522Timer *ti)
212  {
213      uint64_t load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
214  
215      return load_time;
216  }
217  
218  static void mos6522_portA_write(MOS6522State *s)
219  {
220      qemu_log_mask(LOG_UNIMP, "portA_write unimplemented\n");
221  }
222  
223  static void mos6522_portB_write(MOS6522State *s)
224  {
225      qemu_log_mask(LOG_UNIMP, "portB_write unimplemented\n");
226  }
227  
228  uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
229  {
230      MOS6522State *s = opaque;
231      uint32_t val;
232      int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
233  
234      if (now >= s->timers[0].next_irq_time) {
235          mos6522_timer1_update(s, &s->timers[0], now);
236          s->ifr |= T1_INT;
237      }
238      if (now >= s->timers[1].next_irq_time) {
239          mos6522_timer2_update(s, &s->timers[1], now);
240          s->ifr |= T2_INT;
241      }
242      switch (addr) {
243      case VIA_REG_B:
244          val = s->b;
245          break;
246      case VIA_REG_A:
247         qemu_log_mask(LOG_UNIMP, "Read access to register A with handshake");
248         /* fall through */
249      case VIA_REG_ANH:
250          val = s->a;
251          break;
252      case VIA_REG_DIRB:
253          val = s->dirb;
254          break;
255      case VIA_REG_DIRA:
256          val = s->dira;
257          break;
258      case VIA_REG_T1CL:
259          val = get_counter(s, &s->timers[0]) & 0xff;
260          s->ifr &= ~T1_INT;
261          mos6522_update_irq(s);
262          break;
263      case VIA_REG_T1CH:
264          val = get_counter(s, &s->timers[0]) >> 8;
265          mos6522_update_irq(s);
266          break;
267      case VIA_REG_T1LL:
268          val = s->timers[0].latch & 0xff;
269          break;
270      case VIA_REG_T1LH:
271          /* XXX: check this */
272          val = (s->timers[0].latch >> 8) & 0xff;
273          break;
274      case VIA_REG_T2CL:
275          val = get_counter(s, &s->timers[1]) & 0xff;
276          s->ifr &= ~T2_INT;
277          mos6522_update_irq(s);
278          break;
279      case VIA_REG_T2CH:
280          val = get_counter(s, &s->timers[1]) >> 8;
281          break;
282      case VIA_REG_SR:
283          val = s->sr;
284          s->ifr &= ~SR_INT;
285          mos6522_update_irq(s);
286          break;
287      case VIA_REG_ACR:
288          val = s->acr;
289          break;
290      case VIA_REG_PCR:
291          val = s->pcr;
292          break;
293      case VIA_REG_IFR:
294          val = s->ifr;
295          if (s->ifr & s->ier) {
296              val |= 0x80;
297          }
298          break;
299      case VIA_REG_IER:
300          val = s->ier | 0x80;
301          break;
302      default:
303          g_assert_not_reached();
304      }
305  
306      if (addr != VIA_REG_IFR || val != 0) {
307          trace_mos6522_read(addr, val);
308      }
309  
310      return val;
311  }
312  
313  void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
314  {
315      MOS6522State *s = opaque;
316      MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s);
317  
318      trace_mos6522_write(addr, val);
319  
320      switch (addr) {
321      case VIA_REG_B:
322          s->b = (s->b & ~s->dirb) | (val & s->dirb);
323          mdc->portB_write(s);
324          break;
325      case VIA_REG_A:
326         qemu_log_mask(LOG_UNIMP, "Write access to register A with handshake");
327         /* fall through */
328      case VIA_REG_ANH:
329          s->a = (s->a & ~s->dira) | (val & s->dira);
330          mdc->portA_write(s);
331          break;
332      case VIA_REG_DIRB:
333          s->dirb = val;
334          break;
335      case VIA_REG_DIRA:
336          s->dira = val;
337          break;
338      case VIA_REG_T1CL:
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));
342          break;
343      case VIA_REG_T1CH:
344          s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
345          s->ifr &= ~T1_INT;
346          set_counter(s, &s->timers[0], s->timers[0].latch);
347          break;
348      case VIA_REG_T1LL:
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));
352          break;
353      case VIA_REG_T1LH:
354          s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
355          s->ifr &= ~T1_INT;
356          mos6522_timer1_update(s, &s->timers[0],
357                                qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
358          break;
359      case VIA_REG_T2CL:
360          s->timers[1].latch = (s->timers[1].latch & 0xff00) | val;
361          break;
362      case VIA_REG_T2CH:
363          /* To ensure T2 generates an interrupt on zero crossing with the
364             common timer code, write the value directly from the latch to
365             the counter */
366          s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8);
367          s->ifr &= ~T2_INT;
368          set_counter(s, &s->timers[1], s->timers[1].latch);
369          break;
370      case VIA_REG_SR:
371          s->sr = val;
372          break;
373      case VIA_REG_ACR:
374          s->acr = val;
375          mos6522_timer1_update(s, &s->timers[0],
376                                qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
377          break;
378      case VIA_REG_PCR:
379          s->pcr = val;
380          break;
381      case VIA_REG_IFR:
382          /* reset bits */
383          s->ifr &= ~val;
384          mos6522_update_irq(s);
385          break;
386      case VIA_REG_IER:
387          if (val & IER_SET) {
388              /* set bits */
389              s->ier |= val & 0x7f;
390          } else {
391              /* reset bits */
392              s->ier &= ~val;
393          }
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));
400          break;
401      default:
402          g_assert_not_reached();
403      }
404  }
405  
406  static const MemoryRegionOps mos6522_ops = {
407      .read = mos6522_read,
408      .write = mos6522_write,
409      .endianness = DEVICE_NATIVE_ENDIAN,
410      .valid = {
411          .min_access_size = 1,
412          .max_access_size = 1,
413      },
414  };
415  
416  static const VMStateDescription vmstate_mos6522_timer = {
417      .name = "mos6522_timer",
418      .version_id = 0,
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()
427      }
428  };
429  
430  const VMStateDescription vmstate_mos6522 = {
431      .name = "mos6522",
432      .version_id = 0,
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()
447      }
448  };
449  
450  static void mos6522_reset(DeviceState *dev)
451  {
452      MOS6522State *s = MOS6522(dev);
453  
454      s->b = 0;
455      s->a = 0;
456      s->dirb = 0xff;
457      s->dira = 0;
458      s->sr = 0;
459      s->acr = 0;
460      s->pcr = 0;
461      s->ifr = 0;
462      s->ier = 0;
463      /* s->ier = T1_INT | SR_INT; */
464  
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);
469  
470      s->timers[1].frequency = s->frequency;
471      s->timers[1].latch = 0xffff;
472      timer_del(s->timers[1].timer);
473  }
474  
475  static void mos6522_init(Object *obj)
476  {
477      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
478      MOS6522State *s = MOS6522(obj);
479      int i;
480  
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);
484  
485      for (i = 0; i < ARRAY_SIZE(s->timers); i++) {
486          s->timers[i].index = i;
487      }
488  
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);
491  }
492  
493  static Property mos6522_properties[] = {
494      DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0),
495      DEFINE_PROP_END_OF_LIST()
496  };
497  
498  static void mos6522_class_init(ObjectClass *oc, void *data)
499  {
500      DeviceClass *dc = DEVICE_CLASS(oc);
501      MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc);
502  
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;
515  }
516  
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,
522      .abstract = true,
523      .class_size = sizeof(MOS6522DeviceClass),
524      .class_init = mos6522_class_init,
525  };
526  
527  static void mos6522_register_types(void)
528  {
529      type_register_static(&mos6522_type_info);
530  }
531  
532  type_init(mos6522_register_types)
533