sim, arch, base: Refactor the base remote GDB class.
[gem5.git] / src / sim / clocked_object.hh
index 8ab63777224f25ac4dc63f58b3f42c514408951a..b89e1ce13a8eacbccc2a96e7632861389cca92c1 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * 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
@@ -35,6 +36,9 @@
  * 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__