configure: change "found" to "find"
[qemu] / hw / i8254.c
1 /*
2  * QEMU 8253/8254 interval timer emulation
3  *
4  * Copyright (c) 2003-2004 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "hw.h"
25 #include "pc.h"
26 #include "isa.h"
27 #include "qemu-timer.h"
28
29 //#define DEBUG_PIT
30
31 #define RW_STATE_LSB 1
32 #define RW_STATE_MSB 2
33 #define RW_STATE_WORD0 3
34 #define RW_STATE_WORD1 4
35
36 typedef struct PITChannelState {
37     int count; /* can be 65536 */
38     uint16_t latched_count;
39     uint8_t count_latched;
40     uint8_t status_latched;
41     uint8_t status;
42     uint8_t read_state;
43     uint8_t write_state;
44     uint8_t write_latch;
45     uint8_t rw_mode;
46     uint8_t mode;
47     uint8_t bcd; /* not supported */
48     uint8_t gate; /* timer start */
49     int64_t count_load_time;
50     /* irq handling */
51     int64_t next_transition_time;
52     QEMUTimer *irq_timer;
53     qemu_irq irq;
54 } PITChannelState;
55
56 struct PITState {
57     PITChannelState channels[3];
58 };
59
60 static PITState pit_state;
61
62 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
63
64 static int pit_get_count(PITChannelState *s)
65 {
66     uint64_t d;
67     int counter;
68
69     d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ,
70                  get_ticks_per_sec());
71     switch(s->mode) {
72     case 0:
73     case 1:
74     case 4:
75     case 5:
76         counter = (s->count - d) & 0xffff;
77         break;
78     case 3:
79         /* XXX: may be incorrect for odd counts */
80         counter = s->count - ((2 * d) % s->count);
81         break;
82     default:
83         counter = s->count - (d % s->count);
84         break;
85     }
86     return counter;
87 }
88
89 /* get pit output bit */
90 static int pit_get_out1(PITChannelState *s, int64_t current_time)
91 {
92     uint64_t d;
93     int out;
94
95     d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
96                  get_ticks_per_sec());
97     switch(s->mode) {
98     default:
99     case 0:
100         out = (d >= s->count);
101         break;
102     case 1:
103         out = (d < s->count);
104         break;
105     case 2:
106         if ((d % s->count) == 0 && d != 0)
107             out = 1;
108         else
109             out = 0;
110         break;
111     case 3:
112         out = (d % s->count) < ((s->count + 1) >> 1);
113         break;
114     case 4:
115     case 5:
116         out = (d == s->count);
117         break;
118     }
119     return out;
120 }
121
122 int pit_get_out(PITState *pit, int channel, int64_t current_time)
123 {
124     PITChannelState *s = &pit->channels[channel];
125     return pit_get_out1(s, current_time);
126 }
127
128 /* return -1 if no transition will occur.  */
129 static int64_t pit_get_next_transition_time(PITChannelState *s,
130                                             int64_t current_time)
131 {
132     uint64_t d, next_time, base;
133     int period2;
134
135     d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
136                  get_ticks_per_sec());
137     switch(s->mode) {
138     default:
139     case 0:
140     case 1:
141         if (d < s->count)
142             next_time = s->count;
143         else
144             return -1;
145         break;
146     case 2:
147         base = (d / s->count) * s->count;
148         if ((d - base) == 0 && d != 0)
149             next_time = base + s->count;
150         else
151             next_time = base + s->count + 1;
152         break;
153     case 3:
154         base = (d / s->count) * s->count;
155         period2 = ((s->count + 1) >> 1);
156         if ((d - base) < period2)
157             next_time = base + period2;
158         else
159             next_time = base + s->count;
160         break;
161     case 4:
162     case 5:
163         if (d < s->count)
164             next_time = s->count;
165         else if (d == s->count)
166             next_time = s->count + 1;
167         else
168             return -1;
169         break;
170     }
171     /* convert to timer units */
172     next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
173                                               PIT_FREQ);
174     /* fix potential rounding problems */
175     /* XXX: better solution: use a clock at PIT_FREQ Hz */
176     if (next_time <= current_time)
177         next_time = current_time + 1;
178     return next_time;
179 }
180
181 /* val must be 0 or 1 */
182 void pit_set_gate(PITState *pit, int channel, int val)
183 {
184     PITChannelState *s = &pit->channels[channel];
185
186     switch(s->mode) {
187     default:
188     case 0:
189     case 4:
190         /* XXX: just disable/enable counting */
191         break;
192     case 1:
193     case 5:
194         if (s->gate < val) {
195             /* restart counting on rising edge */
196             s->count_load_time = qemu_get_clock(vm_clock);
197             pit_irq_timer_update(s, s->count_load_time);
198         }
199         break;
200     case 2:
201     case 3:
202         if (s->gate < val) {
203             /* restart counting on rising edge */
204             s->count_load_time = qemu_get_clock(vm_clock);
205             pit_irq_timer_update(s, s->count_load_time);
206         }
207         /* XXX: disable/enable counting */
208         break;
209     }
210     s->gate = val;
211 }
212
213 int pit_get_gate(PITState *pit, int channel)
214 {
215     PITChannelState *s = &pit->channels[channel];
216     return s->gate;
217 }
218
219 int pit_get_initial_count(PITState *pit, int channel)
220 {
221     PITChannelState *s = &pit->channels[channel];
222     return s->count;
223 }
224
225 int pit_get_mode(PITState *pit, int channel)
226 {
227     PITChannelState *s = &pit->channels[channel];
228     return s->mode;
229 }
230
231 static inline void pit_load_count(PITChannelState *s, int val)
232 {
233     if (val == 0)
234         val = 0x10000;
235     s->count_load_time = qemu_get_clock(vm_clock);
236     s->count = val;
237     pit_irq_timer_update(s, s->count_load_time);
238 }
239
240 /* if already latched, do not latch again */
241 static void pit_latch_count(PITChannelState *s)
242 {
243     if (!s->count_latched) {
244         s->latched_count = pit_get_count(s);
245         s->count_latched = s->rw_mode;
246     }
247 }
248
249 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
250 {
251     PITState *pit = opaque;
252     int channel, access;
253     PITChannelState *s;
254
255     addr &= 3;
256     if (addr == 3) {
257         channel = val >> 6;
258         if (channel == 3) {
259             /* read back command */
260             for(channel = 0; channel < 3; channel++) {
261                 s = &pit->channels[channel];
262                 if (val & (2 << channel)) {
263                     if (!(val & 0x20)) {
264                         pit_latch_count(s);
265                     }
266                     if (!(val & 0x10) && !s->status_latched) {
267                         /* status latch */
268                         /* XXX: add BCD and null count */
269                         s->status =  (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
270                             (s->rw_mode << 4) |
271                             (s->mode << 1) |
272                             s->bcd;
273                         s->status_latched = 1;
274                     }
275                 }
276             }
277         } else {
278             s = &pit->channels[channel];
279             access = (val >> 4) & 3;
280             if (access == 0) {
281                 pit_latch_count(s);
282             } else {
283                 s->rw_mode = access;
284                 s->read_state = access;
285                 s->write_state = access;
286
287                 s->mode = (val >> 1) & 7;
288                 s->bcd = val & 1;
289                 /* XXX: update irq timer ? */
290             }
291         }
292     } else {
293         s = &pit->channels[addr];
294         switch(s->write_state) {
295         default:
296         case RW_STATE_LSB:
297             pit_load_count(s, val);
298             break;
299         case RW_STATE_MSB:
300             pit_load_count(s, val << 8);
301             break;
302         case RW_STATE_WORD0:
303             s->write_latch = val;
304             s->write_state = RW_STATE_WORD1;
305             break;
306         case RW_STATE_WORD1:
307             pit_load_count(s, s->write_latch | (val << 8));
308             s->write_state = RW_STATE_WORD0;
309             break;
310         }
311     }
312 }
313
314 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
315 {
316     PITState *pit = opaque;
317     int ret, count;
318     PITChannelState *s;
319
320     addr &= 3;
321     s = &pit->channels[addr];
322     if (s->status_latched) {
323         s->status_latched = 0;
324         ret = s->status;
325     } else if (s->count_latched) {
326         switch(s->count_latched) {
327         default:
328         case RW_STATE_LSB:
329             ret = s->latched_count & 0xff;
330             s->count_latched = 0;
331             break;
332         case RW_STATE_MSB:
333             ret = s->latched_count >> 8;
334             s->count_latched = 0;
335             break;
336         case RW_STATE_WORD0:
337             ret = s->latched_count & 0xff;
338             s->count_latched = RW_STATE_MSB;
339             break;
340         }
341     } else {
342         switch(s->read_state) {
343         default:
344         case RW_STATE_LSB:
345             count = pit_get_count(s);
346             ret = count & 0xff;
347             break;
348         case RW_STATE_MSB:
349             count = pit_get_count(s);
350             ret = (count >> 8) & 0xff;
351             break;
352         case RW_STATE_WORD0:
353             count = pit_get_count(s);
354             ret = count & 0xff;
355             s->read_state = RW_STATE_WORD1;
356             break;
357         case RW_STATE_WORD1:
358             count = pit_get_count(s);
359             ret = (count >> 8) & 0xff;
360             s->read_state = RW_STATE_WORD0;
361             break;
362         }
363     }
364     return ret;
365 }
366
367 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
368 {
369     int64_t expire_time;
370     int irq_level;
371
372     if (!s->irq_timer)
373         return;
374     expire_time = pit_get_next_transition_time(s, current_time);
375     irq_level = pit_get_out1(s, current_time);
376     qemu_set_irq(s->irq, irq_level);
377 #ifdef DEBUG_PIT
378     printf("irq_level=%d next_delay=%f\n",
379            irq_level,
380            (double)(expire_time - current_time) / get_ticks_per_sec());
381 #endif
382     s->next_transition_time = expire_time;
383     if (expire_time != -1)
384         qemu_mod_timer(s->irq_timer, expire_time);
385     else
386         qemu_del_timer(s->irq_timer);
387 }
388
389 static void pit_irq_timer(void *opaque)
390 {
391     PITChannelState *s = opaque;
392
393     pit_irq_timer_update(s, s->next_transition_time);
394 }
395
396 static const VMStateDescription vmstate_pit_channel = {
397     .name = "pit channel",
398     .version_id = 2,
399     .minimum_version_id = 2,
400     .minimum_version_id_old = 2,
401     .fields      = (VMStateField []) {
402         VMSTATE_INT32(count, PITChannelState),
403         VMSTATE_UINT16(latched_count, PITChannelState),
404         VMSTATE_UINT8(count_latched, PITChannelState),
405         VMSTATE_UINT8(status_latched, PITChannelState),
406         VMSTATE_UINT8(status, PITChannelState),
407         VMSTATE_UINT8(read_state, PITChannelState),
408         VMSTATE_UINT8(write_state, PITChannelState),
409         VMSTATE_UINT8(write_latch, PITChannelState),
410         VMSTATE_UINT8(rw_mode, PITChannelState),
411         VMSTATE_UINT8(mode, PITChannelState),
412         VMSTATE_UINT8(bcd, PITChannelState),
413         VMSTATE_UINT8(gate, PITChannelState),
414         VMSTATE_INT64(count_load_time, PITChannelState),
415         VMSTATE_INT64(next_transition_time, PITChannelState),
416         VMSTATE_END_OF_LIST()
417     }
418 };
419
420 static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
421 {
422     PITState *pit = opaque;
423     PITChannelState *s;
424     int i;
425
426     if (version_id != 1)
427         return -EINVAL;
428
429     for(i = 0; i < 3; i++) {
430         s = &pit->channels[i];
431         s->count=qemu_get_be32(f);
432         qemu_get_be16s(f, &s->latched_count);
433         qemu_get_8s(f, &s->count_latched);
434         qemu_get_8s(f, &s->status_latched);
435         qemu_get_8s(f, &s->status);
436         qemu_get_8s(f, &s->read_state);
437         qemu_get_8s(f, &s->write_state);
438         qemu_get_8s(f, &s->write_latch);
439         qemu_get_8s(f, &s->rw_mode);
440         qemu_get_8s(f, &s->mode);
441         qemu_get_8s(f, &s->bcd);
442         qemu_get_8s(f, &s->gate);
443         s->count_load_time=qemu_get_be64(f);
444         if (s->irq_timer) {
445             s->next_transition_time=qemu_get_be64(f);
446             qemu_get_timer(f, s->irq_timer);
447         }
448     }
449     return 0;
450 }
451
452 static const VMStateDescription vmstate_pit = {
453     .name = "i8254",
454     .version_id = 2,
455     .minimum_version_id = 2,
456     .minimum_version_id_old = 1,
457     .load_state_old = pit_load_old,
458     .fields      = (VMStateField []) {
459         VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
460         VMSTATE_TIMER(channels[0].irq_timer, PITState),
461         VMSTATE_END_OF_LIST()
462     }
463 };
464
465 static void pit_reset(void *opaque)
466 {
467     PITState *pit = opaque;
468     PITChannelState *s;
469     int i;
470
471     for(i = 0;i < 3; i++) {
472         s = &pit->channels[i];
473         s->mode = 3;
474         s->gate = (i != 2);
475         pit_load_count(s, 0);
476     }
477 }
478
479 /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
480 void hpet_pit_disable(void) {
481     PITChannelState *s;
482     s = &pit_state.channels[0];
483     if (s->irq_timer)
484         qemu_del_timer(s->irq_timer);
485 }
486
487 /* When HPET is reset or leaving legacy mode, it must reenable i8254
488  * timer 0
489  */
490
491 void hpet_pit_enable(void)
492 {
493     PITState *pit = &pit_state;
494     PITChannelState *s;
495     s = &pit->channels[0];
496     s->mode = 3;
497     s->gate = 1;
498     pit_load_count(s, 0);
499 }
500
501 PITState *pit_init(int base, qemu_irq irq)
502 {
503     PITState *pit = &pit_state;
504     PITChannelState *s;
505
506     s = &pit->channels[0];
507     /* the timer 0 is connected to an IRQ */
508     s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
509     s->irq = irq;
510
511     vmstate_register(base, &vmstate_pit, pit);
512     qemu_register_reset(pit_reset, pit);
513     register_ioport_write(base, 4, 1, pit_ioport_write, pit);
514     register_ioport_read(base, 3, 1, pit_ioport_read, pit);
515
516     pit_reset(pit);
517
518     return pit;
519 }