drain.hh revision 10910
19342SAndreas.Sandberg@arm.com/*
210910Sandreas.sandberg@arm.com * Copyright (c) 2012, 2015 ARM Limited
39342SAndreas.Sandberg@arm.com * All rights reserved
49342SAndreas.Sandberg@arm.com *
59342SAndreas.Sandberg@arm.com * The license below extends only to copyright in the software and shall
69342SAndreas.Sandberg@arm.com * not be construed as granting a license to any other intellectual
79342SAndreas.Sandberg@arm.com * property including but not limited to intellectual property relating
89342SAndreas.Sandberg@arm.com * to a hardware implementation of the functionality of the software
99342SAndreas.Sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
109342SAndreas.Sandberg@arm.com * terms below provided that you ensure that this notice is replicated
119342SAndreas.Sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
129342SAndreas.Sandberg@arm.com * modified or unmodified, in source code or in binary form.
139342SAndreas.Sandberg@arm.com *
149342SAndreas.Sandberg@arm.com * Redistribution and use in source and binary forms, with or without
159342SAndreas.Sandberg@arm.com * modification, are permitted provided that the following conditions are
169342SAndreas.Sandberg@arm.com * met: redistributions of source code must retain the above copyright
179342SAndreas.Sandberg@arm.com * notice, this list of conditions and the following disclaimer;
189342SAndreas.Sandberg@arm.com * redistributions in binary form must reproduce the above copyright
199342SAndreas.Sandberg@arm.com * notice, this list of conditions and the following disclaimer in the
209342SAndreas.Sandberg@arm.com * documentation and/or other materials provided with the distribution;
219342SAndreas.Sandberg@arm.com * neither the name of the copyright holders nor the names of its
229342SAndreas.Sandberg@arm.com * contributors may be used to endorse or promote products derived from
239342SAndreas.Sandberg@arm.com * this software without specific prior written permission.
249342SAndreas.Sandberg@arm.com *
259342SAndreas.Sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269342SAndreas.Sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
279342SAndreas.Sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
289342SAndreas.Sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
299342SAndreas.Sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
309342SAndreas.Sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319342SAndreas.Sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329342SAndreas.Sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
339342SAndreas.Sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349342SAndreas.Sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359342SAndreas.Sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
369342SAndreas.Sandberg@arm.com *
379342SAndreas.Sandberg@arm.com * Authors: Andreas Sandberg
389342SAndreas.Sandberg@arm.com */
399342SAndreas.Sandberg@arm.com
409342SAndreas.Sandberg@arm.com#ifndef __SIM_DRAIN_HH__
419342SAndreas.Sandberg@arm.com#define __SIM_DRAIN_HH__
429342SAndreas.Sandberg@arm.com
439342SAndreas.Sandberg@arm.com#include <cassert>
449342SAndreas.Sandberg@arm.com#include <vector>
459342SAndreas.Sandberg@arm.com
469342SAndreas.Sandberg@arm.com#include "base/flags.hh"
479342SAndreas.Sandberg@arm.com
4810910Sandreas.sandberg@arm.comclass Drainable;
4910910Sandreas.sandberg@arm.com
5010910Sandreas.sandberg@arm.com#ifndef SWIG // SWIG doesn't support strongly typed enums
5110910Sandreas.sandberg@arm.com/**
5210910Sandreas.sandberg@arm.com * Object drain/handover states
5310910Sandreas.sandberg@arm.com *
5410910Sandreas.sandberg@arm.com * An object starts out in the Running state. When the simulator
5510910Sandreas.sandberg@arm.com * prepares to take a snapshot or prepares a CPU for handover, it
5610910Sandreas.sandberg@arm.com * calls the drain() method to transfer the object into the Draining
5710910Sandreas.sandberg@arm.com * or Drained state. If any object enters the Draining state
5810910Sandreas.sandberg@arm.com * (Drainable::drain() returning >0), simulation continues until it
5910910Sandreas.sandberg@arm.com * all objects have entered the Drained state.
6010910Sandreas.sandberg@arm.com *
6110910Sandreas.sandberg@arm.com * Before resuming simulation, the simulator calls resume() to
6210910Sandreas.sandberg@arm.com * transfer the object to the Running state.
6310910Sandreas.sandberg@arm.com *
6410910Sandreas.sandberg@arm.com * \note Even though the state of an object (visible to the rest of
6510910Sandreas.sandberg@arm.com * the world through Drainable::getState()) could be used to determine
6610910Sandreas.sandberg@arm.com * if all objects have entered the Drained state, the protocol is
6710910Sandreas.sandberg@arm.com * actually a bit more elaborate. See Drainable::drain() for details.
6810910Sandreas.sandberg@arm.com */
6910910Sandreas.sandberg@arm.comenum class DrainState {
7010910Sandreas.sandberg@arm.com    Running,  /** Running normally */
7110910Sandreas.sandberg@arm.com    Draining, /** Draining buffers pending serialization/handover */
7210910Sandreas.sandberg@arm.com    Drained   /** Buffers drained, ready for serialization/handover */
7310910Sandreas.sandberg@arm.com};
7410910Sandreas.sandberg@arm.com#endif
759342SAndreas.Sandberg@arm.com
769342SAndreas.Sandberg@arm.com/**
779342SAndreas.Sandberg@arm.com * This class coordinates draining of a System.
789342SAndreas.Sandberg@arm.com *
799342SAndreas.Sandberg@arm.com * When draining a System, we need to make sure that all SimObjects in
809342SAndreas.Sandberg@arm.com * that system have drained their state before declaring the operation
819342SAndreas.Sandberg@arm.com * to be successful. This class keeps track of how many objects are
829342SAndreas.Sandberg@arm.com * still in the process of draining their state. Once it determines
839342SAndreas.Sandberg@arm.com * that all objects have drained their state, it exits the simulation
849342SAndreas.Sandberg@arm.com * loop.
859342SAndreas.Sandberg@arm.com *
869342SAndreas.Sandberg@arm.com * @note A System might not be completely drained even though the
879342SAndreas.Sandberg@arm.com * DrainManager has caused the simulation loop to exit. Draining needs
889342SAndreas.Sandberg@arm.com * to be restarted until all Drainable objects declare that they don't
899342SAndreas.Sandberg@arm.com * need further simulation to be completely drained. See Drainable for
909342SAndreas.Sandberg@arm.com * more information.
919342SAndreas.Sandberg@arm.com */
929342SAndreas.Sandberg@arm.comclass DrainManager
939342SAndreas.Sandberg@arm.com{
949342SAndreas.Sandberg@arm.com  public:
959342SAndreas.Sandberg@arm.com    DrainManager();
969342SAndreas.Sandberg@arm.com    virtual ~DrainManager();
979342SAndreas.Sandberg@arm.com
989342SAndreas.Sandberg@arm.com    /**
999342SAndreas.Sandberg@arm.com     * Get the number of objects registered with this DrainManager
1009342SAndreas.Sandberg@arm.com     * that are currently draining their state.
1019342SAndreas.Sandberg@arm.com     *
1029342SAndreas.Sandberg@arm.com     * @return Number of objects currently draining.
1039342SAndreas.Sandberg@arm.com     */
1049342SAndreas.Sandberg@arm.com    unsigned int getCount() const { return _count; }
1059342SAndreas.Sandberg@arm.com
1069342SAndreas.Sandberg@arm.com    void setCount(int count) { _count = count; }
1079342SAndreas.Sandberg@arm.com
1089342SAndreas.Sandberg@arm.com    /**
1099342SAndreas.Sandberg@arm.com     * Notify the DrainManager that a Drainable object has finished
1109342SAndreas.Sandberg@arm.com     * draining.
1119342SAndreas.Sandberg@arm.com     */
1129342SAndreas.Sandberg@arm.com    void signalDrainDone() {
1139342SAndreas.Sandberg@arm.com        assert(_count > 0);
1149342SAndreas.Sandberg@arm.com        if (--_count == 0)
1159342SAndreas.Sandberg@arm.com            drainCycleDone();
1169342SAndreas.Sandberg@arm.com    }
1179342SAndreas.Sandberg@arm.com
1189342SAndreas.Sandberg@arm.com  protected:
1199342SAndreas.Sandberg@arm.com    /**
1209342SAndreas.Sandberg@arm.com     * Callback when all registered Drainable objects have completed a
1219342SAndreas.Sandberg@arm.com     * drain cycle.
1229342SAndreas.Sandberg@arm.com     */
1239342SAndreas.Sandberg@arm.com    virtual void drainCycleDone();
1249342SAndreas.Sandberg@arm.com
1259342SAndreas.Sandberg@arm.com    /** Number of objects still draining. */
1269342SAndreas.Sandberg@arm.com    unsigned int _count;
1279342SAndreas.Sandberg@arm.com};
1289342SAndreas.Sandberg@arm.com
1299342SAndreas.Sandberg@arm.com/**
1309342SAndreas.Sandberg@arm.com * Interface for objects that might require draining before
1319342SAndreas.Sandberg@arm.com * checkpointing.
1329342SAndreas.Sandberg@arm.com *
1339342SAndreas.Sandberg@arm.com * An object's internal state needs to be drained when creating a
1349342SAndreas.Sandberg@arm.com * checkpoint, switching between CPU models, or switching between
1359342SAndreas.Sandberg@arm.com * timing models. Once the internal state has been drained from
1369342SAndreas.Sandberg@arm.com * <i>all</i> objects in the system, the objects are serialized to
1379342SAndreas.Sandberg@arm.com * disc or the configuration change takes place. The process works as
1389342SAndreas.Sandberg@arm.com * follows (see simulate.py for details):
1399342SAndreas.Sandberg@arm.com *
1409342SAndreas.Sandberg@arm.com * <ol>
1419342SAndreas.Sandberg@arm.com * <li>An instance of a DrainManager is created to keep track of how
1429342SAndreas.Sandberg@arm.com *     many objects need to be drained. The object maintains an
1439342SAndreas.Sandberg@arm.com *     internal counter that is decreased every time its
1449342SAndreas.Sandberg@arm.com *     CountedDrainEvent::signalDrainDone() method is called. When the
1459342SAndreas.Sandberg@arm.com *     counter reaches zero, the simulation is stopped.
1469342SAndreas.Sandberg@arm.com *
1479342SAndreas.Sandberg@arm.com * <li>Call Drainable::drain() for every object in the
1489342SAndreas.Sandberg@arm.com *     system. Draining has completed if all of them return
1499342SAndreas.Sandberg@arm.com *     zero. Otherwise, the sum of the return values is loaded into
1509342SAndreas.Sandberg@arm.com *     the counter of the DrainManager. A pointer to the drain
1519342SAndreas.Sandberg@arm.com *     manager is passed as an argument to the drain() method.
1529342SAndreas.Sandberg@arm.com *
1539342SAndreas.Sandberg@arm.com * <li>Continue simulation. When an object has finished draining its
1549342SAndreas.Sandberg@arm.com *     internal state, it calls CountedDrainEvent::signalDrainDone()
1559342SAndreas.Sandberg@arm.com *     on the manager. When the counter in the manager reaches zero,
1569342SAndreas.Sandberg@arm.com *     the simulation stops.
1579342SAndreas.Sandberg@arm.com *
1589342SAndreas.Sandberg@arm.com * <li>Check if any object still needs draining, if so repeat the
1599342SAndreas.Sandberg@arm.com *     process above.
1609342SAndreas.Sandberg@arm.com *
1619342SAndreas.Sandberg@arm.com * <li>Serialize objects, switch CPU model, or change timing model.
1629342SAndreas.Sandberg@arm.com *
1639342SAndreas.Sandberg@arm.com * <li>Call Drainable::drainResume() and continue the simulation.
1649342SAndreas.Sandberg@arm.com * </ol>
1659342SAndreas.Sandberg@arm.com *
1669342SAndreas.Sandberg@arm.com */
1679342SAndreas.Sandberg@arm.comclass Drainable
1689342SAndreas.Sandberg@arm.com{
1699342SAndreas.Sandberg@arm.com  public:
1709342SAndreas.Sandberg@arm.com    Drainable();
1719342SAndreas.Sandberg@arm.com    virtual ~Drainable();
1729342SAndreas.Sandberg@arm.com
1739342SAndreas.Sandberg@arm.com    /**
1749342SAndreas.Sandberg@arm.com     * Determine if an object needs draining and register a
1759342SAndreas.Sandberg@arm.com     * DrainManager.
1769342SAndreas.Sandberg@arm.com     *
1779342SAndreas.Sandberg@arm.com     * When draining the state of an object, the simulator calls drain
1789342SAndreas.Sandberg@arm.com     * with a pointer to a drain manager. If the object does not need
1799342SAndreas.Sandberg@arm.com     * further simulation to drain internal buffers, it switched to
1809342SAndreas.Sandberg@arm.com     * the Drained state and returns 0, otherwise it switches to the
1819342SAndreas.Sandberg@arm.com     * Draining state and returns the number of times that it will
1829342SAndreas.Sandberg@arm.com     * call Event::process() on the drain event. Most objects are
1839342SAndreas.Sandberg@arm.com     * expected to return either 0 or 1.
1849342SAndreas.Sandberg@arm.com     *
1859342SAndreas.Sandberg@arm.com     * @note An object that has entered the Drained state can be
1869342SAndreas.Sandberg@arm.com     * disturbed by other objects in the system and consequently be
1879342SAndreas.Sandberg@arm.com     * forced to enter the Draining state again. The simulator
1889342SAndreas.Sandberg@arm.com     * therefore repeats the draining process until all objects return
1899342SAndreas.Sandberg@arm.com     * 0 on the first call to drain().
1909342SAndreas.Sandberg@arm.com     *
1919342SAndreas.Sandberg@arm.com     * @param drainManager DrainManager to use to inform the simulator
1929342SAndreas.Sandberg@arm.com     * when draining has completed.
1939342SAndreas.Sandberg@arm.com     *
1949342SAndreas.Sandberg@arm.com     * @return 0 if the object is ready for serialization now, >0 if
1959342SAndreas.Sandberg@arm.com     * it needs further simulation.
1969342SAndreas.Sandberg@arm.com     */
1979342SAndreas.Sandberg@arm.com    virtual unsigned int drain(DrainManager *drainManager) = 0;
1989342SAndreas.Sandberg@arm.com
1999342SAndreas.Sandberg@arm.com    /**
2009342SAndreas.Sandberg@arm.com     * Resume execution after a successful drain.
2019342SAndreas.Sandberg@arm.com     *
2029342SAndreas.Sandberg@arm.com     * @note This method is normally only called from the simulation
2039342SAndreas.Sandberg@arm.com     * scripts.
2049342SAndreas.Sandberg@arm.com     */
2059342SAndreas.Sandberg@arm.com    virtual void drainResume();
2069342SAndreas.Sandberg@arm.com
2079346SAndreas.Sandberg@arm.com    /**
2089346SAndreas.Sandberg@arm.com     * Write back dirty buffers to memory using functional writes.
2099346SAndreas.Sandberg@arm.com     *
2109346SAndreas.Sandberg@arm.com     * After returning, an object implementing this method should have
2119346SAndreas.Sandberg@arm.com     * written all its dirty data back to memory. This method is
2129346SAndreas.Sandberg@arm.com     * typically used to prepare a system with caches for
2139346SAndreas.Sandberg@arm.com     * checkpointing.
2149346SAndreas.Sandberg@arm.com     */
2159346SAndreas.Sandberg@arm.com    virtual void memWriteback() {};
2169346SAndreas.Sandberg@arm.com
2179346SAndreas.Sandberg@arm.com    /**
2189346SAndreas.Sandberg@arm.com     * Invalidate the contents of memory buffers.
2199346SAndreas.Sandberg@arm.com     *
2209346SAndreas.Sandberg@arm.com     * When the switching to hardware virtualized CPU models, we need
2219346SAndreas.Sandberg@arm.com     * to make sure that we don't have any cached state in the system
2229346SAndreas.Sandberg@arm.com     * that might become stale when we return. This method is used to
2239346SAndreas.Sandberg@arm.com     * flush all such state back to main memory.
2249346SAndreas.Sandberg@arm.com     *
2259346SAndreas.Sandberg@arm.com     * @warn This does <i>not</i> cause any dirty state to be written
2269346SAndreas.Sandberg@arm.com     * back to memory.
2279346SAndreas.Sandberg@arm.com     */
2289346SAndreas.Sandberg@arm.com    virtual void memInvalidate() {};
2299346SAndreas.Sandberg@arm.com
23010910Sandreas.sandberg@arm.com    DrainState getDrainState() const { return _drainState; }
2319342SAndreas.Sandberg@arm.com
2329342SAndreas.Sandberg@arm.com  protected:
23310910Sandreas.sandberg@arm.com    void setDrainState(DrainState new_state) { _drainState = new_state; }
2349342SAndreas.Sandberg@arm.com
2359342SAndreas.Sandberg@arm.com  private:
23610910Sandreas.sandberg@arm.com    DrainState _drainState;
2379342SAndreas.Sandberg@arm.com};
2389342SAndreas.Sandberg@arm.com
2399554Sandreas.hansson@arm.comDrainManager *createDrainManager();
2409554Sandreas.hansson@arm.comvoid cleanupDrainManager(DrainManager *drain_manager);
2419554Sandreas.hansson@arm.com
2429342SAndreas.Sandberg@arm.com#endif
243