[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v6 5/8] i8254: fix inaccuracies in pit_get_out()
From: |
Matthew Ogilvie |
Subject: |
[Qemu-devel] [PATCH v6 5/8] i8254: fix inaccuracies in pit_get_out() |
Date: |
Sun, 30 Sep 2012 22:56:35 -0600 |
* Fix high-vs-low counting logic to match the timing diagrams
and descriptions in Intel's documentation (23124406.pdf).
* Improve reading back the count in mode 3.
* Handle GATE input properly with respect to the OUT line, and add
a FIXME comment for reading back the counter. GATE is hard wired
high for channel 0 (IRQ0), but it can be software controlled on
channel 2 (PC speaker).
The output line is now high much more often than before, especially
in modes 2 and 4, which might cause updates of the timer chip
to generate extra interrupts. But this should only be an issue for
some migration cases.
Signed-off-by: Matthew Ogilvie <address@hidden>
---
There are still some things not quite modeled correctly.
See the cover letter of this patch series for details, and
the FIXME comments added to the code.
hw/i8254.c | 24 ++++++++++++++++++++++--
hw/i8254_common.c | 18 ++++++------------
2 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/hw/i8254.c b/hw/i8254.c
index 77bd5e8..9168016 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -39,6 +39,15 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t
current_time);
static int pit_get_count(PITChannelState *s)
{
+ /* FIXME: Add some way to represent a paused timer and return
+ * the paused-at counter value, to better model:
+ * - gate-triggered modes (1 and 5),
+ * - gate-pausable modes,
+ * - [maybe] the "wait until next CLK pulse to load counter" logic,
+ * - [maybe/not clear] half-loaded counter logic for mode 0, and
+ * the "null count" status bit,
+ * - etc.
+ */
uint64_t d;
int counter;
@@ -52,8 +61,7 @@ static int pit_get_count(PITChannelState *s)
counter = (s->count - d) & 0xffff;
break;
case 3:
- /* XXX: may be incorrect for odd counts */
- counter = s->count - ((2 * d) % s->count);
+ counter = (s->count - ((2 * d) % s->count)) & 0xfffe;
break;
default:
counter = s->count - (d % s->count);
@@ -98,6 +106,18 @@ static inline void pit_load_count(PITChannelState *s, int
val)
if (val == 0)
val = 0x10000;
s->count_load_time = qemu_get_clock_ns(vm_clock);
+
+ /* In gate-triggered one-shot modes, indirectly model some pit_get_out()
+ * cases by setting the load time way back until gate-triggered.
+ * (Generally only affects reading status from channel 2 speaker,
+ * due to hard-wired gates on other channels.)
+ *
+ * FIXME: This might be redesigned if a paused timer state is added
+ * for pic_get_count().
+ */
+ if (s->mode == 1 || s->mode == 5)
+ s->count_load_time -= muldiv64(val+2, get_ticks_per_sec(), PIT_FREQ);
+
s->count = val;
pit_irq_timer_update(s, s->count_load_time);
}
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
index a03d7cd..dc13c99 100644
--- a/hw/i8254_common.c
+++ b/hw/i8254_common.c
@@ -50,24 +50,18 @@ int pit_get_out(PITChannelState *s, int64_t current_time)
switch (s->mode) {
default:
case 0:
- out = (d >= s->count);
- break;
case 1:
- out = (d < s->count);
+ out = (d >= s->count);
break;
case 2:
- if ((d % s->count) == 0 && d != 0) {
- out = 1;
- } else {
- out = 0;
- }
+ out = (d % s->count) != (s->count - 1) || s->gate == 0;
break;
case 3:
- out = (d % s->count) < ((s->count + 1) >> 1);
+ out = (d % s->count) < ((s->count + 1) >> 1) || s->gate == 0;
break;
case 4:
case 5:
- out = (d == s->count);
+ out = (d != s->count);
break;
}
return out;
@@ -93,10 +87,10 @@ int64_t pit_get_next_transition_time(PITChannelState *s,
int64_t current_time)
break;
case 2:
base = (d / s->count) * s->count;
- if ((d - base) == 0 && d != 0) {
+ if ((d - base) == s->count-1) {
next_time = base + s->count;
} else {
- next_time = base + s->count + 1;
+ next_time = base + s->count - 1;
}
break;
case 3:
--
1.7.10.2.484.gcd07cc5
- [Qemu-devel] [PATCH v6 0/8] i8254, i8259 and running Microport UNIX (ca 1987), Matthew Ogilvie, 2012/10/01
- [Qemu-devel] [PATCH v6 1/8] fix some debug printf format strings, Matthew Ogilvie, 2012/10/01
- [Qemu-devel] [PATCH v6 2/8] vl: fix -hdachs/-hda argument order parsing issues, Matthew Ogilvie, 2012/10/01
- [Qemu-devel] [PATCH v6 3/8] qemu-options.hx: mention retrace= VGA option, Matthew Ogilvie, 2012/10/01
- [Qemu-devel] [PATCH v6 5/8] i8254: fix inaccuracies in pit_get_out(),
Matthew Ogilvie <=
- [Qemu-devel] [PATCH v6 4/8] vga: add some optional CGA compatibility hacks, Matthew Ogilvie, 2012/10/01
- [Qemu-devel] [PATCH v6 6/8] i8259: fix so that dropping IRQ level always clears the interrupt request, Matthew Ogilvie, 2012/10/01
- [Qemu-devel] [PATCH v6 7/8] i8259: refactor pic_set_irq level logic, Matthew Ogilvie, 2012/10/01
- [Qemu-devel] [PATCH v6 8/8] i8259/i8254: migration workaround for timer, Matthew Ogilvie, 2012/10/01