PC speaker emulation (Joachim Henke)
[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 "vl.h"
25
26 //#define DEBUG_PIT
27
28 #define RW_STATE_LSB 1
29 #define RW_STATE_MSB 2
30 #define RW_STATE_WORD0 3
31 #define RW_STATE_WORD1 4
32
33 typedef struct PITChannelState {
34     int count; /* can be 65536 */
35     uint16_t latched_count;
36     uint8_t count_latched;
37     uint8_t status_latched;
38     uint8_t status;
39     uint8_t read_state;
40     uint8_t write_state;
41     uint8_t write_latch;
42     uint8_t rw_mode;
43     uint8_t mode;
44     uint8_t bcd; /* not supported */
45     uint8_t gate; /* timer start */
46     int64_t count_load_time;
47     /* irq handling */
48     int64_t next_transition_time;
49     QEMUTimer *irq_timer;
50     int irq;
51 } PITChannelState;
52
53 struct PITState {
54     PITChannelState channels[3];
55 };
56
57 static PITState pit_state;
58
59 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
60
61 static int pit_get_count(PITChannelState *s)
62 {
63     uint64_t d;
64     int counter;
65
66     d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec);
67     switch(s->mode) {
68     case 0:
69     case 1:
70     case 4:
71     case 5:
72         counter = (s->count - d) & 0xffff;
73         break;
74     case 3:
75         /* XXX: may be incorrect for odd counts */
76         counter = s->count - ((2 * d) % s->count);
77         break;
78     default:
79         counter = s->count - (d % s->count);
80         break;
81     }
82     return counter;
83 }
84
85 /* get pit output bit */
86 static int pit_get_out1(PITChannelState *s, int64_t current_time)
87 {
88     uint64_t d;
89     int out;
90
91     d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
92     switch(s->mode) {
93     default:
94     case 0:
95         out = (d >= s->count);
96         break;
97     case 1:
98         out = (d < s->count);
99         break;
100     case 2:
101         if ((d % s->count) == 0 && d != 0)
102             out = 1;
103         else
104             out = 0;
105         break;
106     case 3:
107         out = (d % s->count) < ((s->count + 1) >> 1);
108         break;
109     case 4:
110     case 5:
111         out = (d == s->count);
112         break;
113     }
114     return out;
115 }
116
117 int pit_get_out(PITState *pit, int channel, int64_t current_time)
118 {
119     PITChannelState *s = &pit->channels[channel];
120     return pit_get_out1(s, current_time);
121 }
122
123 /* return -1 if no transition will occur.  */
124 static int64_t pit_get_next_transition_time(PITChannelState *s, 
125                                             int64_t current_time)
126 {
127     uint64_t d, next_time, base;
128     int period2;
129
130     d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
131     switch(s->mode) {
132     default:
133     case 0:
134     case 1:
135         if (d < s->count)
136             next_time = s->count;
137         else
138             return -1;
139         break;
140     case 2:
141         base = (d / s->count) * s->count;
142         if ((d - base) == 0 && d != 0)
143             next_time = base + s->count;
144         else
145             next_time = base + s->count + 1;
146         break;
147     case 3:
148         base = (d / s->count) * s->count;
149         period2 = ((s->count + 1) >> 1);
150         if ((d - base) < period2) 
151             next_time = base + period2;
152         else
153             next_time = base + s->count;
154         break;
155     case 4:
156     case 5:
157         if (d < s->count)
158             next_time = s->count;
159         else if (d == s->count)
160             next_time = s->count + 1;
161         else
162             return -1;
163         break;
164     }
165     /* convert to timer units */
166     next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ);
167     /* fix potential rounding problems */
168     /* XXX: better solution: use a clock at PIT_FREQ Hz */
169     if (next_time <= current_time)
170         next_time = current_time + 1;
171     return next_time;
172 }
173
174 /* val must be 0 or 1 */
175 void pit_set_gate(PITState *pit, int channel, int val)
176 {
177     PITChannelState *s = &pit->channels[channel];
178
179     switch(s->mode) {
180     default:
181     case 0:
182     case 4:
183         /* XXX: just disable/enable counting */
184         break;
185     case 1:
186     case 5:
187         if (s->gate < val) {
188             /* restart counting on rising edge */
189             s->count_load_time = qemu_get_clock(vm_clock);
190             pit_irq_timer_update(s, s->count_load_time);
191         }
192         break;
193     case 2:
194     case 3:
195         if (s->gate < val) {
196             /* restart counting on rising edge */
197             s->count_load_time = qemu_get_clock(vm_clock);
198             pit_irq_timer_update(s, s->count_load_time);
199         }
200         /* XXX: disable/enable counting */
201         break;
202     }
203     s->gate = val;
204 }
205
206 int pit_get_gate(PITState *pit, int channel)
207 {
208     PITChannelState *s = &pit->channels[channel];
209     return s->gate;
210 }
211
212 int pit_get_initial_count(PITState *pit, int channel)
213 {
214     PITChannelState *s = &pit->channels[channel];
215     return s->count;
216 }
217
218 int pit_get_mode(PITState *pit, int channel)
219 {
220     PITChannelState *s = &pit->channels[channel];
221     return s->mode;
222 }
223
224 static inline void pit_load_count(PITChannelState *s, int val)
225 {
226     if (val == 0)
227         val = 0x10000;
228     s->count_load_time = qemu_get_clock(vm_clock);
229     s->count = val;
230     pit_irq_timer_update(s, s->count_load_time);
231 }
232
233 /* if already latched, do not latch again */
234 static void pit_latch_count(PITChannelState *s)
235 {
236     if (!s->count_latched) {
237         s->latched_count = pit_get_count(s);
238         s->count_latched = s->rw_mode;
239     }
240 }
241
242 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
243 {
244     PITState *pit = opaque;
245     int channel, access;
246     PITChannelState *s;
247
248     addr &= 3;
249     if (addr == 3) {
250         channel = val >> 6;
251         if (channel == 3) {
252             /* read back command */
253             for(channel = 0; channel < 3; channel++) {
254                 s = &pit->channels[channel];
255                 if (val & (2 << channel)) {
256                     if (!(val & 0x20)) {
257                         pit_latch_count(s);
258                     }
259                     if (!(val & 0x10) && !s->status_latched) {
260                         /* status latch */
261                         /* XXX: add BCD and null count */
262                         s->status =  (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
263                             (s->rw_mode << 4) |
264                             (s->mode << 1) |
265                             s->bcd;
266                         s->status_latched = 1;
267                     }
268                 }
269             }
270         } else {
271             s = &pit->channels[channel];
272             access = (val >> 4) & 3;
273             if (access == 0) {
274                 pit_latch_count(s);
275             } else {
276                 s->rw_mode = access;
277                 s->read_state = access;
278                 s->write_state = access;
279
280                 s->mode = (val >> 1) & 7;
281                 s->bcd = val & 1;
282                 /* XXX: update irq timer ? */
283             }
284         }
285     } else {
286         s = &pit->channels[addr];
287         switch(s->write_state) {
288         default:
289         case RW_STATE_LSB:
290             pit_load_count(s, val);
291             break;
292         case RW_STATE_MSB:
293             pit_load_count(s, val << 8);
294             break;
295         case RW_STATE_WORD0:
296             s->write_latch = val;
297             s->write_state = RW_STATE_WORD1;
298             break;
299         case RW_STATE_WORD1:
300             pit_load_count(s, s->write_latch | (val << 8));
301             s->write_state = RW_STATE_WORD0;
302             break;
303         }
304     }
305 }
306
307 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
308 {
309     PITState *pit = opaque;
310     int ret, count;
311     PITChannelState *s;
312     
313     addr &= 3;
314     s = &pit->channels[addr];
315     if (s->status_latched) {
316         s->status_latched = 0;
317         ret = s->status;
318     } else if (s->count_latched) {
319         switch(s->count_latched) {
320         default:
321         case RW_STATE_LSB:
322             ret = s->latched_count & 0xff;
323             s->count_latched = 0;
324             break;
325         case RW_STATE_MSB:
326             ret = s->latched_count >> 8;
327             s->count_latched = 0;
328             break;
329         case RW_STATE_WORD0:
330             ret = s->latched_count & 0xff;
331             s->count_latched = RW_STATE_MSB;
332             break;
333         }
334     } else {
335         switch(s->read_state) {
336         default:
337         case RW_STATE_LSB:
338             count = pit_get_count(s);
339             ret = count & 0xff;
340             break;
341         case RW_STATE_MSB:
342             count = pit_get_count(s);
343             ret = (count >> 8) & 0xff;
344             break;
345         case RW_STATE_WORD0:
346             count = pit_get_count(s);
347             ret = count & 0xff;
348             s->read_state = RW_STATE_WORD1;
349             break;
350         case RW_STATE_WORD1:
351             count = pit_get_count(s);
352             ret = (count >> 8) & 0xff;
353             s->read_state = RW_STATE_WORD0;
354             break;
355         }
356     }
357     return ret;
358 }
359
360 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
361 {
362     int64_t expire_time;
363     int irq_level;
364
365     if (!s->irq_timer)
366         return;
367     expire_time = pit_get_next_transition_time(s, current_time);
368     irq_level = pit_get_out1(s, current_time);
369     pic_set_irq(s->irq, irq_level);
370 #ifdef DEBUG_PIT
371     printf("irq_level=%d next_delay=%f\n",
372            irq_level, 
373            (double)(expire_time - current_time) / ticks_per_sec);
374 #endif
375     s->next_transition_time = expire_time;
376     if (expire_time != -1)
377         qemu_mod_timer(s->irq_timer, expire_time);
378     else
379         qemu_del_timer(s->irq_timer);
380 }
381
382 static void pit_irq_timer(void *opaque)
383 {
384     PITChannelState *s = opaque;
385
386     pit_irq_timer_update(s, s->next_transition_time);
387 }
388
389 static void pit_save(QEMUFile *f, void *opaque)
390 {
391     PITState *pit = opaque;
392     PITChannelState *s;
393     int i;
394     
395     for(i = 0; i < 3; i++) {
396         s = &pit->channels[i];
397         qemu_put_be32s(f, &s->count);
398         qemu_put_be16s(f, &s->latched_count);
399         qemu_put_8s(f, &s->count_latched);
400         qemu_put_8s(f, &s->status_latched);
401         qemu_put_8s(f, &s->status);
402         qemu_put_8s(f, &s->read_state);
403         qemu_put_8s(f, &s->write_state);
404         qemu_put_8s(f, &s->write_latch);
405         qemu_put_8s(f, &s->rw_mode);
406         qemu_put_8s(f, &s->mode);
407         qemu_put_8s(f, &s->bcd);
408         qemu_put_8s(f, &s->gate);
409         qemu_put_be64s(f, &s->count_load_time);
410         if (s->irq_timer) {
411             qemu_put_be64s(f, &s->next_transition_time);
412             qemu_put_timer(f, s->irq_timer);
413         }
414     }
415 }
416
417 static int pit_load(QEMUFile *f, void *opaque, int version_id)
418 {
419     PITState *pit = opaque;
420     PITChannelState *s;
421     int i;
422     
423     if (version_id != 1)
424         return -EINVAL;
425
426     for(i = 0; i < 3; i++) {
427         s = &pit->channels[i];
428         qemu_get_be32s(f, &s->count);
429         qemu_get_be16s(f, &s->latched_count);
430         qemu_get_8s(f, &s->count_latched);
431         qemu_get_8s(f, &s->status_latched);
432         qemu_get_8s(f, &s->status);
433         qemu_get_8s(f, &s->read_state);
434         qemu_get_8s(f, &s->write_state);
435         qemu_get_8s(f, &s->write_latch);
436         qemu_get_8s(f, &s->rw_mode);
437         qemu_get_8s(f, &s->mode);
438         qemu_get_8s(f, &s->bcd);
439         qemu_get_8s(f, &s->gate);
440         qemu_get_be64s(f, &s->count_load_time);
441         if (s->irq_timer) {
442             qemu_get_be64s(f, &s->next_transition_time);
443             qemu_get_timer(f, s->irq_timer);
444         }
445     }
446     return 0;
447 }
448
449 static void pit_reset(void *opaque)
450 {
451     PITState *pit = opaque;
452     PITChannelState *s;
453     int i;
454
455     for(i = 0;i < 3; i++) {
456         s = &pit->channels[i];
457         s->mode = 3;
458         s->gate = (i != 2);
459         pit_load_count(s, 0);
460     }
461 }
462
463 PITState *pit_init(int base, int irq)
464 {
465     PITState *pit = &pit_state;
466     PITChannelState *s;
467
468     s = &pit->channels[0];
469     /* the timer 0 is connected to an IRQ */
470     s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
471     s->irq = irq;
472
473     register_savevm("i8254", base, 1, pit_save, pit_load, pit);
474
475     qemu_register_reset(pit_reset, pit);
476     register_ioport_write(base, 4, 1, pit_ioport_write, pit);
477     register_ioport_read(base, 3, 1, pit_ioport_read, pit);
478
479     pit_reset(pit);
480
481     return pit;
482 }