diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2009-02-01 00:30:11 -0800 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2009-02-01 00:30:11 -0800 |
commit | 6b60a2970637129a39f04724ff082b2b0ffc1eb1 (patch) | |
tree | bbe1bd9e68b8bc919291de9e071bba559419163d | |
parent | 1c5b9773bd5676cdc4ee3c5d3658878ad82c59f9 (diff) | |
download | gem5-6b60a2970637129a39f04724ff082b2b0ffc1eb1.tar.xz |
X86: Fix the time keeping of the Local APIC timer.
-rw-r--r-- | src/arch/x86/interrupts.cc | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc index 4f7753703..29157b3f5 100644 --- a/src/arch/x86/interrupts.cc +++ b/src/arch/x86/interrupts.cc @@ -344,10 +344,19 @@ X86ISA::Interrupts::readReg(ApicRegIndex reg) break; case APIC_CURRENT_COUNT: { - assert(clock); - uint32_t val = regs[reg] - curTick / clock; - val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); - return val; + if (apicTimerEvent.scheduled()) { + assert(clock); + // Compute how many m5 ticks happen per count. + uint64_t ticksPerCount = clock * + divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]); + // Compute how many m5 ticks are left. + uint64_t val = apicTimerEvent.when() - curTick; + // Turn that into a count. + val = (val + ticksPerCount - 1) / ticksPerCount; + return val; + } else { + return 0; + } } default: break; @@ -441,19 +450,17 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) { assert(clock); newVal = bits(val, 31, 0); - uint32_t newCount = newVal * - (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16); - regs[APIC_CURRENT_COUNT] = newCount + curTick / clock; - // Find out how long a "tick" of the timer should take. - Tick timerTick = 16 * clock; + // Compute how many timer ticks we're being programmed for. + uint64_t newCount = newVal * + (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); // Schedule on the edge of the next tick plus the new count. - Tick offset = curTick % timerTick; + Tick offset = curTick % clock; if (offset) { reschedule(apicTimerEvent, - curTick + (newCount + 1) * timerTick - offset, true); + curTick + (newCount + 1) * clock - offset, true); } else { reschedule(apicTimerEvent, - curTick + newCount * timerTick, true); + curTick + newCount * clock, true); } } break; |