Statistics
| Branch: | Revision:

root / hw / i8254.c @ 16fd921b

History | View | Annotate | Download (9.9 kB)

1 80cabfad bellard
/*
2 80cabfad bellard
 * QEMU 8253/8254 interval timer emulation
3 5fafdf24 ths
 *
4 80cabfad bellard
 * Copyright (c) 2003-2004 Fabrice Bellard
5 5fafdf24 ths
 *
6 80cabfad bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 80cabfad bellard
 * of this software and associated documentation files (the "Software"), to deal
8 80cabfad bellard
 * in the Software without restriction, including without limitation the rights
9 80cabfad bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 80cabfad bellard
 * copies of the Software, and to permit persons to whom the Software is
11 80cabfad bellard
 * furnished to do so, subject to the following conditions:
12 80cabfad bellard
 *
13 80cabfad bellard
 * The above copyright notice and this permission notice shall be included in
14 80cabfad bellard
 * all copies or substantial portions of the Software.
15 80cabfad bellard
 *
16 80cabfad bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 80cabfad bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 80cabfad bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 80cabfad bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 80cabfad bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 80cabfad bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 80cabfad bellard
 * THE SOFTWARE.
23 80cabfad bellard
 */
24 87ecb68b pbrook
#include "hw.h"
25 87ecb68b pbrook
#include "pc.h"
26 87ecb68b pbrook
#include "isa.h"
27 87ecb68b pbrook
#include "qemu-timer.h"
28 b1277b03 Jan Kiszka
#include "i8254.h"
29 d11e859e Jan Kiszka
#include "i8254_internal.h"
30 80cabfad bellard
31 b0a21b53 bellard
//#define DEBUG_PIT
32 b0a21b53 bellard
33 ec844b96 bellard
#define RW_STATE_LSB 1
34 ec844b96 bellard
#define RW_STATE_MSB 2
35 ec844b96 bellard
#define RW_STATE_WORD0 3
36 ec844b96 bellard
#define RW_STATE_WORD1 4
37 80cabfad bellard
38 b0a21b53 bellard
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
39 b0a21b53 bellard
40 80cabfad bellard
static int pit_get_count(PITChannelState *s)
41 80cabfad bellard
{
42 80cabfad bellard
    uint64_t d;
43 80cabfad bellard
    int counter;
44 80cabfad bellard
45 74475455 Paolo Bonzini
    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
46 6ee093c9 Juan Quintela
                 get_ticks_per_sec());
47 80cabfad bellard
    switch(s->mode) {
48 80cabfad bellard
    case 0:
49 80cabfad bellard
    case 1:
50 80cabfad bellard
    case 4:
51 80cabfad bellard
    case 5:
52 80cabfad bellard
        counter = (s->count - d) & 0xffff;
53 80cabfad bellard
        break;
54 80cabfad bellard
    case 3:
55 80cabfad bellard
        /* XXX: may be incorrect for odd counts */
56 80cabfad bellard
        counter = s->count - ((2 * d) % s->count);
57 80cabfad bellard
        break;
58 80cabfad bellard
    default:
59 80cabfad bellard
        counter = s->count - (d % s->count);
60 80cabfad bellard
        break;
61 80cabfad bellard
    }
62 80cabfad bellard
    return counter;
63 80cabfad bellard
}
64 80cabfad bellard
65 80cabfad bellard
/* val must be 0 or 1 */
66 d11e859e Jan Kiszka
static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc,
67 d11e859e Jan Kiszka
                                 int val)
68 80cabfad bellard
{
69 d11e859e Jan Kiszka
    switch (sc->mode) {
70 80cabfad bellard
    default:
71 80cabfad bellard
    case 0:
72 80cabfad bellard
    case 4:
73 80cabfad bellard
        /* XXX: just disable/enable counting */
74 80cabfad bellard
        break;
75 80cabfad bellard
    case 1:
76 80cabfad bellard
    case 5:
77 d11e859e Jan Kiszka
        if (sc->gate < val) {
78 80cabfad bellard
            /* restart counting on rising edge */
79 d11e859e Jan Kiszka
            sc->count_load_time = qemu_get_clock_ns(vm_clock);
80 d11e859e Jan Kiszka
            pit_irq_timer_update(sc, sc->count_load_time);
81 80cabfad bellard
        }
82 80cabfad bellard
        break;
83 80cabfad bellard
    case 2:
84 80cabfad bellard
    case 3:
85 d11e859e Jan Kiszka
        if (sc->gate < val) {
86 80cabfad bellard
            /* restart counting on rising edge */
87 d11e859e Jan Kiszka
            sc->count_load_time = qemu_get_clock_ns(vm_clock);
88 d11e859e Jan Kiszka
            pit_irq_timer_update(sc, sc->count_load_time);
89 80cabfad bellard
        }
90 80cabfad bellard
        /* XXX: disable/enable counting */
91 80cabfad bellard
        break;
92 80cabfad bellard
    }
93 d11e859e Jan Kiszka
    sc->gate = val;
94 fd06c375 bellard
}
95 fd06c375 bellard
96 80cabfad bellard
static inline void pit_load_count(PITChannelState *s, int val)
97 80cabfad bellard
{
98 80cabfad bellard
    if (val == 0)
99 80cabfad bellard
        val = 0x10000;
100 74475455 Paolo Bonzini
    s->count_load_time = qemu_get_clock_ns(vm_clock);
101 80cabfad bellard
    s->count = val;
102 b0a21b53 bellard
    pit_irq_timer_update(s, s->count_load_time);
103 80cabfad bellard
}
104 80cabfad bellard
105 ec844b96 bellard
/* if already latched, do not latch again */
106 ec844b96 bellard
static void pit_latch_count(PITChannelState *s)
107 ec844b96 bellard
{
108 ec844b96 bellard
    if (!s->count_latched) {
109 ec844b96 bellard
        s->latched_count = pit_get_count(s);
110 ec844b96 bellard
        s->count_latched = s->rw_mode;
111 ec844b96 bellard
    }
112 ec844b96 bellard
}
113 ec844b96 bellard
114 b41a2cd1 bellard
static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
115 80cabfad bellard
{
116 d11e859e Jan Kiszka
    PITCommonState *pit = opaque;
117 80cabfad bellard
    int channel, access;
118 80cabfad bellard
    PITChannelState *s;
119 80cabfad bellard
120 80cabfad bellard
    addr &= 3;
121 80cabfad bellard
    if (addr == 3) {
122 80cabfad bellard
        channel = val >> 6;
123 ec844b96 bellard
        if (channel == 3) {
124 ec844b96 bellard
            /* read back command */
125 ec844b96 bellard
            for(channel = 0; channel < 3; channel++) {
126 ec844b96 bellard
                s = &pit->channels[channel];
127 ec844b96 bellard
                if (val & (2 << channel)) {
128 ec844b96 bellard
                    if (!(val & 0x20)) {
129 ec844b96 bellard
                        pit_latch_count(s);
130 ec844b96 bellard
                    }
131 ec844b96 bellard
                    if (!(val & 0x10) && !s->status_latched) {
132 ec844b96 bellard
                        /* status latch */
133 ec844b96 bellard
                        /* XXX: add BCD and null count */
134 4aa5d285 Jan Kiszka
                        s->status =
135 4aa5d285 Jan Kiszka
                            (pit_get_out(s,
136 4aa5d285 Jan Kiszka
                                         qemu_get_clock_ns(vm_clock)) << 7) |
137 ec844b96 bellard
                            (s->rw_mode << 4) |
138 ec844b96 bellard
                            (s->mode << 1) |
139 ec844b96 bellard
                            s->bcd;
140 ec844b96 bellard
                        s->status_latched = 1;
141 ec844b96 bellard
                    }
142 ec844b96 bellard
                }
143 ec844b96 bellard
            }
144 ec844b96 bellard
        } else {
145 ec844b96 bellard
            s = &pit->channels[channel];
146 ec844b96 bellard
            access = (val >> 4) & 3;
147 ec844b96 bellard
            if (access == 0) {
148 ec844b96 bellard
                pit_latch_count(s);
149 ec844b96 bellard
            } else {
150 ec844b96 bellard
                s->rw_mode = access;
151 ec844b96 bellard
                s->read_state = access;
152 ec844b96 bellard
                s->write_state = access;
153 ec844b96 bellard
154 ec844b96 bellard
                s->mode = (val >> 1) & 7;
155 ec844b96 bellard
                s->bcd = val & 1;
156 ec844b96 bellard
                /* XXX: update irq timer ? */
157 ec844b96 bellard
            }
158 80cabfad bellard
        }
159 80cabfad bellard
    } else {
160 ec844b96 bellard
        s = &pit->channels[addr];
161 ec844b96 bellard
        switch(s->write_state) {
162 ec844b96 bellard
        default:
163 80cabfad bellard
        case RW_STATE_LSB:
164 80cabfad bellard
            pit_load_count(s, val);
165 80cabfad bellard
            break;
166 80cabfad bellard
        case RW_STATE_MSB:
167 80cabfad bellard
            pit_load_count(s, val << 8);
168 80cabfad bellard
            break;
169 80cabfad bellard
        case RW_STATE_WORD0:
170 ec844b96 bellard
            s->write_latch = val;
171 ec844b96 bellard
            s->write_state = RW_STATE_WORD1;
172 ec844b96 bellard
            break;
173 80cabfad bellard
        case RW_STATE_WORD1:
174 ec844b96 bellard
            pit_load_count(s, s->write_latch | (val << 8));
175 ec844b96 bellard
            s->write_state = RW_STATE_WORD0;
176 80cabfad bellard
            break;
177 80cabfad bellard
        }
178 80cabfad bellard
    }
179 80cabfad bellard
}
180 80cabfad bellard
181 b41a2cd1 bellard
static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
182 80cabfad bellard
{
183 d11e859e Jan Kiszka
    PITCommonState *pit = opaque;
184 80cabfad bellard
    int ret, count;
185 80cabfad bellard
    PITChannelState *s;
186 3b46e624 ths
187 80cabfad bellard
    addr &= 3;
188 ec844b96 bellard
    s = &pit->channels[addr];
189 ec844b96 bellard
    if (s->status_latched) {
190 ec844b96 bellard
        s->status_latched = 0;
191 ec844b96 bellard
        ret = s->status;
192 ec844b96 bellard
    } else if (s->count_latched) {
193 ec844b96 bellard
        switch(s->count_latched) {
194 ec844b96 bellard
        default:
195 ec844b96 bellard
        case RW_STATE_LSB:
196 ec844b96 bellard
            ret = s->latched_count & 0xff;
197 ec844b96 bellard
            s->count_latched = 0;
198 ec844b96 bellard
            break;
199 ec844b96 bellard
        case RW_STATE_MSB:
200 80cabfad bellard
            ret = s->latched_count >> 8;
201 ec844b96 bellard
            s->count_latched = 0;
202 ec844b96 bellard
            break;
203 ec844b96 bellard
        case RW_STATE_WORD0:
204 80cabfad bellard
            ret = s->latched_count & 0xff;
205 ec844b96 bellard
            s->count_latched = RW_STATE_MSB;
206 ec844b96 bellard
            break;
207 ec844b96 bellard
        }
208 ec844b96 bellard
    } else {
209 ec844b96 bellard
        switch(s->read_state) {
210 ec844b96 bellard
        default:
211 ec844b96 bellard
        case RW_STATE_LSB:
212 ec844b96 bellard
            count = pit_get_count(s);
213 ec844b96 bellard
            ret = count & 0xff;
214 ec844b96 bellard
            break;
215 ec844b96 bellard
        case RW_STATE_MSB:
216 ec844b96 bellard
            count = pit_get_count(s);
217 ec844b96 bellard
            ret = (count >> 8) & 0xff;
218 ec844b96 bellard
            break;
219 ec844b96 bellard
        case RW_STATE_WORD0:
220 ec844b96 bellard
            count = pit_get_count(s);
221 ec844b96 bellard
            ret = count & 0xff;
222 ec844b96 bellard
            s->read_state = RW_STATE_WORD1;
223 ec844b96 bellard
            break;
224 ec844b96 bellard
        case RW_STATE_WORD1:
225 ec844b96 bellard
            count = pit_get_count(s);
226 ec844b96 bellard
            ret = (count >> 8) & 0xff;
227 ec844b96 bellard
            s->read_state = RW_STATE_WORD0;
228 ec844b96 bellard
            break;
229 ec844b96 bellard
        }
230 80cabfad bellard
    }
231 80cabfad bellard
    return ret;
232 80cabfad bellard
}
233 80cabfad bellard
234 b0a21b53 bellard
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
235 b0a21b53 bellard
{
236 b0a21b53 bellard
    int64_t expire_time;
237 b0a21b53 bellard
    int irq_level;
238 b0a21b53 bellard
239 ce967e2f Jan Kiszka
    if (!s->irq_timer || s->irq_disabled) {
240 b0a21b53 bellard
        return;
241 ce967e2f Jan Kiszka
    }
242 b0a21b53 bellard
    expire_time = pit_get_next_transition_time(s, current_time);
243 4aa5d285 Jan Kiszka
    irq_level = pit_get_out(s, current_time);
244 d537cf6c pbrook
    qemu_set_irq(s->irq, irq_level);
245 b0a21b53 bellard
#ifdef DEBUG_PIT
246 b0a21b53 bellard
    printf("irq_level=%d next_delay=%f\n",
247 5fafdf24 ths
           irq_level,
248 6ee093c9 Juan Quintela
           (double)(expire_time - current_time) / get_ticks_per_sec());
249 b0a21b53 bellard
#endif
250 b0a21b53 bellard
    s->next_transition_time = expire_time;
251 b0a21b53 bellard
    if (expire_time != -1)
252 b0a21b53 bellard
        qemu_mod_timer(s->irq_timer, expire_time);
253 b0a21b53 bellard
    else
254 b0a21b53 bellard
        qemu_del_timer(s->irq_timer);
255 b0a21b53 bellard
}
256 b0a21b53 bellard
257 b0a21b53 bellard
static void pit_irq_timer(void *opaque)
258 b0a21b53 bellard
{
259 b0a21b53 bellard
    PITChannelState *s = opaque;
260 b0a21b53 bellard
261 b0a21b53 bellard
    pit_irq_timer_update(s, s->next_transition_time);
262 b0a21b53 bellard
}
263 b0a21b53 bellard
264 d11e859e Jan Kiszka
static void pit_reset(DeviceState *dev)
265 b0a21b53 bellard
{
266 d11e859e Jan Kiszka
    PITCommonState *pit = DO_UPCAST(PITCommonState, dev.qdev, dev);
267 b0a21b53 bellard
    PITChannelState *s;
268 b0a21b53 bellard
269 d11e859e Jan Kiszka
    pit_reset_common(pit);
270 5122b431 Juan Quintela
271 d11e859e Jan Kiszka
    s = &pit->channels[0];
272 d11e859e Jan Kiszka
    if (!s->irq_disabled) {
273 d11e859e Jan Kiszka
        qemu_mod_timer(s->irq_timer, s->next_transition_time);
274 80cabfad bellard
    }
275 d7d02e3c bellard
}
276 d7d02e3c bellard
277 ce967e2f Jan Kiszka
/* When HPET is operating in legacy mode, suppress the ignored timer IRQ,
278 ce967e2f Jan Kiszka
 * reenable it when legacy mode is left again. */
279 ce967e2f Jan Kiszka
static void pit_irq_control(void *opaque, int n, int enable)
280 16b29ae1 aliguori
{
281 d11e859e Jan Kiszka
    PITCommonState *pit = opaque;
282 ce967e2f Jan Kiszka
    PITChannelState *s = &pit->channels[0];
283 ce967e2f Jan Kiszka
284 ce967e2f Jan Kiszka
    if (enable) {
285 ce967e2f Jan Kiszka
        s->irq_disabled = 0;
286 ce967e2f Jan Kiszka
        pit_irq_timer_update(s, qemu_get_clock_ns(vm_clock));
287 ce967e2f Jan Kiszka
    } else {
288 ce967e2f Jan Kiszka
        s->irq_disabled = 1;
289 ce967e2f Jan Kiszka
        qemu_del_timer(s->irq_timer);
290 ce967e2f Jan Kiszka
    }
291 16b29ae1 aliguori
}
292 16b29ae1 aliguori
293 60ea6aa8 Richard Henderson
static const MemoryRegionPortio pit_portio[] = {
294 60ea6aa8 Richard Henderson
    { 0, 4, 1, .write = pit_ioport_write },
295 60ea6aa8 Richard Henderson
    { 0, 3, 1, .read = pit_ioport_read },
296 60ea6aa8 Richard Henderson
    PORTIO_END_OF_LIST()
297 60ea6aa8 Richard Henderson
};
298 60ea6aa8 Richard Henderson
299 60ea6aa8 Richard Henderson
static const MemoryRegionOps pit_ioport_ops = {
300 60ea6aa8 Richard Henderson
    .old_portio = pit_portio
301 60ea6aa8 Richard Henderson
};
302 60ea6aa8 Richard Henderson
303 3fbc1c0c Jan Kiszka
static void pit_post_load(PITCommonState *s)
304 3fbc1c0c Jan Kiszka
{
305 3fbc1c0c Jan Kiszka
    PITChannelState *sc = &s->channels[0];
306 3fbc1c0c Jan Kiszka
307 3fbc1c0c Jan Kiszka
    if (sc->next_transition_time != -1) {
308 3fbc1c0c Jan Kiszka
        qemu_mod_timer(sc->irq_timer, sc->next_transition_time);
309 3fbc1c0c Jan Kiszka
    } else {
310 3fbc1c0c Jan Kiszka
        qemu_del_timer(sc->irq_timer);
311 3fbc1c0c Jan Kiszka
    }
312 3fbc1c0c Jan Kiszka
}
313 3fbc1c0c Jan Kiszka
314 d11e859e Jan Kiszka
static int pit_initfn(PITCommonState *pit)
315 d7d02e3c bellard
{
316 d7d02e3c bellard
    PITChannelState *s;
317 d7d02e3c bellard
318 d7d02e3c bellard
    s = &pit->channels[0];
319 d7d02e3c bellard
    /* the timer 0 is connected to an IRQ */
320 74475455 Paolo Bonzini
    s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
321 d11e859e Jan Kiszka
    qdev_init_gpio_out(&pit->dev.qdev, &s->irq, 1);
322 80cabfad bellard
323 60ea6aa8 Richard Henderson
    memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
324 ce967e2f Jan Kiszka
325 d11e859e Jan Kiszka
    qdev_init_gpio_in(&pit->dev.qdev, pit_irq_control, 1);
326 ca22a3a3 Jan Kiszka
327 64d7e9a4 Blue Swirl
    return 0;
328 64d7e9a4 Blue Swirl
}
329 64d7e9a4 Blue Swirl
330 39bffca2 Anthony Liguori
static Property pit_properties[] = {
331 d11e859e Jan Kiszka
    DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
332 39bffca2 Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
333 39bffca2 Anthony Liguori
};
334 39bffca2 Anthony Liguori
335 8f04ee08 Anthony Liguori
static void pit_class_initfn(ObjectClass *klass, void *data)
336 8f04ee08 Anthony Liguori
{
337 d11e859e Jan Kiszka
    PITCommonClass *k = PIT_COMMON_CLASS(klass);
338 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
339 d11e859e Jan Kiszka
340 d11e859e Jan Kiszka
    k->init = pit_initfn;
341 d11e859e Jan Kiszka
    k->set_channel_gate = pit_set_channel_gate;
342 d11e859e Jan Kiszka
    k->get_channel_info = pit_get_channel_info_common;
343 3fbc1c0c Jan Kiszka
    k->post_load = pit_post_load;
344 39bffca2 Anthony Liguori
    dc->reset = pit_reset;
345 39bffca2 Anthony Liguori
    dc->props = pit_properties;
346 8f04ee08 Anthony Liguori
}
347 8f04ee08 Anthony Liguori
348 39bffca2 Anthony Liguori
static TypeInfo pit_info = {
349 39bffca2 Anthony Liguori
    .name          = "isa-pit",
350 d11e859e Jan Kiszka
    .parent        = TYPE_PIT_COMMON,
351 d11e859e Jan Kiszka
    .instance_size = sizeof(PITCommonState),
352 39bffca2 Anthony Liguori
    .class_init    = pit_class_initfn,
353 64d7e9a4 Blue Swirl
};
354 64d7e9a4 Blue Swirl
355 83f7d43a Andreas Färber
static void pit_register_types(void)
356 64d7e9a4 Blue Swirl
{
357 39bffca2 Anthony Liguori
    type_register_static(&pit_info);
358 80cabfad bellard
}
359 83f7d43a Andreas Färber
360 83f7d43a Andreas Färber
type_init(pit_register_types)