From 65f3f097d3c270d2f28fc7d55651afaefb56ceed Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Sat, 23 May 2015 13:46:52 +0100 Subject: dev, arm: Refactor and clean up the generic timer model This changeset cleans up the generic timer a bit and moves most of the register juggling from the ISA code into a separate class in the same source file as the rest of the generic timer. It also removes the assumption that there is always 8 or fewer CPUs in the system. Instead of having a fixed limit, we now instantiate per-core timers as they are requested. This is all in preparation for other patches that add support for virtual timers and a memory mapped interface. --- src/dev/arm/generic_timer.hh | 300 ++++++++++++++++++++++++++----------------- 1 file changed, 181 insertions(+), 119 deletions(-) (limited to 'src/dev/arm/generic_timer.hh') diff --git a/src/dev/arm/generic_timer.hh b/src/dev/arm/generic_timer.hh index bc43f8b3b..8dc921275 100644 --- a/src/dev/arm/generic_timer.hh +++ b/src/dev/arm/generic_timer.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 ARM Limited + * Copyright (c) 2013, 2015 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -35,13 +35,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Giacomo Gabrielli + * Andreas Sandberg */ #ifndef __DEV_ARM_GENERIC_TIMER_HH__ #define __DEV_ARM_GENERIC_TIMER_HH__ +#include "arch/arm/isa_device.hh" #include "base/bitunion.hh" -#include "params/GenericTimer.hh" +#include "dev/arm/base_gic.hh" #include "sim/core.hh" #include "sim/sim_object.hh" @@ -51,149 +53,209 @@ /// ARM, Issue C, Chapter 17). class Checkpoint; -class BaseGic; +class GenericTimerParams; -/// Wrapper around the actual counters and timers of the Generic Timer -/// extension. -class GenericTimer : public SimObject +/// Global system counter. It is shared by the architected timers. +/// @todo: implement memory-mapped controls +class SystemCounter { + protected: + /// Counter frequency (as specified by CNTFRQ). + uint64_t _freq; + /// Cached copy of the counter period (inverse of the frequency). + Tick _period; + /// Tick when the counter was reset. + Tick _resetTick; + + uint32_t _regCntkctl; + public: + SystemCounter(); - /// Global system counter. It is shared by the architected timers. - /// @todo: implement memory-mapped controls - class SystemCounter + /// Returns the current value of the physical counter. + uint64_t value() const { - protected: - /// Counter frequency (as specified by CNTFRQ). - uint64_t _freq; - /// Cached copy of the counter period (inverse of the frequency). - Tick _period; - /// Tick when the counter was reset. - Tick _resetTick; + if (_freq == 0) + return 0; // Counter is still off. + return (curTick() - _resetTick) / _period; + } + + /// Returns the counter frequency. + uint64_t freq() const { return _freq; } + /// Sets the counter frequency. + /// @param freq frequency in Hz. + void setFreq(uint32_t freq); + + /// Returns the counter period. + Tick period() const { return _period; } + void setKernelControl(uint32_t val) { _regCntkctl = val; } + uint32_t getKernelControl() { return _regCntkctl; } + + void serialize(std::ostream &os) const; + void unserialize(Checkpoint *cp, const std::string §ion); + + private: + // Disable copying + SystemCounter(const SystemCounter &c); +}; + +/// Per-CPU architected timer. +class ArchTimer +{ + public: + class Interrupt + { public: - /// Ctor. - SystemCounter() - : _freq(0), _period(0), _resetTick(0) - { - setFreq(0x01800000); - } - - /// Returns the current value of the physical counter. - uint64_t value() const - { - if (_freq == 0) - return 0; // Counter is still off. - return (curTick() - _resetTick) / _period; - } - - /// Returns the counter frequency. - uint64_t freq() const { return _freq; } - /// Sets the counter frequency. - /// @param freq frequency in Hz. - void setFreq(uint32_t freq); - - /// Returns the counter period. - Tick period() const { return _period; } - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + Interrupt(BaseGic &gic, unsigned irq) + : _gic(gic), _ppi(false), _irq(irq), _cpu(0) {} + + Interrupt(BaseGic &gic, unsigned irq, unsigned cpu) + : _gic(gic), _ppi(true), _irq(irq), _cpu(cpu) {} + + void send(); + void clear(); + + private: + BaseGic &_gic; + const bool _ppi; + const unsigned _irq; + const unsigned _cpu; }; - /// Per-CPU architected timer. - class ArchTimer - { - protected: - /// Control register. - BitUnion32(ArchTimerCtrl) - Bitfield<0> enable; - Bitfield<1> imask; - Bitfield<2> istatus; - EndBitUnion(ArchTimerCtrl) - - /// Name of this timer. - std::string _name; - /// Pointer to parent class. - GenericTimer *_parent; - /// Pointer to the global system counter. - SystemCounter *_counter; - /// ID of the CPU this timer is attached to. - int _cpuNum; - /// ID of the interrupt to be triggered. - int _intNum; - /// Cached value of the control register ({CNTP/CNTHP/CNTV}_CTL). - ArchTimerCtrl _control; - /// Programmed limit value for the upcounter ({CNTP/CNTHP/CNTV}_CVAL). - uint64_t _counterLimit; - - /// Called when the upcounter reaches the programmed value. - void counterLimitReached(); - EventWrapper - _counterLimitReachedEvent; - - /// Returns the value of the counter which this timer relies on. - uint64_t counterValue() const { return _counter->value(); } + protected: + /// Control register. + BitUnion32(ArchTimerCtrl) + Bitfield<0> enable; + Bitfield<1> imask; + Bitfield<2> istatus; + EndBitUnion(ArchTimerCtrl) - public: - /// Ctor. - ArchTimer() - : _control(0), _counterLimit(0), _counterLimitReachedEvent(this) - {} + /// Name of this timer. + const std::string _name; - /// Returns the timer name. - std::string name() const { return _name; } + /// Pointer to parent class. + SimObject &_parent; - /// Returns the CompareValue view of the timer. - uint64_t compareValue() const { return _counterLimit; } - /// Sets the CompareValue view of the timer. - void setCompareValue(uint64_t val); + SystemCounter &_systemCounter; - /// Returns the TimerValue view of the timer. - uint32_t timerValue() const { return _counterLimit - counterValue(); } - /// Sets the TimerValue view of the timer. - void setTimerValue(uint32_t val); + Interrupt _interrupt; - /// Sets the control register. - uint32_t control() const { return _control; } - void setControl(uint32_t val); + /// Value of the control register ({CNTP/CNTHP/CNTV}_CTL). + ArchTimerCtrl _control; + /// Programmed limit value for the upcounter ({CNTP/CNTHP/CNTV}_CVAL). + uint64_t _counterLimit; - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); + /** + * Timer settings or the offset has changed, re-evaluate + * trigger condition and raise interrupt if necessary. + */ + void updateCounter(); - friend class GenericTimer; - }; + /// Called when the upcounter reaches the programmed value. + void counterLimitReached(); + EventWrapper + _counterLimitReachedEvent; + + public: + ArchTimer(const std::string &name, + SimObject &parent, + SystemCounter &sysctr, + const Interrupt &interrupt); + + /// Returns the timer name. + std::string name() const { return _name; } + + /// Returns the CompareValue view of the timer. + uint64_t compareValue() const { return _counterLimit; } + /// Sets the CompareValue view of the timer. + void setCompareValue(uint64_t val); + + /// Returns the TimerValue view of the timer. + uint32_t timerValue() const { return _counterLimit - value(); } + /// Sets the TimerValue view of the timer. + void setTimerValue(uint32_t val); + + /// Sets the control register. + uint32_t control() const { return _control; } + void setControl(uint32_t val); + + /// Returns the value of the counter which this timer relies on. + uint64_t value() const; + + void serialize(std::ostream &os) const; + void unserialize(Checkpoint *cp, const std::string §ion); + + private: + // Disable copying + ArchTimer(const ArchTimer &t); +}; + +class GenericTimer : public SimObject +{ + public: + GenericTimer(GenericTimerParams *p); + + void serialize(std::ostream &os) M5_ATTR_OVERRIDE; + void unserialize(Checkpoint *cp, const std::string &sec) M5_ATTR_OVERRIDE; + + public: + void setMiscReg(int misc_reg, unsigned cpu, ArmISA::MiscReg val); + ArmISA::MiscReg readMiscReg(int misc_reg, unsigned cpu); protected: + struct CoreTimers { + CoreTimers(GenericTimer &parent, unsigned cpu, + unsigned _irqPhys) + : irqPhys(*parent.gic, _irqPhys, cpu), + // This should really be phys_timerN, but we are stuck with + // arch_timer for backwards compatibility. + phys(csprintf("%s.arch_timer%d", parent.name(), cpu), + parent, parent.systemCounter, + irqPhys) + {} - static const int CPU_MAX = 8; + ArchTimer::Interrupt irqPhys; + ArchTimer phys; + + private: + // Disable copying + CoreTimers(const CoreTimers &c); + }; + + CoreTimers &getTimers(int cpu_id); + void createTimers(unsigned cpus); - /// Pointer to the GIC, needed to trigger timer interrupts. - BaseGic *_gic; /// System counter. - SystemCounter _systemCounter; - /// Per-CPU architected timers. - // @todo: this would become a 2-dim. array with Security and Virt. - ArchTimer _archTimers[CPU_MAX]; + SystemCounter systemCounter; - public: - typedef GenericTimerParams Params; - const Params * - params() const - { - return dynamic_cast(_params); - } + /// Per-CPU physical architected timers. + std::vector> timers; - /// Ctor. - GenericTimer(Params *p); + protected: // Configuration + /// Pointer to the GIC, needed to trigger timer interrupts. + BaseGic *const gic; - /// Returns a pointer to the system counter. - SystemCounter *getSystemCounter() { return &_systemCounter; } + /// Physical timer interrupt + const unsigned irqPhys; +}; - /// Returns a pointer to the architected timer for cpu_id. - ArchTimer *getArchTimer(int cpu_id) { return &_archTimers[cpu_id]; } +class GenericTimerISA : public ArmISA::BaseISADevice +{ + public: + GenericTimerISA(GenericTimer &_parent, unsigned _cpu) + : parent(_parent), cpu(_cpu) {} + + void setMiscReg(int misc_reg, ArmISA::MiscReg val) M5_ATTR_OVERRIDE { + parent.setMiscReg(misc_reg, cpu, val); + } + ArmISA::MiscReg readMiscReg(int misc_reg) M5_ATTR_OVERRIDE { + return parent.readMiscReg(misc_reg, cpu); + } - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); + protected: + GenericTimer &parent; + unsigned cpu; }; #endif // __DEV_ARM_GENERIC_TIMER_HH__ -- cgit v1.2.3