x86: Move APIC clock divider to Python

This patch moves the 16x APIC clock divider to the Python code to
avoid the post-instantiation modifications to the clock. The x86 APIC
was the only object setting the clock after creation time and this
required some custom functionality and configuration. With this patch,
the clock multiplier is moved to the Python code and the objects are
instantiated with the appropriate clock.
This commit is contained in:
Andreas Hansson 2013-02-19 05:56:06 -05:00
parent 86a4d09269
commit 5c7ebee434
5 changed files with 23 additions and 27 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012 ARM Limited * Copyright (c) 2012-2013 ARM Limited
* All rights reserved * All rights reserved
* *
* The license below extends only to copyright in the software and shall * The license below extends only to copyright in the software and shall
@ -410,9 +410,8 @@ X86ISA::Interrupts::readReg(ApicRegIndex reg)
case APIC_CURRENT_COUNT: case APIC_CURRENT_COUNT:
{ {
if (apicTimerEvent.scheduled()) { if (apicTimerEvent.scheduled()) {
assert(clock);
// Compute how many m5 ticks happen per count. // Compute how many m5 ticks happen per count.
uint64_t ticksPerCount = clock * uint64_t ticksPerCount = clockPeriod() *
divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]); divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
// Compute how many m5 ticks are left. // Compute how many m5 ticks are left.
uint64_t val = apicTimerEvent.when() - curTick(); uint64_t val = apicTimerEvent.when() - curTick();
@ -587,19 +586,20 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
break; break;
case APIC_INITIAL_COUNT: case APIC_INITIAL_COUNT:
{ {
assert(clock);
newVal = bits(val, 31, 0); newVal = bits(val, 31, 0);
// Compute how many timer ticks we're being programmed for. // Compute how many timer ticks we're being programmed for.
uint64_t newCount = newVal * uint64_t newCount = newVal *
(divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
// Schedule on the edge of the next tick plus the new count. // Schedule on the edge of the next tick plus the new count.
Tick offset = curTick() % clock; Tick offset = curTick() % clockPeriod();
if (offset) { if (offset) {
reschedule(apicTimerEvent, reschedule(apicTimerEvent,
curTick() + (newCount + 1) * clock - offset, true); curTick() + (newCount + 1) *
clockPeriod() - offset, true);
} else { } else {
reschedule(apicTimerEvent, reschedule(apicTimerEvent,
curTick() + newCount * clock, true); curTick() + newCount *
clockPeriod(), true);
} }
} }
break; break;
@ -629,8 +629,6 @@ X86ISA::Interrupts::Interrupts(Params * p) :
pendingIPIs(0), cpu(NULL), pendingIPIs(0), cpu(NULL),
intSlavePort(name() + ".int_slave", this, this, latency) intSlavePort(name() + ".int_slave", this, this, latency)
{ {
// Override the default clock
clock = 0;
pioSize = PageBytes; pioSize = PageBytes;
memset(regs, 0, sizeof(regs)); memset(regs, 0, sizeof(regs));
//Set the local apic DFR to the flat model. //Set the local apic DFR to the flat model.
@ -735,7 +733,6 @@ void
X86ISA::Interrupts::serialize(std::ostream &os) X86ISA::Interrupts::serialize(std::ostream &os)
{ {
SERIALIZE_ARRAY(regs, NUM_APIC_REGS); SERIALIZE_ARRAY(regs, NUM_APIC_REGS);
SERIALIZE_SCALAR(clock);
SERIALIZE_SCALAR(pendingSmi); SERIALIZE_SCALAR(pendingSmi);
SERIALIZE_SCALAR(smiVector); SERIALIZE_SCALAR(smiVector);
SERIALIZE_SCALAR(pendingNmi); SERIALIZE_SCALAR(pendingNmi);
@ -761,7 +758,6 @@ void
X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string &section) X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string &section)
{ {
UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS); UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS);
UNSERIALIZE_SCALAR(clock);
UNSERIALIZE_SCALAR(pendingSmi); UNSERIALIZE_SCALAR(pendingSmi);
UNSERIALIZE_SCALAR(smiVector); UNSERIALIZE_SCALAR(smiVector);
UNSERIALIZE_SCALAR(pendingNmi); UNSERIALIZE_SCALAR(pendingNmi);

View file

@ -201,12 +201,6 @@ class Interrupts : public BasicPioDevice, IntDev
void setCPU(BaseCPU * newCPU); void setCPU(BaseCPU * newCPU);
void
setClock(Tick newClock)
{
clock = newClock;
}
const Params * const Params *
params() const params() const
{ {

View file

@ -174,10 +174,6 @@ void initCPU(ThreadContext *tc, int cpuId)
interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14); interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14);
// @todo: Control the relative frequency, in this case 16:1, of
// the clocks in the Python code
interrupts->setClock(tc->getCpuPtr()->clockPeriod() * 16);
// TODO Set the SMRAM base address (SMBASE) to 0x00030000 // TODO Set the SMRAM base address (SMBASE) to 0x00030000
tc->setMiscReg(MISCREG_VM_CR, 0); tc->setMiscReg(MISCREG_VM_CR, 0);

View file

@ -221,8 +221,9 @@ class BaseCPU(MemObject):
elif buildEnv['TARGET_ISA'] == 'alpha': elif buildEnv['TARGET_ISA'] == 'alpha':
self.interrupts = AlphaInterrupts() self.interrupts = AlphaInterrupts()
elif buildEnv['TARGET_ISA'] == 'x86': elif buildEnv['TARGET_ISA'] == 'x86':
_localApic = X86LocalApic(pio_addr=0x2000000000000000) self.interrupts = X86LocalApic(clock = Parent.clock * 16,
self.interrupts = _localApic pio_addr=0x2000000000000000)
_localApic = self.interrupts
elif buildEnv['TARGET_ISA'] == 'mips': elif buildEnv['TARGET_ISA'] == 'mips':
self.interrupts = MipsInterrupts() self.interrupts = MipsInterrupts()
elif buildEnv['TARGET_ISA'] == 'arm': elif buildEnv['TARGET_ISA'] == 'arm':

View file

@ -1,4 +1,4 @@
# Copyright (c) 2012 ARM Limited # Copyright (c) 2012-2013 ARM Limited
# All rights reserved. # All rights reserved.
# #
# The license below extends only to copyright in the software and shall # The license below extends only to copyright in the software and shall
@ -1207,9 +1207,10 @@ class Frequency(TickParamValue):
def ini_str(self): def ini_str(self):
return '%d' % self.getValue() return '%d' % self.getValue()
# A generic frequency and/or Latency value. Value is stored as a latency, # A generic frequency and/or Latency value. Value is stored as a
# but to avoid ambiguity this object does not support numeric ops (* or /). # latency, and any manipulation using a multiplier thus scales the
# An explicit conversion to a Latency or Frequency must be made first. # clock period, i.e. a 2x multiplier doubles the clock period and thus
# halves the clock frequency.
class Clock(ParamValue): class Clock(ParamValue):
cxx_type = 'Tick' cxx_type = 'Tick'
@ -1243,6 +1244,14 @@ class Clock(ParamValue):
return Latency(self) return Latency(self)
raise AttributeError, "Frequency object has no attribute '%s'" % attr raise AttributeError, "Frequency object has no attribute '%s'" % attr
def __mul__(self, other):
# Always treat the clock as a period when scaling
newobj = self.__class__(self)
newobj.value *= other
return newobj
__rmul__ = __mul__
def getValue(self): def getValue(self):
return self.period.getValue() return self.period.getValue()