/*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012-2013, 2015-2016 ARM Limited
+ * Copyright (c) 2013 Cornell University
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Andreas Hansson
+ * Christopher Torng
+ * Akash Bagdia
+ * David Guillen Fandos
*/
/**
#ifndef __SIM_CLOCKED_OBJECT_HH__
#define __SIM_CLOCKED_OBJECT_HH__
+#include "base/callback.hh"
#include "base/intmath.hh"
+#include "enums/PwrState.hh"
#include "params/ClockedObject.hh"
+#include "sim/core.hh"
+#include "sim/clock_domain.hh"
#include "sim/sim_object.hh"
/**
- * The ClockedObject class extends the SimObject with a clock and
- * accessor functions to relate ticks to the cycles of the object.
+ * Helper class for objects that need to be clocked. Clocked objects
+ * typically inherit from this class. Objects that need SimObject
+ * functionality as well should inherit from ClockedObject.
*/
-class ClockedObject : public SimObject
+class Clocked
{
private:
+ // the tick value of the next clock edge (>= curTick()) at the
+ // time of the last call to update()
+ mutable Tick tick;
+
+ // The cycle counter value corresponding to the current value of
+ // 'tick'
+ mutable Cycles cycle;
/**
- * Prevent inadvertent use of the copy constructor and assignment
- * operator by making them private.
+ * Align cycle and tick to the next clock edge if not already done. When
+ * complete, tick must be at least curTick().
*/
- ClockedObject(ClockedObject&);
- ClockedObject& operator=(ClockedObject&);
+ void update() const
+ {
+ // both tick and cycle are up-to-date and we are done, note
+ // that the >= is important as it captures cases where tick
+ // has already passed curTick()
+ if (tick >= curTick())
+ return;
- protected:
+ // optimise for the common case and see if the tick should be
+ // advanced by a single clock period
+ tick += clockPeriod();
+ ++cycle;
+
+ // see if we are done at this point
+ if (tick >= curTick())
+ return;
+
+ // if not, we have to recalculate the cycle and tick, we
+ // perform the calculations in terms of relative cycles to
+ // allow changes to the clock period in the future
+ Cycles elapsedCycles(divCeil(curTick() - tick, clockPeriod()));
+ cycle += elapsedCycles;
+ tick += elapsedCycles * clockPeriod();
+ }
+
+ /**
+ * The clock domain this clocked object belongs to
+ */
+ ClockDomain &clockDomain;
- // Clock period in ticks
- Tick clock;
+ protected:
/**
- * Create a clocked object and set the clock based on the
+ * Create a clocked object and set the clock domain based on the
* parameters.
*/
- ClockedObject(const ClockedObjectParams* p) : SimObject(p), clock(p->clock)
- { }
+ Clocked(ClockDomain &clk_domain)
+ : tick(0), cycle(0), clockDomain(clk_domain)
+ {
+ // Register with the clock domain, so that if the clock domain
+ // frequency changes, we can update this object's tick.
+ clockDomain.registerWithClockDomain(this);
+ }
+
+ Clocked(Clocked &) = delete;
+ Clocked &operator=(Clocked &) = delete;
/**
* Virtual destructor due to inheritance.
*/
- virtual ~ClockedObject() { }
+ virtual ~Clocked() { }
+
+ /**
+ * Reset the object's clock using the current global tick value. Likely
+ * to be used only when the global clock is reset. Currently, this done
+ * only when Ruby is done warming up the memory system.
+ */
+ void resetClock() const
+ {
+ Cycles elapsedCycles(divCeil(curTick(), clockPeriod()));
+ cycle = elapsedCycles;
+ tick = elapsedCycles * clockPeriod();
+ }
public:
/**
- * Based on the clock of the object, determine the tick when the
- * next cycle begins, in other words, round the curTick() to the
- * next tick that is a multiple of the clock.
+ * Update the tick to the current tick.
*
- * @return The tick when the next cycle starts
*/
- Tick nextCycle() const
- { return divCeil(curTick(), clock) * clock; }
+ inline void updateClockPeriod() const
+ {
+ update();
+ }
/**
- * Determine the next cycle starting from a given tick instead of
- * curTick().
+ * Determine the tick when a cycle begins, by default the current one, but
+ * the argument also enables the caller to determine a future cycle. When
+ * curTick() is on a clock edge, the number of cycles in the parameter is
+ * added to curTick() to be returned. When curTick() is not aligned to a
+ * clock edge, the number of cycles in the parameter is added to the next
+ * clock edge.
*
- * @param begin_tick The tick to round to a clock edge
+ * @param cycles The number of cycles into the future
*
- * @return The tick when the cycle after or on begin_tick starts
+ * @return The start tick when the requested clock edge occurs. Precisely,
+ * this tick can be
+ * curTick() + [0, clockPeriod()) + clockPeriod() * cycles
*/
- Tick nextCycle(Tick begin_tick) const
- { return divCeil(begin_tick, clock) * clock; }
+ inline Tick clockEdge(Cycles cycles = Cycles(0)) const
+ {
+ // align tick to the next clock edge
+ update();
- inline Tick frequency() const { return SimClock::Frequency / clock; }
+ // figure out when this future cycle is
+ return tick + clockPeriod() * cycles;
+ }
- inline Tick ticks(int numCycles) const { return clock * numCycles; }
+ /**
+ * Determine the current cycle, corresponding to a tick aligned to
+ * a clock edge.
+ *
+ * @return When curTick() is on a clock edge, return the Cycle corresponding
+ * to that clock edge. When curTick() is not on a clock edge, return the
+ * Cycle corresponding to the next clock edge.
+ */
+ inline Cycles curCycle() const
+ {
+ // align cycle to the next clock edge.
+ update();
- inline Tick curCycle() const { return curTick() / clock; }
+ return cycle;
+ }
- inline Tick tickToCycles(Tick val) const { return val / clock; }
+ /**
+ * Based on the clock of the object, determine the start tick of the first
+ * cycle that is at least one cycle in the future. When curTick() is at the
+ * current cycle edge, this returns the next clock edge. When calling this
+ * during the middle of a cycle, this returns 2 clock edges in the future.
+ *
+ * @return The start tick of the first cycle that is at least one cycle in
+ * the future. Precisely, the returned tick can be in the range
+ * curTick() + [clockPeriod(), 2 * clockPeriod())
+ */
+ Tick nextCycle() const
+ { return clockEdge(Cycles(1)); }
+
+ inline uint64_t frequency() const
+ {
+ return SimClock::Frequency / clockPeriod();
+ }
+
+ inline Tick clockPeriod() const
+ {
+ return clockDomain.clockPeriod();
+ }
+ inline double voltage() const
+ {
+ return clockDomain.voltage();
+ }
+
+ inline Cycles ticksToCycles(Tick t) const
+ { return Cycles(divCeil(t, clockPeriod())); }
+
+ inline Tick cyclesToTicks(Cycles c) const
+ { return clockPeriod() * c; }
+};
+
+/**
+ * The ClockedObject class extends the SimObject with a clock and
+ * accessor functions to relate ticks to the cycles of the object.
+ */
+class ClockedObject
+ : public SimObject, public Clocked
+{
+ public:
+ ClockedObject(const ClockedObjectParams *p);
+
+ /** Parameters of ClockedObject */
+ typedef ClockedObjectParams Params;
+ const Params* params() const
+ { return reinterpret_cast<const Params*>(_params); }
+
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
+
+ inline Enums::PwrState pwrState() const
+ { return _currPwrState; }
+
+ inline std::string pwrStateName() const
+ { return Enums::PwrStateStrings[_currPwrState]; }
+
+ /** Returns the percentage residency for each power state */
+ std::vector<double> pwrStateWeights() const;
+
+ /**
+ * Record stats values like state residency by computing the time
+ * difference from previous update. Also, updates the previous evaluation
+ * tick once all stats are recorded.
+ * Usually called on power state change and stats dump callback.
+ */
+ void computeStats();
+
+ void pwrState(Enums::PwrState);
+ void regStats() override;
+
+ protected:
+
+ /** To keep track of the current power state */
+ Enums::PwrState _currPwrState;
+
+ Tick prvEvalTick;
+
+ Stats::Scalar numPwrStateTransitions;
+ Stats::Distribution pwrStateClkGateDist;
+ Stats::Vector pwrStateResidencyTicks;
+
+};
+
+class ClockedObjectDumpCallback : public Callback
+{
+ ClockedObject *co;
+ public:
+ ClockedObjectDumpCallback(ClockedObject *co_t) : co(co_t) {}
+ virtual void process() { co->computeStats(); };
};
#endif //__SIM_CLOCKED_OBJECT_HH__