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