]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - hw/i8254.c
cf9ed2ff25f381cad04454fb957cf7abbff900ff
[lisovros/qemu_apohw.git] / 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 typedef struct PITState {
57     ISADevice dev;
58     MemoryRegion ioports;
59     uint32_t irq;
60     uint32_t iobase;
61     PITChannelState channels[3];
62 } PITState;
63
64 static PITState pit_state;
65
66 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
67
68 static int pit_get_count(PITChannelState *s)
69 {
70     uint64_t d;
71     int counter;
72
73     d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
74                  get_ticks_per_sec());
75     switch(s->mode) {
76     case 0:
77     case 1:
78     case 4:
79     case 5:
80         counter = (s->count - d) & 0xffff;
81         break;
82     case 3:
83         /* XXX: may be incorrect for odd counts */
84         counter = s->count - ((2 * d) % s->count);
85         break;
86     default:
87         counter = s->count - (d % s->count);
88         break;
89     }
90     return counter;
91 }
92
93 /* get pit output bit */
94 static int pit_get_out1(PITChannelState *s, int64_t current_time)
95 {
96     uint64_t d;
97     int out;
98
99     d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
100                  get_ticks_per_sec());
101     switch(s->mode) {
102     default:
103     case 0:
104         out = (d >= s->count);
105         break;
106     case 1:
107         out = (d < s->count);
108         break;
109     case 2:
110         if ((d % s->count) == 0 && d != 0)
111             out = 1;
112         else
113             out = 0;
114         break;
115     case 3:
116         out = (d % s->count) < ((s->count + 1) >> 1);
117         break;
118     case 4:
119     case 5:
120         out = (d == s->count);
121         break;
122     }
123     return out;
124 }
125
126 int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
127 {
128     PITState *pit = DO_UPCAST(PITState, dev, dev);
129     PITChannelState *s = &pit->channels[channel];
130     return pit_get_out1(s, current_time);
131 }
132
133 /* return -1 if no transition will occur.  */
134 static int64_t pit_get_next_transition_time(PITChannelState *s,
135                                             int64_t current_time)
136 {
137     uint64_t d, next_time, base;
138     int period2;
139
140     d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
141                  get_ticks_per_sec());
142     switch(s->mode) {
143     default:
144     case 0:
145     case 1:
146         if (d < s->count)
147             next_time = s->count;
148         else
149             return -1;
150         break;
151     case 2:
152         base = (d / s->count) * s->count;
153         if ((d - base) == 0 && d != 0)
154             next_time = base + s->count;
155         else
156             next_time = base + s->count + 1;
157         break;
158     case 3:
159         base = (d / s->count) * s->count;
160         period2 = ((s->count + 1) >> 1);
161         if ((d - base) < period2)
162             next_time = base + period2;
163         else
164             next_time = base + s->count;
165         break;
166     case 4:
167     case 5:
168         if (d < s->count)
169             next_time = s->count;
170         else if (d == s->count)
171             next_time = s->count + 1;
172         else
173             return -1;
174         break;
175     }
176     /* convert to timer units */
177     next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
178                                               PIT_FREQ);
179     /* fix potential rounding problems */
180     /* XXX: better solution: use a clock at PIT_FREQ Hz */
181     if (next_time <= current_time)
182         next_time = current_time + 1;
183     return next_time;
184 }
185
186 /* val must be 0 or 1 */
187 void pit_set_gate(ISADevice *dev, int channel, int val)
188 {
189     PITState *pit = DO_UPCAST(PITState, dev, dev);
190     PITChannelState *s = &pit->channels[channel];
191
192     switch(s->mode) {
193     default:
194     case 0:
195     case 4:
196         /* XXX: just disable/enable counting */
197         break;
198     case 1:
199     case 5:
200         if (s->gate < val) {
201             /* restart counting on rising edge */
202             s->count_load_time = qemu_get_clock_ns(vm_clock);
203             pit_irq_timer_update(s, s->count_load_time);
204         }
205         break;
206     case 2:
207     case 3:
208         if (s->gate < val) {
209             /* restart counting on rising edge */
210             s->count_load_time = qemu_get_clock_ns(vm_clock);
211             pit_irq_timer_update(s, s->count_load_time);
212         }
213         /* XXX: disable/enable counting */
214         break;
215     }
216     s->gate = val;
217 }
218
219 int pit_get_gate(ISADevice *dev, int channel)
220 {
221     PITState *pit = DO_UPCAST(PITState, dev, dev);
222     PITChannelState *s = &pit->channels[channel];
223     return s->gate;
224 }
225
226 int pit_get_initial_count(ISADevice *dev, int channel)
227 {
228     PITState *pit = DO_UPCAST(PITState, dev, dev);
229     PITChannelState *s = &pit->channels[channel];
230     return s->count;
231 }
232
233 int pit_get_mode(ISADevice *dev, int channel)
234 {
235     PITState *pit = DO_UPCAST(PITState, dev, dev);
236     PITChannelState *s = &pit->channels[channel];
237     return s->mode;
238 }
239
240 static inline void pit_load_count(PITChannelState *s, int val)
241 {
242     if (val == 0)
243         val = 0x10000;
244     s->count_load_time = qemu_get_clock_ns(vm_clock);
245     s->count = val;
246     pit_irq_timer_update(s, s->count_load_time);
247 }
248
249 /* if already latched, do not latch again */
250 static void pit_latch_count(PITChannelState *s)
251 {
252     if (!s->count_latched) {
253         s->latched_count = pit_get_count(s);
254         s->count_latched = s->rw_mode;
255     }
256 }
257
258 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
259 {
260     PITState *pit = opaque;
261     int channel, access;
262     PITChannelState *s;
263
264     addr &= 3;
265     if (addr == 3) {
266         channel = val >> 6;
267         if (channel == 3) {
268             /* read back command */
269             for(channel = 0; channel < 3; channel++) {
270                 s = &pit->channels[channel];
271                 if (val & (2 << channel)) {
272                     if (!(val & 0x20)) {
273                         pit_latch_count(s);
274                     }
275                     if (!(val & 0x10) && !s->status_latched) {
276                         /* status latch */
277                         /* XXX: add BCD and null count */
278                         s->status =  (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
279                             (s->rw_mode << 4) |
280                             (s->mode << 1) |
281                             s->bcd;
282                         s->status_latched = 1;
283                     }
284                 }
285             }
286         } else {
287             s = &pit->channels[channel];
288             access = (val >> 4) & 3;
289             if (access == 0) {
290                 pit_latch_count(s);
291             } else {
292                 s->rw_mode = access;
293                 s->read_state = access;
294                 s->write_state = access;
295
296                 s->mode = (val >> 1) & 7;
297                 s->bcd = val & 1;
298                 /* XXX: update irq timer ? */
299             }
300         }
301     } else {
302         s = &pit->channels[addr];
303         switch(s->write_state) {
304         default:
305         case RW_STATE_LSB:
306             pit_load_count(s, val);
307             break;
308         case RW_STATE_MSB:
309             pit_load_count(s, val << 8);
310             break;
311         case RW_STATE_WORD0:
312             s->write_latch = val;
313             s->write_state = RW_STATE_WORD1;
314             break;
315         case RW_STATE_WORD1:
316             pit_load_count(s, s->write_latch | (val << 8));
317             s->write_state = RW_STATE_WORD0;
318             break;
319         }
320     }
321 }
322
323 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
324 {
325     PITState *pit = opaque;
326     int ret, count;
327     PITChannelState *s;
328
329     addr &= 3;
330     s = &pit->channels[addr];
331     if (s->status_latched) {
332         s->status_latched = 0;
333         ret = s->status;
334     } else if (s->count_latched) {
335         switch(s->count_latched) {
336         default:
337         case RW_STATE_LSB:
338             ret = s->latched_count & 0xff;
339             s->count_latched = 0;
340             break;
341         case RW_STATE_MSB:
342             ret = s->latched_count >> 8;
343             s->count_latched = 0;
344             break;
345         case RW_STATE_WORD0:
346             ret = s->latched_count & 0xff;
347             s->count_latched = RW_STATE_MSB;
348             break;
349         }
350     } else {
351         switch(s->read_state) {
352         default:
353         case RW_STATE_LSB:
354             count = pit_get_count(s);
355             ret = count & 0xff;
356             break;
357         case RW_STATE_MSB:
358             count = pit_get_count(s);
359             ret = (count >> 8) & 0xff;
360             break;
361         case RW_STATE_WORD0:
362             count = pit_get_count(s);
363             ret = count & 0xff;
364             s->read_state = RW_STATE_WORD1;
365             break;
366         case RW_STATE_WORD1:
367             count = pit_get_count(s);
368             ret = (count >> 8) & 0xff;
369             s->read_state = RW_STATE_WORD0;
370             break;
371         }
372     }
373     return ret;
374 }
375
376 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
377 {
378     int64_t expire_time;
379     int irq_level;
380
381     if (!s->irq_timer)
382         return;
383     expire_time = pit_get_next_transition_time(s, current_time);
384     irq_level = pit_get_out1(s, current_time);
385     qemu_set_irq(s->irq, irq_level);
386 #ifdef DEBUG_PIT
387     printf("irq_level=%d next_delay=%f\n",
388            irq_level,
389            (double)(expire_time - current_time) / get_ticks_per_sec());
390 #endif
391     s->next_transition_time = expire_time;
392     if (expire_time != -1)
393         qemu_mod_timer(s->irq_timer, expire_time);
394     else
395         qemu_del_timer(s->irq_timer);
396 }
397
398 static void pit_irq_timer(void *opaque)
399 {
400     PITChannelState *s = opaque;
401
402     pit_irq_timer_update(s, s->next_transition_time);
403 }
404
405 static const VMStateDescription vmstate_pit_channel = {
406     .name = "pit channel",
407     .version_id = 2,
408     .minimum_version_id = 2,
409     .minimum_version_id_old = 2,
410     .fields      = (VMStateField []) {
411         VMSTATE_INT32(count, PITChannelState),
412         VMSTATE_UINT16(latched_count, PITChannelState),
413         VMSTATE_UINT8(count_latched, PITChannelState),
414         VMSTATE_UINT8(status_latched, PITChannelState),
415         VMSTATE_UINT8(status, PITChannelState),
416         VMSTATE_UINT8(read_state, PITChannelState),
417         VMSTATE_UINT8(write_state, PITChannelState),
418         VMSTATE_UINT8(write_latch, PITChannelState),
419         VMSTATE_UINT8(rw_mode, PITChannelState),
420         VMSTATE_UINT8(mode, PITChannelState),
421         VMSTATE_UINT8(bcd, PITChannelState),
422         VMSTATE_UINT8(gate, PITChannelState),
423         VMSTATE_INT64(count_load_time, PITChannelState),
424         VMSTATE_INT64(next_transition_time, PITChannelState),
425         VMSTATE_END_OF_LIST()
426     }
427 };
428
429 static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
430 {
431     PITState *pit = opaque;
432     PITChannelState *s;
433     int i;
434
435     if (version_id != 1)
436         return -EINVAL;
437
438     for(i = 0; i < 3; i++) {
439         s = &pit->channels[i];
440         s->count=qemu_get_be32(f);
441         qemu_get_be16s(f, &s->latched_count);
442         qemu_get_8s(f, &s->count_latched);
443         qemu_get_8s(f, &s->status_latched);
444         qemu_get_8s(f, &s->status);
445         qemu_get_8s(f, &s->read_state);
446         qemu_get_8s(f, &s->write_state);
447         qemu_get_8s(f, &s->write_latch);
448         qemu_get_8s(f, &s->rw_mode);
449         qemu_get_8s(f, &s->mode);
450         qemu_get_8s(f, &s->bcd);
451         qemu_get_8s(f, &s->gate);
452         s->count_load_time=qemu_get_be64(f);
453         if (s->irq_timer) {
454             s->next_transition_time=qemu_get_be64(f);
455             qemu_get_timer(f, s->irq_timer);
456         }
457     }
458     return 0;
459 }
460
461 static const VMStateDescription vmstate_pit = {
462     .name = "i8254",
463     .version_id = 2,
464     .minimum_version_id = 2,
465     .minimum_version_id_old = 1,
466     .load_state_old = pit_load_old,
467     .fields      = (VMStateField []) {
468         VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
469         VMSTATE_TIMER(channels[0].irq_timer, PITState),
470         VMSTATE_END_OF_LIST()
471     }
472 };
473
474 static void pit_reset(DeviceState *dev)
475 {
476     PITState *pit = container_of(dev, PITState, dev.qdev);
477     PITChannelState *s;
478     int i;
479
480     for(i = 0;i < 3; i++) {
481         s = &pit->channels[i];
482         s->mode = 3;
483         s->gate = (i != 2);
484         pit_load_count(s, 0);
485     }
486 }
487
488 /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
489 void hpet_pit_disable(void) {
490     PITChannelState *s;
491     s = &pit_state.channels[0];
492     if (s->irq_timer)
493         qemu_del_timer(s->irq_timer);
494 }
495
496 /* When HPET is reset or leaving legacy mode, it must reenable i8254
497  * timer 0
498  */
499
500 void hpet_pit_enable(void)
501 {
502     PITState *pit = &pit_state;
503     PITChannelState *s;
504     s = &pit->channels[0];
505     s->mode = 3;
506     s->gate = 1;
507     pit_load_count(s, 0);
508 }
509
510 static const MemoryRegionPortio pit_portio[] = {
511     { 0, 4, 1, .write = pit_ioport_write },
512     { 0, 3, 1, .read = pit_ioport_read },
513     PORTIO_END_OF_LIST()
514 };
515
516 static const MemoryRegionOps pit_ioport_ops = {
517     .old_portio = pit_portio
518 };
519
520 static int pit_initfn(ISADevice *dev)
521 {
522     PITState *pit = DO_UPCAST(PITState, dev, dev);
523     PITChannelState *s;
524
525     s = &pit->channels[0];
526     /* the timer 0 is connected to an IRQ */
527     s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
528     s->irq = isa_get_irq(dev, pit->irq);
529
530     memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
531     isa_register_ioport(dev, &pit->ioports, pit->iobase);
532
533     qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
534
535     return 0;
536 }
537
538 static ISADeviceInfo pit_info = {
539     .qdev.name     = "isa-pit",
540     .qdev.size     = sizeof(PITState),
541     .qdev.vmsd     = &vmstate_pit,
542     .qdev.reset    = pit_reset,
543     .qdev.no_user  = 1,
544     .init          = pit_initfn,
545     .qdev.props = (Property[]) {
546         DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
547         DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
548         DEFINE_PROP_END_OF_LIST(),
549     },
550 };
551
552 static void pit_register(void)
553 {
554     isa_qdev_register(&pit_info);
555 }
556 device_init(pit_register)