summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2009-02-01 00:30:11 -0800
committerGabe Black <gblack@eecs.umich.edu>2009-02-01 00:30:11 -0800
commit6b60a2970637129a39f04724ff082b2b0ffc1eb1 (patch)
treebbe1bd9e68b8bc919291de9e071bba559419163d
parent1c5b9773bd5676cdc4ee3c5d3658878ad82c59f9 (diff)
downloadgem5-6b60a2970637129a39f04724ff082b2b0ffc1eb1.tar.xz
X86: Fix the time keeping of the Local APIC timer.
-rw-r--r--src/arch/x86/interrupts.cc31
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;