diff mbox

[v3,8/25] i8254: add NEC PC-9821 family interface

Message ID 200910281651.AA00172@YOUR-BD18D6DD63.m1.interq.or.jp
State New
Headers show

Commit Message

武田 =?ISO-2022-JP?B?IBskQj1TTGkbKEI=?= Oct. 28, 2009, 4:51 p.m. UTC

diff mbox

Patch

diff --git a/qemu/hw/i8254.c b/qemu/hw/i8254.c
index 5c49e6e..7b7bf63 100644
--- a/qemu/hw/i8254.c
+++ b/qemu/hw/i8254.c
@@ -47,6 +47,7 @@  typedef struct PITChannelState {
     uint8_t bcd; /* not supported */
     uint8_t gate; /* timer start */
     int64_t count_load_time;
+    uint64_t frequency;
     /* irq handling */
     int64_t next_transition_time;
     QEMUTimer *irq_timer;
@@ -66,7 +67,7 @@  static int pit_get_count(PITChannelState *s)
     uint64_t d;
     int counter;
 
-    d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ,
+    d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, s->frequency,
                  get_ticks_per_sec());
     switch(s->mode) {
     case 0:
@@ -92,7 +93,7 @@  static int pit_get_out1(PITChannelState *s, int64_t current_time)
     uint64_t d;
     int out;
 
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+    d = muldiv64(current_time - s->count_load_time, s->frequency,
                  get_ticks_per_sec());
     switch(s->mode) {
     default:
@@ -132,7 +133,7 @@  static int64_t pit_get_next_transition_time(PITChannelState *s,
     uint64_t d, next_time, base;
     int period2;
 
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+    d = muldiv64(current_time - s->count_load_time, s->frequency,
                  get_ticks_per_sec());
     switch(s->mode) {
     default:
@@ -170,7 +171,7 @@  static int64_t pit_get_next_transition_time(PITChannelState *s,
     }
     /* convert to timer units */
     next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
-                                              PIT_FREQ);
+                                              s->frequency);
     /* fix potential rounding problems */
     /* XXX: better solution: use a clock at PIT_FREQ Hz */
     if (next_time <= current_time)
@@ -498,22 +499,66 @@  void hpet_pit_enable(void)
     pit_load_count(s, 0);
 }
 
-PITState *pit_init(int base, qemu_irq irq)
+static void pit_init_common(PITState *pit, int base, qemu_irq irq,
+                            uint64_t frequency)
 {
-    PITState *pit = &pit_state;
     PITChannelState *s;
+    int i;
 
     s = &pit->channels[0];
     /* the timer 0 is connected to an IRQ */
     s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
     s->irq = irq;
 
+    for (i = 0; i < 3; i++) {
+        pit->channels[i].frequency = frequency;
+    }
+
     vmstate_register(base, &vmstate_pit, pit);
     qemu_register_reset(pit_reset, pit);
+
+    pit_reset(pit);
+}
+
+PITState *pit_init(int base, qemu_irq irq)
+{
+    PITState *pit = &pit_state;
+
+    pit_init_common(pit, base, irq, PIT_FREQ);
+
     register_ioport_write(base, 4, 1, pit_ioport_write, pit);
     register_ioport_read(base, 3, 1, pit_ioport_read, pit);
 
-    pit_reset(pit);
+    return pit;
+}
+
+/* NEC PC-9821 */
+
+static void pc98_pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    pit_ioport_write(opaque, addr >> 1, val);
+}
+
+static uint32_t pc98_pit_ioport_read(void *opaque, uint32_t addr)
+{
+    return pit_ioport_read(opaque, addr >> 1);
+}
+
+PITState *pc98_pit_init(qemu_irq irq)
+{
+    PITState *pit = &pit_state;
+    int i;
+
+    pit_init_common(pit, 0, irq, PC98_PIT_FREQ);
+
+    for (i = 0; i < 4; i++) {
+        register_ioport_write(0x71 + (i << 1), 1, 1, pc98_pit_ioport_write, pit);
+        register_ioport_write(0x3fd9 + (i << 1), 1, 1, pc98_pit_ioport_write, pit);
+    }
+    for (i = 0; i < 3; i++) {
+        register_ioport_read(0x71 + (i << 1), 1, 1, pc98_pit_ioport_read, pit);
+        register_ioport_read(0x3fd9 + (i << 1), 1, 1, pc98_pit_ioport_read, pit);
+    }
 
     return pit;
 }