sim_object.hh revision 9196
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * Copyright (c) 2010 Advanced Micro Devices, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Steve Reinhardt
30 *          Nathan Binkert
31 */
32
33/* @file
34 * User Console Definitions
35 */
36
37#ifndef __SIM_OBJECT_HH__
38#define __SIM_OBJECT_HH__
39
40#include <iostream>
41#include <list>
42#include <map>
43#include <string>
44#include <vector>
45
46#include "enums/MemoryMode.hh"
47#include "params/SimObject.hh"
48#include "sim/eventq.hh"
49#include "sim/serialize.hh"
50
51class BaseCPU;
52class Event;
53
54/**
55 * Abstract superclass for simulation objects.  Represents things that
56 * correspond to physical components and can be specified via the
57 * config file (CPUs, caches, etc.).
58 *
59 * SimObject initialization is controlled by the instantiate method in
60 * src/python/m5/simulate.py. There are slightly different
61 * initialization paths when starting the simulation afresh and when
62 * loading from a checkpoint.  After instantiation and connecting
63 * ports, simulate.py initializes the object using the following call
64 * sequence:
65 *
66 * <ol>
67 * <li>SimObject::init()
68 * <li>SimObject::regStats()
69 * <li><ul>
70 *     <li>SimObject::initState() if starting afresh.
71 *     <li>SimObject::loadState() if restoring from a checkpoint.
72 *     </ul>
73 * <li>SimObject::resetStats()
74 * <li>SimObject::startup()
75 * <li>SimObject::resume() if resuming from a checkpoint.
76 * </ol>
77 *
78 * An object's internal state needs to be drained when creating a
79 * checkpoint, switching between CPU models, or switching between
80 * timing models. Once the internal state has been drained from
81 * <i>all</i> objects in the system, the objects are serialized to
82 * disc or the configuration change takes place. The process works as
83 * follows (see simulate.py for details):
84 *
85 * <ol>
86 * <li>An instance of a CountedDrainEvent is created to keep track of
87 *     how many objects need to be drained. The object maintains an
88 *     internal counter that is decreased every time its
89 *     CountedDrainEvent::process() method is called. When the counter
90 *     reaches zero, the simulation is stopped.
91 *
92 * <li>Call SimObject::drain() for every object in the
93 *     system. Draining has completed if all of them return
94 *     zero. Otherwise, the sum of the return values is loaded into
95 *     the counter of the CountedDrainEvent. A pointer of the drain
96 *     event is passed as an argument to the drain() method.
97 *
98 * <li>Continue simulation. When an object has finished draining its
99 *     internal state, it calls CountedDrainEvent::process() on the
100 *     CountedDrainEvent. When counter in the CountedDrainEvent reaches
101 *     zero, the simulation stops.
102 *
103 * <li>Check if any object still needs draining, if so repeat the
104 *     process above.
105 *
106 * <li>Serialize objects, switch CPU model, or change timing model.
107 *
108 * <li>Call SimObject::resume() and continue the simulation.
109 * </ol>
110 *
111 * @note Whenever a method is called on all objects in the simulator's
112 * object tree (e.g., init(), startup(), or loadState()), a pre-order
113 * depth-first traversal is performed (see descendants() in
114 * SimObject.py). This has the effect of calling the method on the
115 * parent node <i>before</i> its children.
116 */
117class SimObject : public EventManager, public Serializable
118{
119  public:
120    /**
121     * Object drain/handover states
122     *
123     * An object starts out in the Running state. When the simulator
124     * prepares to take a snapshot or prepares a CPU for handover, it
125     * calls the drain() method to transfer the object into the
126     * Draining or Drained state. If any object enters the Draining
127     * state (drain() returning >0), simulation continues until it all
128     * objects have entered the Drained.
129     *
130     * The before resuming simulation, the simulator calls resume() to
131     * transfer the object to the Running state.
132     *
133     * \note Even though the state of an object (visible to the rest
134     * of the world through getState()) could be used to determine if
135     * all objects have entered the Drained state, the protocol is
136     * actually a bit more elaborate. See drain() for details.
137     */
138    enum State {
139        Running,  /** Running normally */
140        Draining, /** Draining buffers pending serialization/handover */
141        Drained   /** Buffers drained, ready for serialization/handover */
142    };
143
144  private:
145    State state;
146
147  protected:
148    void changeState(State new_state) { state = new_state; }
149
150  public:
151    State getState() { return state; }
152
153  private:
154    typedef std::vector<SimObject *> SimObjectList;
155
156    /** List of all instantiated simulation objects. */
157    static SimObjectList simObjectList;
158
159  protected:
160    /** Cached copy of the object parameters. */
161    const SimObjectParams *_params;
162
163  public:
164    typedef SimObjectParams Params;
165    const Params *params() const { return _params; }
166    SimObject(const Params *_params);
167    virtual ~SimObject() {}
168
169  public:
170
171    virtual const std::string name() const { return params()->name; }
172
173    /**
174     * init() is called after all C++ SimObjects have been created and
175     * all ports are connected.  Initializations that are independent
176     * of unserialization but rely on a fully instantiated and
177     * connected SimObject graph should be done here.
178     */
179    virtual void init();
180
181    /**
182     * loadState() is called on each SimObject when restoring from a
183     * checkpoint.  The default implementation simply calls
184     * unserialize() if there is a corresponding section in the
185     * checkpoint.  However, objects can override loadState() to get
186     * other behaviors, e.g., doing other programmed initializations
187     * after unserialize(), or complaining if no checkpoint section is
188     * found.
189     *
190     * @param cp Checkpoint to restore the state from.
191     */
192    virtual void loadState(Checkpoint *cp);
193
194    /**
195     * initState() is called on each SimObject when *not* restoring
196     * from a checkpoint.  This provides a hook for state
197     * initializations that are only required for a "cold start".
198     */
199    virtual void initState();
200
201    /**
202     * Register statistics for this object.
203     */
204    virtual void regStats();
205
206    /**
207     * Reset statistics associated with this object.
208     */
209    virtual void resetStats();
210
211    /**
212     * startup() is the final initialization call before simulation.
213     * All state is initialized (including unserialized state, if any,
214     * such as the curTick() value), so this is the appropriate place to
215     * schedule initial event(s) for objects that need them.
216     */
217    virtual void startup();
218
219    /**
220     * Serialize all SimObjects in the system.
221     */
222    static void serializeAll(std::ostream &os);
223
224    /**
225     * Determine if an object needs draining and register a drain
226     * event.
227     *
228     * When draining the state of an object, the simulator calls drain
229     * with a pointer to a drain event. If the object does not need
230     * further simulation to drain internal buffers, it switched to
231     * the Drained state and returns 0, otherwise it switches to the
232     * Draining state and returns the number of times that it will
233     * call Event::process() on the drain event. Most objects are
234     * expected to return either 0 or 1.
235     *
236     * The default implementation simply switches to the Drained state
237     * and returns 0.
238     *
239     * @note An object that has entered the Drained state can be
240     * disturbed by other objects in the system and consequently be
241     * forced to enter the Draining state again. The simulator
242     * therefore repeats the draining process until all objects return
243     * 0 on the first call to drain().
244     *
245     * @param drain_event Event to use to inform the simulator when
246     * the draining has completed.
247     *
248     * @return 0 if the object is ready for serialization now, >0 if
249     * it needs further simulation.
250     */
251    virtual unsigned int drain(Event *drain_event);
252
253    /**
254     * Switch an object in the Drained stated into the Running state.
255     */
256    virtual void resume();
257
258    /**
259     * Change the memory mode the simulator operates in.
260     *
261     * @note Should only be implemented in the System object.
262     */
263    virtual void setMemoryMode(Enums::MemoryMode new_mode);
264
265    /**
266     * Prepare a CPU model to be switched out, invoked on active CPUs
267     * that are about to be replaced.
268     *
269     * @note This should only be implemented in CPU models.
270     */
271    virtual void switchOut();
272
273    /**
274     * Load the state of a CPU from the previous CPU object, invoked
275     * on all new CPUs that are about to be switched in.
276     *
277     * A CPU model implementing this method is expected to initialize
278     * its state from the old CPU and connect its memory (unless they
279     * are already connected) to the memories connected to the old
280     * CPU.
281     *
282     * @note This should only be implemented in CPU models.
283     *
284     * @param cpu CPU to initialize read state from.
285     */
286    virtual void takeOverFrom(BaseCPU *cpu);
287
288#ifdef DEBUG
289  public:
290    bool doDebugBreak;
291    static void debugObjectBreak(const std::string &objs);
292#endif
293
294    /**
295     * Find the SimObject with the given name and return a pointer to
296     * it.  Primarily used for interactive debugging.  Argument is
297     * char* rather than std::string to make it callable from gdb.
298     */
299    static SimObject *find(const char *name);
300};
301
302#endif // __SIM_OBJECT_HH__
303