summaryrefslogtreecommitdiff
path: root/src/sim
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim')
-rw-r--r--src/sim/async.hh52
-rw-r--r--src/sim/builder.cc179
-rw-r--r--src/sim/builder.hh223
-rw-r--r--src/sim/byteswap.hh176
-rw-r--r--src/sim/debug.cc139
-rw-r--r--src/sim/debug.hh36
-rw-r--r--src/sim/eventq.cc269
-rw-r--r--src/sim/eventq.hh416
-rw-r--r--src/sim/faults.cc55
-rw-r--r--src/sim/faults.hh79
-rw-r--r--src/sim/host.hh71
-rw-r--r--src/sim/main.cc454
-rw-r--r--src/sim/param.cc779
-rw-r--r--src/sim/param.hh782
-rw-r--r--src/sim/process.cc539
-rw-r--r--src/sim/process.hh228
-rw-r--r--src/sim/pseudo_inst.cc347
-rw-r--r--src/sim/pseudo_inst.hh65
-rw-r--r--src/sim/root.cc160
-rw-r--r--src/sim/serialize.cc442
-rw-r--r--src/sim/serialize.hh246
-rw-r--r--src/sim/sim_events.cc169
-rw-r--r--src/sim/sim_events.hh143
-rw-r--r--src/sim/sim_exit.hh58
-rw-r--r--src/sim/sim_object.cc303
-rw-r--r--src/sim/sim_object.hh138
-rw-r--r--src/sim/startup.cc66
-rw-r--r--src/sim/startup.hh43
-rw-r--r--src/sim/stat_control.cc233
-rw-r--r--src/sim/stat_control.hh56
-rw-r--r--src/sim/stats.hh39
-rw-r--r--src/sim/syscall_emul.cc501
-rw-r--r--src/sim/syscall_emul.hh943
-rw-r--r--src/sim/system.cc298
-rw-r--r--src/sim/system.hh248
-rw-r--r--src/sim/vptr.hh124
36 files changed, 9099 insertions, 0 deletions
diff --git a/src/sim/async.hh b/src/sim/async.hh
new file mode 100644
index 000000000..50ae73040
--- /dev/null
+++ b/src/sim/async.hh
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
+ */
+
+#ifndef __ASYNC_HH__
+#define __ASYNC_HH__
+
+///
+/// @file sim/async.hh
+/// This file defines flags used to handle asynchronous simulator events.
+///
+
+/// @name Asynchronous event flags.
+/// To avoid races, signal handlers simply set these flags, which are
+/// then checked in the main event loop. Defined in main.cc.
+/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm.
+//@{
+extern volatile bool async_event; ///< Some asynchronous event has happened.
+extern volatile bool async_dump; ///< Async request to dump stats.
+extern volatile bool async_exit; ///< Async request to exit simulator.
+extern volatile bool async_io; ///< Async I/O request (SIGIO).
+extern volatile bool async_alarm; ///< Async alarm event (SIGALRM).
+//@}
+
+#endif // __ASYNC_HH__
diff --git a/src/sim/builder.cc b/src/sim/builder.cc
new file mode 100644
index 000000000..9074cc899
--- /dev/null
+++ b/src/sim/builder.cc
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#include <assert.h>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+SimObjectBuilder::SimObjectBuilder(const std::string &_iniSection)
+ : ParamContext(_iniSection, NoAutoInit)
+{
+}
+
+SimObjectBuilder::~SimObjectBuilder()
+{
+}
+
+///////////////////////////////////////////
+//
+// SimObjectBuilder member definitions
+//
+///////////////////////////////////////////
+
+// override ParamContext::parseParams() to check params based on
+// instance name first. If not found, then check based on iniSection
+// (as in default ParamContext implementation).
+void
+SimObjectBuilder::parseParams(IniFile &iniFile)
+{
+ iniFilePtr = &iniFile; // set object member
+
+ ParamList::iterator i;
+
+ for (i = paramList->begin(); i != paramList->end(); ++i) {
+ string string_value;
+ if (iniFile.find(iniSection, (*i)->name, string_value))
+ (*i)->parse(string_value);
+ }
+}
+
+
+void
+SimObjectBuilder::printErrorProlog(ostream &os)
+{
+ ccprintf(os, "Error creating object '%s':\n", iniSection);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObjectClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SimObjectBuilder creation functions. Need to
+// make this a pointer so we can force initialization on the first
+// reference; otherwise, some SimObjectClass constructors may be invoked
+// before the classMap constructor.
+map<string,SimObjectClass::CreateFunc> *SimObjectClass::classMap = NULL;
+
+// SimObjectClass constructor: add mapping to classMap
+SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SimObjectClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ panic("Error: simulation object class '%s' redefined\n", className);
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+SimObject *
+SimObjectClass::createObject(IniFile &configDB, const std::string &iniSection)
+{
+ string type;
+ if (!configDB.find(iniSection, "type", type)) {
+ // no C++ type associated with this object
+ return NULL;
+ }
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(type) == classMap->end())
+ panic("Simulator object type '%s' not found.\n", type);
+
+
+ CreateFunc createFunc = (*classMap)[type];
+
+ // call createFunc with config hierarchy node to get object
+ // builder instance (context with parameters for object creation)
+ SimObjectBuilder *objectBuilder = (*createFunc)(iniSection);
+
+ assert(objectBuilder != NULL);
+
+ // parse all parameters in context to generate parameter values
+ objectBuilder->parseParams(configDB);
+
+ // now create the actual simulation object
+ SimObject *object = objectBuilder->create();
+
+ assert(object != NULL);
+
+ // echo object parameters to stats file (for documenting the
+ // config used to generate the associated stats)
+ ccprintf(*configStream, "[%s]\n", object->name());
+ ccprintf(*configStream, "type=%s\n", type);
+ objectBuilder->showParams(*configStream);
+ ccprintf(*configStream, "\n");
+
+ // done with the SimObjectBuilder now
+ delete objectBuilder;
+
+ return object;
+}
+
+
+//
+// static method:
+//
+void
+SimObjectClass::describeAllClasses(ostream &os)
+{
+ map<string,CreateFunc>::iterator iter;
+
+ for (iter = classMap->begin(); iter != classMap->end(); ++iter) {
+ const string &className = iter->first;
+ CreateFunc createFunc = iter->second;
+
+ os << "[" << className << "]\n";
+
+ // create dummy object builder just to instantiate parameters
+ SimObjectBuilder *objectBuilder = (*createFunc)("");
+
+ // now get the object builder to describe ite params
+ objectBuilder->describeParams(os);
+
+ os << endl;
+
+ // done with the object builder now
+ delete objectBuilder;
+ }
+}
diff --git a/src/sim/builder.hh b/src/sim/builder.hh
new file mode 100644
index 000000000..aa0e3d17c
--- /dev/null
+++ b/src/sim/builder.hh
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __BUILDER_HH__
+#define __BUILDER_HH__
+
+#include <iosfwd>
+#include <list>
+#include <map>
+#include <vector>
+
+#include "sim/param.hh"
+
+class SimObject;
+
+//
+// A SimObjectBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a SimObject. This
+// evaluation context corresponds to a section in the .ini file (as
+// with the base ParamContext) plus an optional node in the
+// configuration hierarchy (the configNode member) for resolving
+// SimObject references. SimObjectBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// SimObject (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SimObjectClass::createObject().
+//
+class SimObjectBuilder : public ParamContext
+{
+ public:
+ SimObjectBuilder(const std::string &_iniSection);
+
+ virtual ~SimObjectBuilder();
+
+ // call parse() on all params in this context to convert string
+ // representations to parameter values
+ virtual void parseParams(IniFile &iniFile);
+
+ // parameter error prolog (override of ParamContext)
+ virtual void printErrorProlog(std::ostream &);
+
+ // generate the name for this SimObject instance (derived from the
+ // configuration hierarchy node label and position)
+ virtual const std::string &getInstanceName() { return iniSection; }
+
+ // Create the actual SimObject corresponding to the parameter
+ // values in this context. This function is overridden in derived
+ // classes to call a specific constructor for a particular
+ // subclass of SimObject.
+ virtual SimObject *create() = 0;
+};
+
+
+//
+// Handy macros for initializing parameter members of classes derived
+// from SimObjectBuilder. Assumes that the name of the parameter
+// member object is the same as the textual parameter name seen by the
+// user. (Note that '#p' is expanded by the preprocessor to '"p"'.)
+//
+#define INIT_PARAM(p, desc) p(this, #p, desc)
+#define INIT_PARAM_DFLT(p, desc, dflt) p(this, #p, desc, dflt)
+
+//
+// Initialize an enumeration variable... assumes that 'map' is the
+// name of an array of mappings (char * for SimpleEnumParam, or
+// EnumParamMap for MappedEnumParam).
+//
+#define INIT_ENUM_PARAM(p, desc, map) \
+ p(this, #p, desc, map, sizeof(map)/sizeof(map[0]))
+#define INIT_ENUM_PARAM_DFLT(p, desc, map, dflt) \
+ p(this, #p, desc, map, sizeof(map)/sizeof(map[0]), dflt)
+
+//
+// An instance of SimObjectClass corresponds to a class derived from
+// SimObject. The SimObjectClass instance serves to bind the string
+// name (found in the config file) to a function that creates an
+// instance of the appropriate derived class.
+//
+// This would be much cleaner in Smalltalk or Objective-C, where types
+// are first-class objects themselves.
+//
+class SimObjectClass
+{
+ public:
+ // Type CreateFunc is a pointer to a function that creates a new
+ // simulation object builder based on a .ini-file parameter
+ // section (specified by the first string argument), a unique name
+ // for the object (specified by the second string argument), and
+ // an optional config hierarchy node (specified by the third
+ // argument). A pointer to the new SimObjectBuilder is returned.
+ typedef SimObjectBuilder *(*CreateFunc)(const std::string &iniSection);
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SimObjectClass baseCacheClass("BaseCache", newBaseCacheBuilder);
+ //
+ SimObjectClass(const std::string &className, CreateFunc createFunc);
+
+ // create SimObject given name of class and pointer to
+ // configuration hierarchy node
+ static SimObject *createObject(IniFile &configDB,
+ const std::string &iniSection);
+
+ // print descriptions of all parameters registered with all
+ // SimObject classes
+ static void describeAllClasses(std::ostream &os);
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SimObjectBuilder and SimObjectClass objects
+//
+
+#define BEGIN_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+class OBJ_CLASS##Builder : public SimObjectBuilder \
+{ \
+ public:
+
+#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+ \
+ OBJ_CLASS##Builder(const std::string &iniSection); \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+};
+
+#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+ OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &iSec) \
+ : SimObjectBuilder(iSec),
+
+
+#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+{ \
+}
+
+#define CREATE_SIM_OBJECT(OBJ_CLASS) \
+OBJ_CLASS *OBJ_CLASS##Builder::create()
+
+#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \
+SimObjectBuilder * \
+new##OBJ_CLASS##Builder(const std::string &iniSection) \
+{ \
+ return new OBJ_CLASS##Builder(iniSection); \
+} \
+ \
+SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder); \
+ \
+/* see param.hh */ \
+DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS)
+
+/* Macros that use the namespace for sinic... yuk. */
+#define BEGIN_DECLARE_SIM_OBJECT_PARAMS_WNS(NAME_SPACE, OBJ_CLASS) \
+class NAME_SPACE##OBJ_CLASS##Builder : public SimObjectBuilder \
+{ \
+ public:
+
+#define END_DECLARE_SIM_OBJECT_PARAMS_WNS(NAME_SPACE, OBJ_CLASS) \
+ \
+ NAME_SPACE##OBJ_CLASS##Builder(const std::string &iniSection); \
+ virtual ~NAME_SPACE##OBJ_CLASS##Builder() {} \
+ \
+ NAME_SPACE::OBJ_CLASS *create(); \
+};
+
+#define BEGIN_INIT_SIM_OBJECT_PARAMS_WNS(NAME_SPACE, OBJ_CLASS) \
+ NAME_SPACE::OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &iSec) \
+ : SimObjectBuilder(iSec),
+
+
+#define END_INIT_SIM_OBJECT_PARAMS_WNS(NAME_SPACE, OBJ_CLASS) \
+{ \
+}
+
+#define CREATE_SIM_OBJECT_WNS(NAME_SPACE, OBJ_CLASS) \
+NAME_SPACE::OBJ_CLASS *NAME_SPACE##OBJ_CLASS##Builder::create()
+
+#define REGISTER_SIM_OBJECT_WNS(NAME_SPACE, CLASS_NAME, OBJ_CLASS) \
+SimObjectBuilder * \
+new##NAME_SPACEi##OBJ_CLASS##Builder(const std::string &iniSection) \
+{ \
+ return new NAME_SPACE##OBJ_CLASS##Builder(iniSection); \
+} \
+ \
+SimObjectClass the##NAME_SPACE##OBJ_CLASS##Class(CLASS_NAME, \
+ new##NAME_SPACE##OBJ_CLASS##Builder); \
+ \
+/* see param.hh */ \
+DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, NAME_SPACE##OBJ_CLASS)
+
+
+
+#endif // __BUILDER_HH__
diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh
new file mode 100644
index 000000000..7648b8fcd
--- /dev/null
+++ b/src/sim/byteswap.hh
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ * Ali Saidi
+ * Nathan Binkert
+ */
+
+//The purpose of this file is to provide endainness conversion utility
+//functions. Depending on the endianness of the guest system, either
+//the LittleEndianGuest or BigEndianGuest namespace is used.
+
+#ifndef __SIM_BYTE_SWAP_HH__
+#define __SIM_BYTE_SWAP_HH__
+
+#include "base/misc.hh"
+#include "sim/host.hh"
+
+// This lets us figure out what the byte order of the host system is
+#if defined(linux)
+#include <endian.h>
+// If this is a linux system, lets used the optimized definitions if they exist.
+// If one doesn't exist, we pretty much get what is listed below, so it all
+// works out
+#include <byteswap.h>
+#else
+#include <machine/endian.h>
+#endif
+
+#if defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#endif
+
+//These functions actually perform the swapping for parameters
+//of various bit lengths
+static inline uint64_t
+swap_byte64(uint64_t x)
+{
+#if defined(linux)
+ return bswap_64(x);
+#elif defined(__APPLE__)
+ return OSSwapInt64(x);
+#else
+ return (uint64_t)((((uint64_t)(x) & 0xff) << 56) |
+ ((uint64_t)(x) & 0xff00ULL) << 40 |
+ ((uint64_t)(x) & 0xff0000ULL) << 24 |
+ ((uint64_t)(x) & 0xff000000ULL) << 8 |
+ ((uint64_t)(x) & 0xff00000000ULL) >> 8 |
+ ((uint64_t)(x) & 0xff0000000000ULL) >> 24 |
+ ((uint64_t)(x) & 0xff000000000000ULL) >> 40 |
+ ((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ;
+#endif
+}
+
+static inline uint32_t
+swap_byte32(uint32_t x)
+{
+#if defined(linux)
+ return bswap_32(x);
+#elif defined(__APPLE__)
+ return OSSwapInt32(x);
+#else
+ return (uint32_t)(((uint32_t)(x) & 0xff) << 24 |
+ ((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 |
+ ((uint32_t)(x) & 0xff000000) >> 24);
+#endif
+}
+
+static inline uint16_t
+swap_byte16(uint16_t x)
+{
+#if defined(linux)
+ return bswap_16(x);
+#elif defined(__APPLE__)
+ return OSSwapInt16(x);
+#else
+ return (uint16_t)(((uint16_t)(x) & 0xff) << 8 |
+ ((uint16_t)(x) & 0xff00) >> 8);
+#endif
+}
+
+// This function lets the compiler figure out how to call the
+// swap_byte functions above for different data types. Since the
+// sizeof() values are known at compiel time, it should inline to a
+// direct call to the right swap_byteNN() function.
+template <typename T>
+static inline T swap_byte(T x) {
+ if (sizeof(T) == 8)
+ return swap_byte64((uint64_t)x);
+ else if (sizeof(T) == 4)
+ return swap_byte32((uint32_t)x);
+ else if (sizeof(T) == 2)
+ return swap_byte16((uint16_t)x);
+ else if (sizeof(T) == 1)
+ return x;
+ else
+ panic("Can't byte-swap values larger than 64 bits");
+}
+
+//The conversion functions with fixed endianness on both ends don't need to
+//be in a namespace
+template <typename T> static inline T betole(T value) {return swap_byte(value);}
+template <typename T> static inline T letobe(T value) {return swap_byte(value);}
+
+//For conversions not involving the guest system, we can define the functions
+//conditionally based on the BYTE_ORDER macro and outside of the namespaces
+#if BYTE_ORDER == BIG_ENDIAN
+template <typename T> static inline T htole(T value) {return swap_byte(value);}
+template <typename T> static inline T letoh(T value) {return swap_byte(value);}
+template <typename T> static inline T htobe(T value) {return value;}
+template <typename T> static inline T betoh(T value) {return value;}
+#elif BYTE_ORDER == LITTLE_ENDIAN
+template <typename T> static inline T htole(T value) {return value;}
+template <typename T> static inline T letoh(T value) {return value;}
+template <typename T> static inline T htobe(T value) {return swap_byte(value);}
+template <typename T> static inline T betoh(T value) {return swap_byte(value);}
+#else
+ #error Invalid Endianess
+#endif
+
+namespace BigEndianGuest
+{
+ template <typename T>
+ static inline T gtole(T value) {return betole(value);}
+ template <typename T>
+ static inline T letog(T value) {return letobe(value);}
+ template <typename T>
+ static inline T gtobe(T value) {return value;}
+ template <typename T>
+ static inline T betog(T value) {return value;}
+ template <typename T>
+ static inline T htog(T value) {return htobe(value);}
+ template <typename T>
+ static inline T gtoh(T value) {return betoh(value);}
+}
+
+namespace LittleEndianGuest
+{
+ template <typename T>
+ static inline T gtole(T value) {return value;}
+ template <typename T>
+ static inline T letog(T value) {return value;}
+ template <typename T>
+ static inline T gtobe(T value) {return letobe(value);}
+ template <typename T>
+ static inline T betog(T value) {return betole(value);}
+ template <typename T>
+ static inline T htog(T value) {return htole(value);}
+ template <typename T>
+ static inline T gtoh(T value) {return letoh(value);}
+}
+#endif // __SIM_BYTE_SWAP_HH__
diff --git a/src/sim/debug.cc b/src/sim/debug.cc
new file mode 100644
index 000000000..be9566836
--- /dev/null
+++ b/src/sim/debug.cc
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "sim/debug.hh"
+#include "sim/eventq.hh"
+#include "sim/param.hh"
+#include "sim/sim_events.hh"
+
+using namespace std;
+
+void
+debug_break()
+{
+#ifndef NDEBUG
+ kill(getpid(), SIGTRAP);
+#else
+ cprintf("debug_break suppressed, compiled with NDEBUG\n");
+#endif
+}
+
+//
+// Debug event: place a breakpoint on the process function and
+// schedule the event to break at a particular cycle
+//
+class DebugBreakEvent : public Event
+{
+ public:
+
+ DebugBreakEvent(EventQueue *q, Tick _when);
+
+ void process(); // process event
+ virtual const char *description();
+};
+
+//
+// constructor: schedule at specified time
+//
+DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when)
+ : Event(q, Debug_Break_Pri)
+{
+ setFlags(AutoDelete);
+ schedule(_when);
+}
+
+//
+// handle debug event: set debugger breakpoint on this function
+//
+void
+DebugBreakEvent::process()
+{
+ debug_break();
+}
+
+
+const char *
+DebugBreakEvent::description()
+{
+ return "debug break";
+}
+
+//
+// Parameter context for global debug options
+//
+class DebugContext : public ParamContext
+{
+ public:
+ DebugContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+DebugContext debugParams("debug");
+
+VectorParam<Tick> break_cycles(&debugParams, "break_cycles",
+ "cycle(s) to create breakpoint events");
+
+void
+DebugContext::checkParams()
+{
+ if (break_cycles.isValid()) {
+ vector<Tick> &cycles = break_cycles;
+
+ vector<Tick>::iterator i = cycles.begin();
+ vector<Tick>::iterator end = cycles.end();
+
+ for (; i < end; ++i)
+ new DebugBreakEvent(&mainEventQueue, *i);
+ }
+}
+
+//
+// handy function to schedule DebugBreakEvent on main event queue
+// (callable from debugger)
+//
+void sched_break_cycle(Tick when)
+{
+ new DebugBreakEvent(&mainEventQueue, when);
+}
+
+void eventq_dump()
+{
+ mainEventQueue.dump();
+}
+
diff --git a/src/sim/debug.hh b/src/sim/debug.hh
new file mode 100644
index 000000000..79792234b
--- /dev/null
+++ b/src/sim/debug.hh
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __DEBUG_HH__
+#define __DEBUG_HH__
+
+void debug_break();
+
+#endif // __DEBUG_HH__
diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc
new file mode 100644
index 000000000..6ae838897
--- /dev/null
+++ b/src/sim/eventq.cc
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Nathan Binkert
+ * Steve Raasch
+ */
+
+#include <assert.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "cpu/smt.hh"
+#include "base/misc.hh"
+
+#include "sim/eventq.hh"
+#include "base/trace.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+EventQueue mainEventQueue("MainEventQueue");
+
+void
+EventQueue::insert(Event *event)
+{
+ if (head == NULL || event->when() < head->when() ||
+ (event->when() == head->when() &&
+ event->priority() <= head->priority())) {
+ event->next = head;
+ head = event;
+ } else {
+ Event *prev = head;
+ Event *curr = head->next;
+
+ while (curr) {
+ if (event->when() <= curr->when() &&
+ (event->when() < curr->when() ||
+ event->priority() <= curr->priority()))
+ break;
+
+ prev = curr;
+ curr = curr->next;
+ }
+
+ event->next = curr;
+ prev->next = event;
+ }
+}
+
+void
+EventQueue::remove(Event *event)
+{
+ if (head == NULL)
+ return;
+
+ if (head == event){
+ head = event->next;
+ return;
+ }
+
+ Event *prev = head;
+ Event *curr = head->next;
+ while (curr && curr != event) {
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (curr == event)
+ prev->next = curr->next;
+}
+
+Event *
+EventQueue::serviceOne()
+{
+ Event *event = head;
+ event->clearFlags(Event::Scheduled);
+ head = event->next;
+
+ // handle action
+ if (!event->squashed()) {
+ event->process();
+ if (event->isExitEvent()) {
+ assert(!event->getFlags(Event::AutoDelete)); // would be silly
+ return event;
+ }
+ } else {
+ event->clearFlags(Event::Squashed);
+ }
+
+ if (event->getFlags(Event::AutoDelete) && !event->scheduled())
+ delete event;
+
+ return NULL;
+}
+
+
+void
+Event::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(_when);
+ SERIALIZE_SCALAR(_priority);
+ SERIALIZE_ENUM(_flags);
+}
+
+
+void
+Event::unserialize(Checkpoint *cp, const string &section)
+{
+ if (scheduled())
+ deschedule();
+
+ UNSERIALIZE_SCALAR(_when);
+ UNSERIALIZE_SCALAR(_priority);
+
+ // need to see if original event was in a scheduled, unsquashed
+ // state, but don't want to restore those flags in the current
+ // object itself (since they aren't immediately true)
+ UNSERIALIZE_ENUM(_flags);
+ bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed);
+ _flags &= ~(Squashed | Scheduled);
+
+ if (wasScheduled) {
+ DPRINTF(Config, "rescheduling at %d\n", _when);
+ schedule(_when);
+ }
+}
+
+void
+EventQueue::serialize(ostream &os)
+{
+ std::list<Event *> eventPtrs;
+
+ int numEvents = 0;
+ Event *event = head;
+ while (event) {
+ if (event->getFlags(Event::AutoSerialize)) {
+ eventPtrs.push_back(event);
+ paramOut(os, csprintf("event%d", numEvents++), event->name());
+ }
+ event = event->next;
+ }
+
+ SERIALIZE_SCALAR(numEvents);
+
+ for (std::list<Event *>::iterator it=eventPtrs.begin();
+ it != eventPtrs.end(); ++it) {
+ (*it)->nameOut(os);
+ (*it)->serialize(os);
+ }
+}
+
+void
+EventQueue::unserialize(Checkpoint *cp, const std::string &section)
+{
+ int numEvents;
+ UNSERIALIZE_SCALAR(numEvents);
+
+ std::string eventName;
+ for (int i = 0; i < numEvents; i++) {
+ // get the pointer value associated with the event
+ paramIn(cp, section, csprintf("event%d", i), eventName);
+
+ // create the event based on its pointer value
+ Serializable::create(cp, eventName);
+ }
+}
+
+void
+EventQueue::dump()
+{
+ cprintf("============================================================\n");
+ cprintf("EventQueue Dump (cycle %d)\n", curTick);
+ cprintf("------------------------------------------------------------\n");
+
+ if (empty())
+ cprintf("<No Events>\n");
+ else {
+ Event *event = head;
+ while (event) {
+ event->dump();
+ event = event->next;
+ }
+ }
+
+ cprintf("============================================================\n");
+}
+
+extern "C"
+void
+dumpMainQueue()
+{
+ mainEventQueue.dump();
+}
+
+
+const char *
+Event::description()
+{
+ return "generic";
+}
+
+#if TRACING_ON
+void
+Event::trace(const char *action)
+{
+ // This DPRINTF is unconditional because calls to this function
+ // are protected by an 'if (DTRACE(Event))' in the inlined Event
+ // methods.
+ //
+ // This is just a default implementation for derived classes where
+ // it's not worth doing anything special. If you want to put a
+ // more informative message in the trace, override this method on
+ // the particular subclass where you have the information that
+ // needs to be printed.
+ DPRINTFN("%s event %s @ %d\n", description(), action, when());
+}
+#endif
+
+void
+Event::dump()
+{
+ cprintf("Event (%s)\n", description());
+ cprintf("Flags: %#x\n", _flags);
+#if TRACING_ON
+ cprintf("Created: %d\n", when_created);
+#endif
+ if (scheduled()) {
+#if TRACING_ON
+ cprintf("Scheduled at %d\n", when_scheduled);
+#endif
+ cprintf("Scheduled for %d, priority %d\n", when(), _priority);
+ }
+ else {
+ cprintf("Not Scheduled\n");
+ }
+}
diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh
new file mode 100644
index 000000000..537bfb918
--- /dev/null
+++ b/src/sim/eventq.hh
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Nathan Binkert
+ */
+
+/* @file
+ * EventQueue interfaces
+ */
+
+#ifndef __SIM_EVENTQ_HH__
+#define __SIM_EVENTQ_HH__
+
+#include <assert.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "sim/host.hh" // for Tick
+
+#include "base/fast_alloc.hh"
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "sim/serialize.hh"
+
+class EventQueue; // forward declaration
+
+//////////////////////
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+// defined in eventq.cc
+//
+//////////////////////
+extern EventQueue mainEventQueue;
+
+
+/*
+ * An item on an event queue. The action caused by a given
+ * event is specified by deriving a subclass and overriding the
+ * process() member function.
+ */
+class Event : public Serializable, public FastAlloc
+{
+ friend class EventQueue;
+
+ private:
+ /// queue to which this event belongs (though it may or may not be
+ /// scheduled on this queue yet)
+ EventQueue *queue;
+
+ Event *next;
+
+ Tick _when; //!< timestamp when event should be processed
+ int _priority; //!< event priority
+ char _flags;
+
+ protected:
+ enum Flags {
+ None = 0x0,
+ Squashed = 0x1,
+ Scheduled = 0x2,
+ AutoDelete = 0x4,
+ AutoSerialize = 0x8,
+ IsExitEvent = 0x10
+ };
+
+ bool getFlags(Flags f) const { return (_flags & f) == f; }
+ void setFlags(Flags f) { _flags |= f; }
+ void clearFlags(Flags f) { _flags &= ~f; }
+
+ protected:
+ EventQueue *theQueue() const { return queue; }
+
+#if TRACING_ON
+ Tick when_created; //!< Keep track of creation time For debugging
+ Tick when_scheduled; //!< Keep track of creation time For debugging
+
+ virtual void trace(const char *action); //!< trace event activity
+#else
+ void trace(const char *) {}
+#endif
+
+ unsigned annotated_value;
+
+ public:
+
+ /// Event priorities, to provide tie-breakers for events scheduled
+ /// at the same cycle. Most events are scheduled at the default
+ /// priority; these values are used to control events that need to
+ /// be ordered within a cycle.
+ enum Priority {
+ /// Breakpoints should happen before anything else, so we
+ /// don't miss any action when debugging.
+ Debug_Break_Pri = -100,
+
+ /// For some reason "delayed" inter-cluster writebacks are
+ /// scheduled before regular writebacks (which have default
+ /// priority). Steve?
+ Delayed_Writeback_Pri = -1,
+
+ /// Default is zero for historical reasons.
+ Default_Pri = 0,
+
+ /// CPU switches schedule the new CPU's tick event for the
+ /// same cycle (after unscheduling the old CPU's tick event).
+ /// The switch needs to come before any tick events to make
+ /// sure we don't tick both CPUs in the same cycle.
+ CPU_Switch_Pri = -31,
+
+ /// Serailization needs to occur before tick events also, so
+ /// that a serialize/unserialize is identical to an on-line
+ /// CPU switch.
+ Serialize_Pri = 32,
+
+ /// CPU ticks must come after other associated CPU events
+ /// (such as writebacks).
+ CPU_Tick_Pri = 50,
+
+ /// Statistics events (dump, reset, etc.) come after
+ /// everything else, but before exit.
+ Stat_Event_Pri = 90,
+
+ /// If we want to exit on this cycle, it's the very last thing
+ /// we do.
+ Sim_Exit_Pri = 100
+ };
+
+ /*
+ * Event constructor
+ * @param queue that the event gets scheduled on
+ */
+ Event(EventQueue *q, Priority p = Default_Pri)
+ : queue(q), next(NULL), _priority(p), _flags(None),
+#if TRACING_ON
+ when_created(curTick), when_scheduled(0),
+#endif
+ annotated_value(0)
+ {
+ }
+
+ ~Event() {}
+
+ virtual const std::string name() const {
+ return csprintf("Event_%x", (uintptr_t)this);
+ }
+
+ /// Determine if the current event is scheduled
+ bool scheduled() const { return getFlags(Scheduled); }
+
+ /// Schedule the event with the current priority or default priority
+ void schedule(Tick t);
+
+ /// Reschedule the event with the current priority
+ void reschedule(Tick t);
+
+ /// Remove the event from the current schedule
+ void deschedule();
+
+ /// Return a C string describing the event. This string should
+ /// *not* be dynamically allocated; just a const char array
+ /// describing the event class.
+ virtual const char *description();
+
+ /// Dump the current event data
+ void dump();
+
+ /*
+ * This member function is invoked when the event is processed
+ * (occurs). There is no default implementation; each subclass
+ * must provide its own implementation. The event is not
+ * automatically deleted after it is processed (to allow for
+ * statically allocated event objects).
+ *
+ * If the AutoDestroy flag is set, the object is deleted once it
+ * is processed.
+ */
+ virtual void process() = 0;
+
+ void annotate(unsigned value) { annotated_value = value; };
+ unsigned annotation() { return annotated_value; }
+
+ /// Squash the current event
+ void squash() { setFlags(Squashed); }
+
+ /// Check whether the event is squashed
+ bool squashed() { return getFlags(Squashed); }
+
+ /// See if this is a SimExitEvent (without resorting to RTTI)
+ bool isExitEvent() { return getFlags(IsExitEvent); }
+
+ /// Get the time that the event is scheduled
+ Tick when() const { return _when; }
+
+ /// Get the event priority
+ int priority() const { return _priority; }
+
+ struct priority_compare :
+ public std::binary_function<Event *, Event *, bool>
+ {
+ bool operator()(const Event *l, const Event *r) const {
+ return l->when() >= r->when() || l->priority() >= r->priority();
+ }
+ };
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+template <class T, void (T::* F)()>
+void
+DelayFunction(Tick when, T *object)
+{
+ class DelayEvent : public Event
+ {
+ private:
+ T *object;
+
+ public:
+ DelayEvent(Tick when, T *o)
+ : Event(&mainEventQueue), object(o)
+ { setFlags(this->AutoDestroy); schedule(when); }
+ void process() { (object->*F)(); }
+ const char *description() { return "delay"; }
+ };
+
+ new DelayEvent(when, object);
+}
+
+template <class T, void (T::* F)()>
+class EventWrapper : public Event
+{
+ private:
+ T *object;
+
+ public:
+ EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue,
+ Priority p = Default_Pri)
+ : Event(q, p), object(obj)
+ {
+ if (del)
+ setFlags(AutoDelete);
+ }
+ void process() { (object->*F)(); }
+};
+
+/*
+ * Queue of events sorted in time order
+ */
+class EventQueue : public Serializable
+{
+ protected:
+ std::string objName;
+
+ private:
+ Event *head;
+
+ void insert(Event *event);
+ void remove(Event *event);
+
+ public:
+
+ // constructor
+ EventQueue(const std::string &n)
+ : objName(n), head(NULL)
+ {}
+
+ virtual const std::string name() const { return objName; }
+
+ // schedule the given event on this queue
+ void schedule(Event *ev);
+ void deschedule(Event *ev);
+ void reschedule(Event *ev);
+
+ Tick nextTick() { return head->when(); }
+ Event *serviceOne();
+
+ // process all events up to the given timestamp. we inline a
+ // quick test to see if there are any events to process; if so,
+ // call the internal out-of-line version to process them all.
+ void serviceEvents(Tick when) {
+ while (!empty()) {
+ if (nextTick() > when)
+ break;
+
+ /**
+ * @todo this assert is a good bug catcher. I need to
+ * make it true again.
+ */
+ //assert(head->when() >= when && "event scheduled in the past");
+ serviceOne();
+ }
+ }
+
+ // default: process all events up to 'now' (curTick)
+ void serviceEvents() { serviceEvents(curTick); }
+
+ // return true if no events are queued
+ bool empty() { return head == NULL; }
+
+ void dump();
+
+ Tick nextEventTime() { return empty() ? curTick : head->when(); }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+
+//////////////////////
+//
+// inline functions
+//
+// can't put these inside declaration due to circular dependence
+// between Event and EventQueue classes.
+//
+//////////////////////
+
+// schedule at specified time (place on event queue specified via
+// constructor)
+inline void
+Event::schedule(Tick t)
+{
+ assert(!scheduled());
+// if (t < curTick)
+// warn("t is less than curTick, ensure you don't want cycles");
+
+ setFlags(Scheduled);
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->schedule(this);
+}
+
+inline void
+Event::deschedule()
+{
+ assert(scheduled());
+
+ clearFlags(Squashed);
+ clearFlags(Scheduled);
+ queue->deschedule(this);
+}
+
+inline void
+Event::reschedule(Tick t)
+{
+ assert(scheduled());
+ clearFlags(Squashed);
+
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->reschedule(this);
+}
+
+inline void
+EventQueue::schedule(Event *event)
+{
+ insert(event);
+ if (DTRACE(Event))
+ event->trace("scheduled");
+}
+
+inline void
+EventQueue::deschedule(Event *event)
+{
+ remove(event);
+ if (DTRACE(Event))
+ event->trace("descheduled");
+}
+
+inline void
+EventQueue::reschedule(Event *event)
+{
+ remove(event);
+ insert(event);
+ if (DTRACE(Event))
+ event->trace("rescheduled");
+}
+
+
+
+#endif // __SIM_EVENTQ_HH__
diff --git a/src/sim/faults.cc b/src/sim/faults.cc
new file mode 100644
index 000000000..650b728f7
--- /dev/null
+++ b/src/sim/faults.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Gabe Black
+ */
+
+#include "base/misc.hh"
+#include "sim/faults.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/base.hh"
+
+#if !FULL_SYSTEM
+void FaultBase::invoke(ThreadContext * tc)
+{
+ fatal("fault (%s) detected @ PC 0x%08p", name(), tc->readPC());
+}
+#else
+void FaultBase::invoke(ThreadContext * tc)
+{
+ DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), tc->readPC());
+ tc->getCpuPtr()->recordEvent(csprintf("Fault %s", name()));
+
+ assert(!tc->misspeculating());
+}
+#endif
+
+void UnimpFault::invoke(ThreadContext * tc)
+{
+ panic("Unimpfault: %s\n", panicStr.c_str());
+}
diff --git a/src/sim/faults.hh b/src/sim/faults.hh
new file mode 100644
index 000000000..00264d8fc
--- /dev/null
+++ b/src/sim/faults.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Gabe Black
+ */
+
+#ifndef __FAULTS_HH__
+#define __FAULTS_HH__
+
+#include "base/refcnt.hh"
+#include "sim/stats.hh"
+#include "config/full_system.hh"
+
+class ThreadContext;
+class FaultBase;
+typedef RefCountingPtr<FaultBase> Fault;
+
+typedef const char * FaultName;
+typedef Stats::Scalar<> FaultStat;
+
+// Each class has it's name statically define in _name,
+// and has a virtual function to access it's name.
+// The function is necessary because otherwise, all objects
+// which are being accessed cast as a FaultBase * (namely
+// all faults returned using the Fault type) will use the
+// generic FaultBase name.
+
+class FaultBase : public RefCounted
+{
+ public:
+ virtual FaultName name() = 0;
+ virtual void invoke(ThreadContext * tc);
+// template<typename T>
+// bool isA() {return dynamic_cast<T *>(this);}
+ virtual bool isMachineCheckFault() {return false;}
+ virtual bool isAlignmentFault() {return false;}
+};
+
+FaultBase * const NoFault = 0;
+
+class UnimpFault : public FaultBase
+{
+ private:
+ std::string panicStr;
+ public:
+ UnimpFault(std::string _str)
+ : panicStr(_str)
+ { }
+
+ FaultName name() {return "Unimplemented simulator feature";}
+ void invoke(ThreadContext * tc);
+};
+
+#endif // __FAULTS_HH__
diff --git a/src/sim/host.hh b/src/sim/host.hh
new file mode 100644
index 000000000..9c79580b1
--- /dev/null
+++ b/src/sim/host.hh
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/**
+ * @file
+ * Defines host-dependent types:
+ * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t.
+ */
+
+#ifndef __HOST_HH__
+#define __HOST_HH__
+
+#include <inttypes.h>
+
+/** uint64_t constant */
+#define ULL(N) ((uint64_t)N##ULL)
+/** int64_t constant */
+#define LL(N) (((int64_t)N##LL)
+
+/** Statistics counter type. Not much excuse for not using a 64-bit
+ * integer here, but if you're desperate and only run short
+ * simulations you could make this 32 bits.
+ */
+typedef int64_t Counter;
+
+/**
+ * Clock cycle count type.
+ * @note using an unsigned breaks the cache.
+ */
+typedef int64_t Tick;
+
+const Tick MaxTick = (1LL << 62);
+
+/**
+ * Address type
+ * This will probably be moved somewhere else in the near future.
+ * This should be at least as big as the biggest address width in use
+ * in the system, which will probably be 64 bits.
+ */
+typedef uint64_t Addr;
+
+const Addr MaxAddr = (Addr)-1;
+
+#endif // __HOST_H__
diff --git a/src/sim/main.cc b/src/sim/main.cc
new file mode 100644
index 000000000..5725897f8
--- /dev/null
+++ b/src/sim/main.cc
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Raasch
+ * Nathan Binkert
+ * Steve Reinhardt
+ */
+
+///
+/// @file sim/main.cc
+///
+#include <Python.h> // must be before system headers... see Python docs
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <getopt.h>
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/callback.hh"
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/pollevent.hh"
+#include "base/statistics.hh"
+#include "base/str.hh"
+#include "base/time.hh"
+#include "cpu/base.hh"
+#include "cpu/smt.hh"
+#include "mem/mem_object.hh"
+#include "mem/port.hh"
+#include "sim/async.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+#include "sim/stat_control.hh"
+#include "sim/stats.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+// See async.h.
+volatile bool async_event = false;
+volatile bool async_dump = false;
+volatile bool async_dumpreset = false;
+volatile bool async_exit = false;
+volatile bool async_io = false;
+volatile bool async_alarm = false;
+
+/// Stats signal handler.
+void
+dumpStatsHandler(int sigtype)
+{
+ async_event = true;
+ async_dump = true;
+}
+
+void
+dumprstStatsHandler(int sigtype)
+{
+ async_event = true;
+ async_dumpreset = true;
+}
+
+/// Exit signal handler.
+void
+exitNowHandler(int sigtype)
+{
+ async_event = true;
+ async_exit = true;
+}
+
+/// Abort signal handler.
+void
+abortHandler(int sigtype)
+{
+ cerr << "Program aborted at cycle " << curTick << endl;
+
+#if TRACING_ON
+ // dump trace buffer, if there is one
+ Trace::theLog.dump(cerr);
+#endif
+}
+
+extern "C" { void init_cc_main(); }
+
+int
+main(int argc, char **argv)
+{
+ signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
+ signal(SIGTRAP, SIG_IGN);
+ signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats
+ signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats
+ signal(SIGINT, exitNowHandler); // dump final stats and exit
+ signal(SIGABRT, abortHandler);
+
+ Py_SetProgramName(argv[0]);
+
+ // default path to m5 python code is the currently executing
+ // file... Python ZipImporter will find embedded zip archive.
+ // The M5_ARCHIVE environment variable can be used to override this.
+ char *m5_archive = getenv("M5_ARCHIVE");
+ string pythonpath = m5_archive ? m5_archive : argv[0];
+
+ char *oldpath = getenv("PYTHONPATH");
+ if (oldpath != NULL) {
+ pythonpath += ":";
+ pythonpath += oldpath;
+ }
+
+ if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1)
+ fatal("setenv: %s\n", strerror(errno));
+
+ // initialize embedded Python interpreter
+ Py_Initialize();
+ PySys_SetArgv(argc, argv);
+
+ // initialize SWIG 'cc_main' module
+ init_cc_main();
+
+ PyRun_SimpleString("import m5.main");
+ PyRun_SimpleString("m5.main.main()");
+
+ // clean up Python intepreter.
+ Py_Finalize();
+}
+
+
+void
+setOutputDir(const string &dir)
+{
+ simout.setDirectory(dir);
+}
+
+
+IniFile inifile;
+
+SimObject *
+createSimObject(const string &name)
+{
+ return SimObjectClass::createObject(inifile, name);
+}
+
+
+/**
+ * Pointer to the Python function that maps names to SimObjects.
+ */
+PyObject *resolveFunc = NULL;
+
+/**
+ * Convert a pointer to the Python object that SWIG wraps around a C++
+ * SimObject pointer back to the actual C++ pointer. See main.i.
+ */
+extern "C" SimObject *convertSwigSimObjectPtr(PyObject *);
+
+
+SimObject *
+resolveSimObject(const string &name)
+{
+ PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str());
+ if (pyPtr == NULL) {
+ PyErr_Print();
+ panic("resolveSimObject: failure on call to Python for %s", name);
+ }
+
+ SimObject *simObj = convertSwigSimObjectPtr(pyPtr);
+ if (simObj == NULL)
+ panic("resolveSimObject: failure on pointer conversion for %s", name);
+
+ return simObj;
+}
+
+
+/**
+ * Load config.ini into C++ database. Exported to Python via SWIG;
+ * invoked from m5.instantiate().
+ */
+void
+loadIniFile(PyObject *_resolveFunc)
+{
+ resolveFunc = _resolveFunc;
+ configStream = simout.find("config.out");
+
+ // The configuration database is now complete; start processing it.
+ inifile.load(simout.resolve("config.ini"));
+
+ // Initialize statistics database
+ Stats::InitSimStats();
+}
+
+
+/**
+ * Look up a MemObject port. Helper function for connectPorts().
+ */
+Port *
+lookupPort(SimObject *so, const std::string &name, int i)
+{
+ MemObject *mo = dynamic_cast<MemObject *>(so);
+ if (mo == NULL) {
+ warn("error casting SimObject %s to MemObject", so->name());
+ return NULL;
+ }
+
+ Port *p = mo->getPort(name, i);
+ if (p == NULL)
+ warn("error looking up port %s on object %s", name, so->name());
+ return p;
+}
+
+
+/**
+ * Connect the described MemObject ports. Called from Python via SWIG.
+ */
+int
+connectPorts(SimObject *o1, const std::string &name1, int i1,
+ SimObject *o2, const std::string &name2, int i2)
+{
+ Port *p1 = lookupPort(o1, name1, i1);
+ Port *p2 = lookupPort(o2, name2, i2);
+
+ if (p1 == NULL || p2 == NULL) {
+ warn("connectPorts: port lookup error");
+ return 0;
+ }
+
+ p1->setPeer(p2);
+ p2->setPeer(p1);
+
+ return 1;
+}
+
+/**
+ * Do final initialization steps after object construction but before
+ * start of simulation.
+ */
+void
+finalInit()
+{
+ // Parse and check all non-config-hierarchy parameters.
+ ParamContext::parseAllContexts(inifile);
+ ParamContext::checkAllContexts();
+
+ // Echo all parameter settings to stats file as well.
+ ParamContext::showAllContexts(*configStream);
+
+ // Do a second pass to finish initializing the sim objects
+ SimObject::initAll();
+
+ // Restore checkpointed state, if any.
+#if 0
+ configHierarchy.unserializeSimObjects();
+#endif
+
+ SimObject::regAllStats();
+
+ // Check to make sure that the stats package is properly initialized
+ Stats::check();
+
+ // Reset to put the stats in a consistent state.
+ Stats::reset();
+
+ SimStartup();
+}
+
+
+/** Simulate for num_cycles additional cycles. If num_cycles is -1
+ * (the default), do not limit simulation; some other event must
+ * terminate the loop. Exported to Python via SWIG.
+ * @return The SimLoopExitEvent that caused the loop to exit.
+ */
+SimLoopExitEvent *
+simulate(Tick num_cycles = -1)
+{
+ warn("Entering event queue @ %d. Starting simulation...\n", curTick);
+
+ // Fix up num_cycles. Special default value -1 means simulate
+ // "forever"... schedule event at MaxTick just to be safe.
+ // Otherwise it's a delta for additional cycles to simulate past
+ // curTick, and thus must be non-negative.
+ if (num_cycles == -1)
+ num_cycles = MaxTick;
+ else if (num_cycles < 0)
+ fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
+ else
+ num_cycles = curTick + num_cycles;
+
+ Event *limit_event = new SimLoopExitEvent(num_cycles,
+ "simulate() limit reached");
+
+ while (1) {
+ // there should always be at least one event (the SimLoopExitEvent
+ // we just scheduled) in the queue
+ assert(!mainEventQueue.empty());
+ assert(curTick <= mainEventQueue.nextTick() &&
+ "event scheduled in the past");
+
+ // forward current cycle to the time of the first event on the
+ // queue
+ curTick = mainEventQueue.nextTick();
+ Event *exit_event = mainEventQueue.serviceOne();
+ if (exit_event != NULL) {
+ // hit some kind of exit event; return to Python
+ // event must be subclass of SimLoopExitEvent...
+ SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event);
+ if (se_event == NULL)
+ panic("Bogus exit event class!");
+
+ // if we didn't hit limit_event, delete it
+ if (se_event != limit_event) {
+ assert(limit_event->scheduled());
+ limit_event->deschedule();
+ delete limit_event;
+ }
+
+ return se_event;
+ }
+
+ if (async_event) {
+ async_event = false;
+ if (async_dump) {
+ async_dump = false;
+
+ using namespace Stats;
+ SetupEvent(Dump, curTick);
+ }
+
+ if (async_dumpreset) {
+ async_dumpreset = false;
+
+ using namespace Stats;
+ SetupEvent(Dump | Reset, curTick);
+ }
+
+ if (async_exit) {
+ async_exit = false;
+ exitSimLoop("user interrupt received");
+ }
+
+ if (async_io || async_alarm) {
+ async_io = false;
+ async_alarm = false;
+ pollQueue.service();
+ }
+ }
+ }
+
+ // not reached... only exit is return on SimLoopExitEvent
+}
+
+Event *
+createCountedDrain()
+{
+ return new CountedDrainEvent();
+}
+
+void
+cleanupCountedDrain(Event *counted_drain)
+{
+ CountedDrainEvent *event =
+ dynamic_cast<CountedDrainEvent *>(counted_drain);
+ if (event == NULL) {
+ fatal("Called cleanupCountedDrain() on an event that was not "
+ "a CountedDrainEvent.");
+ }
+ assert(event->getCount() == 0);
+ delete event;
+}
+
+void
+serializeAll(const std::string &cpt_dir)
+{
+ Serializable::serializeAll(cpt_dir);
+}
+
+void
+unserializeAll(const std::string &cpt_dir)
+{
+ Serializable::unserializeAll(cpt_dir);
+}
+
+/**
+ * Queue of C++ callbacks to invoke on simulator exit.
+ */
+CallbackQueue exitCallbacks;
+
+/**
+ * Register an exit callback.
+ */
+void
+registerExitCallback(Callback *callback)
+{
+ exitCallbacks.add(callback);
+}
+
+BaseCPU *
+convertToBaseCPUPtr(SimObject *obj)
+{
+ BaseCPU *ptr = dynamic_cast<BaseCPU *>(obj);
+
+ if (ptr == NULL)
+ warn("Casting to BaseCPU pointer failed");
+ return ptr;
+}
+
+/**
+ * Do C++ simulator exit processing. Exported to SWIG to be invoked
+ * when simulator terminates via Python's atexit mechanism.
+ */
+void
+doExitCleanup()
+{
+ exitCallbacks.process();
+ exitCallbacks.clear();
+
+ cout.flush();
+
+ ParamContext::cleanupAllContexts();
+
+ // print simulation stats
+ Stats::DumpNow();
+}
diff --git a/src/sim/param.cc b/src/sim/param.cc
new file mode 100644
index 000000000..b1c50946b
--- /dev/null
+++ b/src/sim/param.cc
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/range.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "sim/param.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// BaseParam member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+void
+BaseParam::die(const string &err) const
+{
+ context->printErrorProlog(cerr);
+ cerr << " parameter '" << name << "': "
+ << err << endl;
+ abort();
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Param<T> and VectorParam<T> member definitions
+//
+// We implement parsing & displaying values for various parameter
+// types T using a set of overloaded functions:
+//
+// - parseParam(string s, T &value) parses s into value
+// - showParam(ostream &os, T &value) displays value on os
+//
+// By making these independent functions, we can reuse the same code
+// for type T in both Param<T> and VectorParam<T>.
+//
+// For enum types, the parseParam function requires additional
+// arguments, in which case we must specialize the Param<T>::parse and
+// VectorParam<T>::parse calls as well.
+//
+// Type-specific instances come first, followed by more generic
+// templated versions and their instantiations.
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// The base implementations use to_number for parsing and '<<' for
+// displaying, suitable for integer types.
+//
+template <class T>
+bool
+parseParam(const string &s, T &value)
+{
+ return to_number(s, value);
+}
+
+template <class T>
+void
+showParam(ostream &os, T const &value)
+{
+ os << value;
+}
+
+//
+// Template specializations:
+// - char (8-bit integer)
+// - floating-point types
+// - bool
+// - string
+//
+
+// Treat 8-bit ints (chars) as ints on output, not as chars
+template <>
+void
+showParam(ostream &os, const char &value)
+{
+ os << (int)value;
+}
+
+
+template <>
+void
+showParam(ostream &os, const unsigned char &value)
+{
+ os << (unsigned int)value;
+}
+
+
+// Use sscanf() for FP types as to_number() only handles integers
+template <>
+bool
+parseParam(const string &s, float &value)
+{
+ return (sscanf(s.c_str(), "%f", &value) == 1);
+}
+
+template <>
+bool
+parseParam(const string &s, double &value)
+{
+ return (sscanf(s.c_str(), "%lf", &value) == 1);
+}
+
+// Be flexible about what we take for bool
+template <>
+bool
+parseParam(const string &s, bool &value)
+{
+ const string &ls = to_lower(s);
+
+ if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") {
+ value = true;
+ return true;
+ }
+
+ if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") {
+ value = false;
+ return true;
+ }
+
+ return false;
+}
+
+// Display bools as strings
+template <>
+void
+showParam(ostream &os, const bool &value)
+{
+ os << (value ? "true" : "false");
+}
+
+
+// String requires no processing to speak of
+template <>
+bool
+parseParam(const string &s, string &value)
+{
+ value = s;
+ return true;
+}
+
+template <>
+bool
+parseParam(const string &s, Range<uint32_t> &value)
+{
+ value = s;
+ return value.valid();
+}
+
+template <>
+bool
+parseParam(const string &s, Range<uint64_t> &value)
+{
+ value = s;
+ return value.valid();
+}
+
+//
+// End of parseParam/showParam definitions. Now we move on to
+// incorporate them into the Param/VectorParam parse() and showValue()
+// methods.
+//
+
+// These definitions for Param<T>::parse and VectorParam<T>::parse
+// work for any type for which parseParam() takes only two arguments
+// (i.e., all the fundamental types like int, bool, etc.), thanks to
+// overloading.
+template <class T>
+void
+Param<T>::parse(const string &s)
+{
+ if (parseParam(s, value)) {
+ wasSet = true;
+ }
+ else {
+ string err("could not parse \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+template <class T>
+void
+VectorParam<T>::parse(const string &s)
+{
+ if (s.empty()) {
+ wasSet = true;
+ return;
+ }
+
+ vector<string> tokens;
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ // need to parse into local variable to handle vector<bool>,
+ // for which operator[] returns a special reference class
+ // that's not the same as 'bool&', (since it's a packed
+ // vector)
+ T scalar_value;
+ if (!parseParam(tokens[i], scalar_value)) {
+ string err("could not parse \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+
+ // assign parsed value to vector
+ value[i] = scalar_value;
+ }
+
+ wasSet = true;
+}
+
+// These definitions for Param<T>::showValue() and
+// VectorParam<T>::showValue() work for any type where showParam()
+// takes only two arguments (i.e., everything but the SimpleEnum and
+// MappedEnum classes).
+template <class T>
+void
+Param<T>::showValue(ostream &os) const
+{
+ showParam(os, value);
+}
+
+template <class T>
+void
+VectorParam<T>::showValue(ostream &os) const
+{
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0) {
+ os << " ";
+ }
+ showParam(os, value[i]);
+ }
+}
+
+
+#ifdef INSURE_BUILD
+#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
+void Param<type>::showType(ostream &os) const { os << typestr; } \
+void VectorParam<type>::showType(ostream &os) const { \
+ os << "vector of " << typestr; \
+} \
+template Param<type>; \
+template VectorParam<type>;
+
+#else
+// instantiate all four methods (parse/show, scalar/vector) for basic
+// types that can use the above templates
+#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
+template bool parseParam<type>(const string &s, type &value); \
+template void showParam<type>(ostream &os, type const &value); \
+template void Param<type>::parse(const string &); \
+template void VectorParam<type>::parse(const string &); \
+template void Param<type>::showValue(ostream &) const; \
+template void VectorParam<type>::showValue(ostream &) const; \
+template <> void Param<type>::showType(ostream &os) const { os << typestr; } \
+template <> void VectorParam<type>::showType(ostream &os) const { \
+ os << "vector of " << typestr; \
+}
+#endif
+
+INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
+INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
+INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
+INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
+INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
+INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
+INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
+INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
+INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
+INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
+
+INSTANTIATE_PARAM_TEMPLATES(float, "float")
+INSTANTIATE_PARAM_TEMPLATES(double, "double")
+
+INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
+INSTANTIATE_PARAM_TEMPLATES(string, "string")
+
+INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range")
+INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range")
+
+#undef INSTANTIATE_PARAM_TEMPLATES
+
+//
+// SimpleEnumParam & MappedEnumParam must specialize their parse(),
+// showValue(), and showType() methods.
+//
+
+//
+// SimpleEnumParam & SimpleEnumVectorParam
+//
+bool
+parseEnumParam(const char *const *map, const int num_values,
+ const string &s, int &value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (s == map[i]) {
+ value = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+showEnumParam(ostream &os,
+ const char *const *map, const int num_values,
+ int value)
+{
+ assert(0 <= value && value < num_values);
+ os << map[value];
+}
+
+void
+showEnumType(ostream &os,
+ const char *const *map, const int num_values)
+{
+ os << "{" << map[0];
+ for (int i = 1; i < num_values; ++i)
+ os << "," << map[i];
+
+ os << "}";
+}
+
+
+//
+// MappedEnumParam & MappedEnumVectorParam
+//
+bool
+parseEnumParam(const EnumParamMap *map, const int num_values,
+ const string &s, int &value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (s == map[i].name) {
+ value = map[i].value;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+showEnumParam(ostream &os,
+ const EnumParamMap *map, const int num_values,
+ int value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (value == map[i].value) {
+ os << map[i].name;
+ return;
+ }
+ }
+
+ // if we can't find a reverse mapping just print the int value
+ os << value;
+}
+
+void
+showEnumType(ostream &os,
+ const EnumParamMap *map, const int num_values)
+{
+ os << "{" << map[0].name;
+ for (int i = 1; i < num_values; ++i)
+ os << "," << map[i].name;
+
+ os << "}";
+}
+
+
+template <class Map>
+void
+EnumParam<Map>::parse(const string &s)
+{
+ if (parseEnumParam(map, num_values, s, value)) {
+ wasSet = true;
+ } else {
+ string err("no match for enum string \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::parse(const string &s)
+{
+ vector<string> tokens;
+
+ if (s.empty()) {
+ wasSet = true;
+ return;
+ }
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ if (!parseEnumParam(map, num_values, tokens[i], value[i])) {
+ string err("no match for enum string \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+ }
+
+ wasSet = true;
+}
+
+template <class Map>
+void
+EnumParam<Map>::showValue(ostream &os) const
+{
+ showEnumParam(os, map, num_values, value);
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::showValue(ostream &os) const
+{
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0) {
+ os << " ";
+ }
+ showEnumParam(os, map, num_values, value[i]);
+ }
+}
+
+template <class Map>
+void
+EnumParam<Map>::showType(ostream &os) const
+{
+ showEnumType(os, map, num_values);
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::showType(ostream &os) const
+{
+ os << "vector of";
+ showEnumType(os, map, num_values);
+}
+
+template class EnumParam<const char *>;
+template class EnumVectorParam<const char *>;
+
+template class EnumParam<EnumParamMap>;
+template class EnumVectorParam<EnumParamMap>;
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObjectBaseParam methods
+//
+////////////////////////////////////////////////////////////////////////
+
+bool
+parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
+{
+ SimObject *obj;
+
+ if (to_lower(s) == "null") {
+ // explicitly set to null by user; assume that's OK
+ obj = NULL;
+ }
+ else {
+ // defined in main.cc
+ extern SimObject *resolveSimObject(const string &);
+ obj = resolveSimObject(s);
+
+ if (obj == NULL)
+ return false;
+ }
+
+ value = obj;
+ return true;
+}
+
+
+void
+SimObjectBaseParam::showValue(ostream &os, SimObject *value) const
+{
+ os << (value ? value->name() : "null");
+}
+
+void
+SimObjectBaseParam::parse(const string &s, SimObject *&value)
+{
+ if (parseSimObjectParam(context, s, value)) {
+ wasSet = true;
+ }
+ else {
+ string err("could not resolve object name \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+void
+SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value)
+{
+ vector<string> tokens;
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ if (!parseSimObjectParam(context, tokens[i], value[i])) {
+ string err("could not resolve object name \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+ }
+
+ wasSet = true;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ParamContext member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+list<ParamContext *> *ParamContext::ctxList = NULL;
+
+ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase)
+ : iniFilePtr(NULL), // initialized on call to parseParams()
+ iniSection(_iniSection), paramList(NULL),
+ initPhase(_initPhase)
+{
+ // Put this context on global list for initialization
+ if (initPhase != NoAutoInit) {
+ if (ctxList == NULL)
+ ctxList = new list<ParamContext *>();
+
+ // keep list sorted by ascending initPhase values
+ list<ParamContext *>::iterator i = ctxList->begin();
+ list<ParamContext *>::iterator end = ctxList->end();
+ for (; i != end; ++i) {
+ if (initPhase <= (*i)->initPhase) {
+ // found where we want to insert
+ break;
+ }
+ }
+ // (fall through case: insert at end)
+ ctxList->insert(i, this);
+ }
+}
+
+
+void
+ParamContext::addParam(BaseParam *param)
+{
+ getParamList()->push_back(param);
+}
+
+
+void
+ParamContext::parseParams(IniFile &iniFile)
+{
+ iniFilePtr = &iniFile; // set object member
+
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ string string_value;
+
+ if (iniFile.find(iniSection, (*i)->name, string_value))
+ (*i)->parse(string_value);
+ }
+}
+
+
+// Check parameter values for validity & consistency. Default
+// implementation is no-op; derive subclass & override to add
+// actual functionality here.
+void
+ParamContext::checkParams()
+{
+ // nada
+}
+
+
+// Clean up context-related objects at end of execution. Default
+// implementation is no-op; derive subclass & override to add actual
+// functionality here.
+void
+ParamContext::cleanup()
+{
+ // nada
+}
+
+
+void
+ParamContext::describeParams(ostream &os)
+{
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ BaseParam *p = *i;
+
+ os << p->name << " (";
+ p->showType(os);
+ os << "): " << p->description << "\n";
+ }
+}
+
+
+
+void
+ParamContext::showParams(ostream &os)
+{
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ BaseParam *p = *i;
+
+ if (p->isValid()) {
+ os << p->name << "=";
+ p->showValue(os);
+ os << endl;
+ }
+ else {
+ os << "// "<< p->name << " not specified" << endl;
+ }
+ }
+}
+
+
+void
+ParamContext::printErrorProlog(ostream &os)
+{
+ os << "Parameter error in section [" << iniSection << "]: " << endl;
+}
+
+//
+// static method: call parseParams() on all registered contexts
+//
+void
+ParamContext::parseAllContexts(IniFile &iniFile)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->parseParams(iniFile);
+ }
+}
+
+
+//
+// static method: call checkParams() on all registered contexts
+//
+void
+ParamContext::checkAllContexts()
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->checkParams();
+ }
+}
+
+
+//
+// static method: call showParams() on all registered contexts
+//
+void
+ParamContext::showAllContexts(ostream &os)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ os << "[" << pc->iniSection << "]" << endl;
+ pc->showParams(os);
+ os << endl;
+ }
+}
+
+
+//
+// static method: call cleanup() on all registered contexts
+//
+void
+ParamContext::cleanupAllContexts()
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->cleanup();
+ }
+}
+
+
+//
+// static method: call describeParams() on all registered contexts
+//
+void
+ParamContext::describeAllContexts(ostream &os)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ os << "[" << pc->iniSection << "]\n";
+ pc->describeParams(os);
+ os << endl;
+ }
+}
diff --git a/src/sim/param.hh b/src/sim/param.hh
new file mode 100644
index 000000000..1bc55c125
--- /dev/null
+++ b/src/sim/param.hh
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+#ifndef __SIM_PARAM_HH__
+#define __SIM_PARAM_HH__
+
+#include <iostream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "sim/startup.hh"
+
+// forward decls
+class IniFile;
+class BaseParam;
+class SimObject;
+
+//
+// The context of a parameter definition... usually a subclass of
+// SimObjectBuilder (which derives from ParamContext), but abstracted
+// here to support more global simulator control parameters as well.
+//
+class ParamContext : protected StartupCallback
+{
+ private:
+
+ // static list of all ParamContext objects, built as a side effect
+ // of the ParamContext constructor
+ static std::list<ParamContext *> *ctxList;
+
+ protected:
+
+ // .ini file (database) for parameter lookup... initialized on call
+ // to parseParams()
+ IniFile *iniFilePtr;
+
+ // .ini file section for parameter lookup
+ const std::string iniSection;
+
+ typedef std::vector<BaseParam *> ParamList;
+
+ // list of parameters defined in this context
+ ParamList *paramList;
+
+ ParamList *getParamList() {
+ if (!paramList)
+ paramList = new ParamList;
+ return paramList;
+ }
+
+ public:
+
+ /// Initialization phases for ParamContext objects.
+ enum InitPhase {
+ NoAutoInit = -1, ///< Don't initialize at all... params
+ /// will be parsed later (used by
+ /// SimObjectBuilder, which parses
+ /// params in SimObject::create().
+ OutputInitPhase = 0, ///< Output stream initialization
+ TraceInitPhase = 1, ///< Trace context initialization:
+ /// depends on output streams, but
+ /// needs to come before others so we
+ /// can use tracing in other
+ /// ParamContext init code
+ StatsInitPhase = 2, ///< Stats output initialization
+ DefaultInitPhase = 3 ///< Everything else
+ };
+
+ /// Records the initialization phase for this ParamContext.
+ InitPhase initPhase;
+
+ /// Constructor.
+ /// @param _iniSection Name of .ini section corresponding to this context.
+ /// @param _initPhase Initialization phase (see InitPhase).
+ ParamContext(const std::string &_iniSection,
+ InitPhase _initPhase = DefaultInitPhase);
+
+ virtual ~ParamContext() {}
+
+ // add a parameter to the context... called from the parameter
+ // object's constructor (see BaseParam::BaseParam())
+ void addParam(BaseParam *);
+
+ // call parse() on all params in this context to convert string
+ // representations to parameter values
+ virtual void parseParams(IniFile &iniFile);
+
+ // Check parameter values for validity & consistency. Default
+ // implementation is no-op; derive subclass & override to add
+ // actual functionality here
+ virtual void checkParams();
+
+ // Clean up at end of execution: close file descriptors, etc.
+ // Default implementation is no-op; derive subclass & override to
+ // add actual functionality here
+ virtual void cleanup();
+
+ // dump parameter descriptions
+ void describeParams(std::ostream &);
+
+ // Display the parameters & values used
+ void showParams(std::ostream &);
+
+ // print context information for parameter error
+ virtual void printErrorProlog(std::ostream &);
+
+ // generate the name for this instance of this context (used as a
+ // prefix to create unique names in resolveSimObject()
+ virtual const std::string &getInstanceName() { return iniSection; }
+
+ // Parse all parameters registered with all ParamContext objects.
+ static void parseAllContexts(IniFile &iniFile);
+
+ // Check all parameters registered with all ParamContext objects.
+ // (calls checkParams() on each)
+ static void checkAllContexts();
+
+ // Print all parameter values on indicated ostream.
+ static void showAllContexts(std::ostream &os);
+
+ // Clean up all registered ParamContext objects. (calls cleanup()
+ // on each)
+ static void cleanupAllContexts();
+
+ // print descriptions of all parameters registered with all
+ // ParamContext objects
+ static void describeAllContexts(std::ostream &os);
+};
+
+
+//
+// Base class for all parameter objects
+//
+class BaseParam
+{
+ public:
+
+ ParamContext *context;
+ std::string name;
+ std::string description; // text description for help message
+ bool wasSet; // true if parameter was set by user
+ bool hasDefault; // true if parameter has default value
+
+ BaseParam(ParamContext *_context, const std::string &_name,
+ const std::string &_description, bool _hasDefault)
+ : context(_context), name(_name), description(_description),
+ wasSet(false), hasDefault(_hasDefault)
+ {
+ context->addParam(this);
+ }
+
+ virtual ~BaseParam() {}
+
+ // a parameter is valid only if its value was set by the user or
+ // it has a default value
+ bool isValid() const
+ {
+ return (wasSet || hasDefault);
+ }
+
+ // set value by parsing string
+ virtual void parse(const std::string &s) = 0;
+
+ // display value to stream
+ virtual void showValue(std::ostream &) const = 0;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const = 0;
+
+ // signal parse or usage error
+ virtual void die(const std::string &err) const;
+};
+
+//
+// Template classes to specialize parameters to specific types.
+//
+// Param<T> is for single-valued (scalar) parameters of type T.
+// VectorParam<T> is for multi-valued (vector) parameters of type T.
+// These are specified in the .ini file as a space-delimited list of
+// arguments.
+//
+template <class T>
+class Param : public BaseParam
+{
+ protected:
+
+ T value;
+
+ public:
+
+ // Param with default value: set value to default
+ Param(ParamContext *context,
+ const std::string &name, const std::string &description, T dfltValue)
+ : BaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ Param(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : BaseParam(context, name, description, false)
+ {
+ }
+
+ virtual ~Param() {}
+
+ operator T&()
+ {
+ // if we attempt to reference an invalid parameter (i.e., one
+ // with no default value that was not set by the user), die.
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+
+//
+// Template class for vector-valued parameters (lists)
+//
+template <class T>
+class VectorParam : public BaseParam
+{
+ protected:
+
+ std::vector<T> value;
+
+ public:
+
+ typedef typename std::vector<T>::size_type size_type;
+
+ // Param with default value: set value to default
+ VectorParam(ParamContext *context, const std::string &name,
+ const std::string &description,
+ const std::vector<T> &dfltValue)
+ : BaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ VectorParam(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : BaseParam(context, name, description, false)
+ {
+ }
+
+ virtual ~VectorParam() {}
+
+ // basic vector access methods
+ size_type size() const
+ {
+ if (!isValid())
+ die("not found");
+ return value.size();
+ }
+
+ const T &operator[](size_type n) const
+ {
+ if (!isValid())
+ die("not found");
+ return value[n];
+ }
+
+ // return reference to value vector
+ operator std::vector<T>&()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+//
+// Specialization of Param<int> and VectorParam<int> to handle
+// enumerated types is done in two ways, using SimpleEnumParam and
+// MappedEnumParam (and their vector counterparts,
+// SimpleEnumVectorParam and MappedEnumVectorParam). SimpleEnumParam
+// takes an array of strings and maps them to integers based on array
+// index. MappedEnumParam takes an array of string-to-int mappings,
+// allowing for mapping strings to non-contiguous integer values, or
+// mapping multiple strings to the same integer value.
+//
+// Both SimpleEnumParam and MappedEnumParam are implemented using a
+// single template class, EnumParam<Map>, which takes the type of the map
+// as a parameter (const char * or EnumParamMap). Similarly,
+// SimpleEnumVectorParam and MappedEnumVectorParam are both
+// implemented using EnumVectorParam<Map>.
+//
+template <class Map>
+class EnumParam : public Param<int>
+{
+ const int num_values;
+ const Map *map;
+
+ public:
+
+ // Param with default value: set value to default
+ EnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values,
+ int dfltValue)
+ : Param<int>(context, name, description, dfltValue),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ EnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values)
+ : Param<int>(context, name, description),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ virtual ~EnumParam() {}
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+//
+// Vector counterpart to SimpleEnumParam
+//
+template <class Map>
+class EnumVectorParam : public VectorParam<int>
+{
+ const int num_values;
+ const Map *map;
+
+ public:
+
+ // Param with default value: set value to default
+ EnumVectorParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values,
+ std::vector<int> &dfltValue)
+ : VectorParam<int>(context, name, description, dfltValue),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ EnumVectorParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values)
+ : VectorParam<int>(context, name, description),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ virtual ~EnumVectorParam() {}
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class SimpleEnumParam : public EnumParam<const char *>
+{
+ public:
+
+ SimpleEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const char **_map, int _num_values,
+ ENUM dfltValue)
+ : EnumParam<const char *>(context, name, description,
+ _map, _num_values, (int)dfltValue)
+ {
+ }
+
+ SimpleEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const char **_map, int _num_values)
+ : EnumParam<const char *>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ operator ENUM() const
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value;
+ }
+};
+
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class SimpleEnumVectorParam : public EnumVectorParam<const char *>
+{
+ public:
+
+ // skip default value constructor: too much pain to convert
+ // vector<ENUM> initializer to vector<int>
+
+
+ SimpleEnumVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ const char **_map, int _num_values)
+ : EnumVectorParam<const char *>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ ENUM operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[n];
+ }
+};
+
+
+//
+// Handle enums via string-to-int map (see comment above).
+//
+
+// An array of string-to-int mappings must be supplied using the
+// following type.
+typedef struct {
+ const char *name;
+ int value;
+} EnumParamMap;
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class MappedEnumParam : public EnumParam<EnumParamMap>
+{
+ public:
+
+ MappedEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const EnumParamMap *_map, int _num_values,
+ ENUM dfltValue)
+ : EnumParam<EnumParamMap>(context, name, description,
+ _map, _num_values, (int)dfltValue)
+ {
+ }
+
+ MappedEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const EnumParamMap *_map, int _num_values)
+ : EnumParam<EnumParamMap>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ operator ENUM()
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[this->n];
+ }
+};
+
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class MappedEnumVectorParam : public EnumVectorParam<EnumParamMap>
+{
+ public:
+
+ // skip default value constructor: too much pain to convert
+ // vector<ENUM> initializer to vector<int>
+
+
+ MappedEnumVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ const EnumParamMap *_map, int _num_values)
+ : EnumVectorParam<EnumParamMap>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ ENUM operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[n];
+ }
+};
+
+
+//
+// Parameters that point to other simulation objects (e.g. caches,
+// busses, etc.) are handled by specializing SimObjectBaseParam to the
+// specific subtype. The main purpose of SimObjectBaseParam is to
+// provide a place to stick several helper functions common to all
+// SimObject-derived parameters.
+//
+class SimObjectBaseParam : public BaseParam
+{
+ public:
+
+ SimObjectBaseParam(ParamContext *context, const std::string &name,
+ const std::string &description, bool hasDefault)
+ : BaseParam(context, name, description, hasDefault)
+ {
+ }
+
+ virtual ~SimObjectBaseParam() {}
+
+ // helper function for SimObjectParam<T>::showValue()
+ void showValue(std::ostream &os, SimObject *obj) const;
+
+ // helper function for SimObjectParam<T>::parse()
+ void parse(const std::string &s, SimObject *&value);
+
+ // helper function for SimObjectParam<T>::parse()
+ void parse(const std::string &s, std::vector<SimObject *>&value_vec);
+};
+
+
+//
+// Parameter to a specific type of SimObject. Note that T must be a
+// pointer to a class derived from SimObject (e.g., <CPU *>).
+//
+
+template <class T> class SimObjectParam;
+
+template <class T>
+class SimObjectParam<T *> : public SimObjectBaseParam
+{
+ protected:
+
+ T *value;
+
+ public:
+
+ // initialization w/o default
+ SimObjectParam(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : SimObjectBaseParam(context, name, description, false)
+ {
+ }
+
+ // initialization wit=h default
+ SimObjectParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ T *dfltValue)
+ : SimObjectBaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ virtual ~SimObjectParam() {}
+
+ // convert to pointer
+ operator T*()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ T *operator->() const
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const
+ {
+ SimObjectBaseParam::showValue(os, value);
+ }
+
+ // display type to stream: see REGISTER_SIM_OBJECT macro in
+ // sim_object.hh for declaration
+ virtual void showType(std::ostream &os) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s)
+ {
+ SimObject *so_ptr;
+ // first parse to generic SimObject *
+ SimObjectBaseParam::parse(s, so_ptr);
+ // now dynamic_cast to specific derived type
+ value = dynamic_cast<T *>(so_ptr);
+ // check for failure of dynamic_cast
+ if (value == NULL && so_ptr != NULL)
+ die("not of appropriate type");
+ }
+};
+
+
+//
+// Vector counterpart to SimObjectParam<T>
+//
+
+template <class T> class SimObjectVectorParam;
+
+template <class T>
+class SimObjectVectorParam<T *> : public SimObjectBaseParam
+{
+ protected:
+
+ std::vector<T *> value;
+
+ public:
+
+ typedef typename std::vector<T *>::size_type size_type;
+
+ SimObjectVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description)
+ : SimObjectBaseParam(context, name, description, false)
+ {
+ }
+
+ SimObjectVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ std::vector<T *> dfltValue)
+ : SimObjectBaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ virtual ~SimObjectVectorParam() {}
+
+ // basic vector access methods
+ size_type size() const
+ {
+ if (!isValid())
+ die("not found");
+ return value.size();
+ }
+
+ T *&operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return value[n];
+ }
+
+ // return reference to value vector
+ operator std::vector<T *>&()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const
+ {
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0)
+ os << " ";
+ SimObjectBaseParam::showValue(os, value[i]);
+ }
+ }
+
+ // display type to stream: see
+ virtual void showType(std::ostream &os) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s)
+ {
+ std::vector<SimObject *> so_ptr_vec;
+ // first parse to generic SimObject * vector (from SimObjectBaseParam)
+ SimObjectBaseParam::parse(s, so_ptr_vec);
+
+ value.resize(so_ptr_vec.size());
+
+ for (int i = 0; i < so_ptr_vec.size(); ++i) {
+ // now dynamic_cast to specific derived type
+ value[i] = dynamic_cast<T *>(so_ptr_vec[i]);
+ // check for failure of dynamic_cast
+ if (value[i] == NULL && so_ptr_vec[i] != NULL)
+ die("not of appropriate type");
+ }
+ }
+};
+
+//
+// Macro to define showType() methods for SimObjectParam &
+// SimObjectVectorParam. Can't do this automatically as it requires a
+// string name for the type, which you can't get from a template
+// argument. For concrete derived SimObject types, this macro is
+// automatically invoked by REGISTER_SIM_OBJECT() (see sim_object.hh).
+//
+#define DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) \
+template<> \
+void \
+SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << CLASS_NAME; \
+} \
+ \
+template<> \
+void \
+SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << "vector of " << CLASS_NAME; \
+}
+
+
+//
+// Declarations for low-level parsing & displaying functions. These
+// are used internally, but should not be used directly by clients of
+// the parameter mechanism, but are declared here so they can be
+// shared with the serialization code (see sim/serialize.cc).
+template <class T> bool parseParam(const std::string &str, T &data);
+template <class T> void showParam(std::ostream &os, const T &data);
+
+#endif // _SIM_PARAM_HH_
diff --git a/src/sim/process.cc b/src/sim/process.cc
new file mode 100644
index 000000000..46ccd2596
--- /dev/null
+++ b/src/sim/process.cc
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
+ * Ali Saidi
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <string>
+
+#include "base/intmath.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/thread_context.hh"
+#include "mem/page_table.hh"
+#include "mem/physical.hh"
+#include "mem/translating_port.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/stats.hh"
+#include "sim/syscall_emul.hh"
+#include "sim/system.hh"
+
+#include "arch/isa_specific.hh"
+#if THE_ISA == ALPHA_ISA
+#include "arch/alpha/linux/process.hh"
+#include "arch/alpha/tru64/process.hh"
+#elif THE_ISA == SPARC_ISA
+#include "arch/sparc/linux/process.hh"
+#include "arch/sparc/solaris/process.hh"
+#elif THE_ISA == MIPS_ISA
+#include "arch/mips/linux/process.hh"
+#else
+#error "THE_ISA not set"
+#endif
+
+
+using namespace std;
+using namespace TheISA;
+
+//
+// The purpose of this code is to fake the loader & syscall mechanism
+// when there's no OS: thus there's no resone to use it in FULL_SYSTEM
+// mode when we do have an OS
+//
+#if FULL_SYSTEM
+#error "process.cc not compatible with FULL_SYSTEM"
+#endif
+
+// current number of allocated processes
+int num_processes = 0;
+
+Process::Process(const string &nm,
+ System *_system,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd)
+ : SimObject(nm), system(_system)
+{
+ // initialize first 3 fds (stdin, stdout, stderr)
+ fd_map[STDIN_FILENO] = stdin_fd;
+ fd_map[STDOUT_FILENO] = stdout_fd;
+ fd_map[STDERR_FILENO] = stderr_fd;
+
+ // mark remaining fds as free
+ for (int i = 3; i <= MAX_FD; ++i) {
+ fd_map[i] = -1;
+ }
+
+ mmap_start = mmap_end = 0;
+ nxm_start = nxm_end = 0;
+ pTable = new PageTable(system);
+ // other parameters will be initialized when the program is loaded
+}
+
+
+void
+Process::regStats()
+{
+ using namespace Stats;
+
+ num_syscalls
+ .name(name() + ".PROG:num_syscalls")
+ .desc("Number of system calls")
+ ;
+}
+
+//
+// static helper functions
+//
+int
+Process::openInputFile(const string &filename)
+{
+ int fd = open(filename.c_str(), O_RDONLY);
+
+ if (fd == -1) {
+ perror(NULL);
+ cerr << "unable to open \"" << filename << "\" for reading\n";
+ fatal("can't open input file");
+ }
+
+ return fd;
+}
+
+
+int
+Process::openOutputFile(const string &filename)
+{
+ int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
+
+ if (fd == -1) {
+ perror(NULL);
+ cerr << "unable to open \"" << filename << "\" for writing\n";
+ fatal("can't open output file");
+ }
+
+ return fd;
+}
+
+
+int
+Process::registerThreadContext(ThreadContext *tc)
+{
+ // add to list
+ int myIndex = threadContexts.size();
+ threadContexts.push_back(tc);
+
+ // return CPU number to caller
+ return myIndex;
+}
+
+void
+Process::startup()
+{
+ if (threadContexts.empty())
+ fatal("Process %s is not associated with any CPUs!\n", name());
+
+ // first thread context for this process... initialize & enable
+ ThreadContext *tc = threadContexts[0];
+
+ // mark this context as active so it will start ticking.
+ tc->activate(0);
+
+ Port *mem_port;
+ mem_port = system->physmem->getPort("functional");
+ initVirtMem = new TranslatingPort("process init port", pTable, true);
+ mem_port->setPeer(initVirtMem);
+ initVirtMem->setPeer(mem_port);
+}
+
+void
+Process::replaceThreadContext(ThreadContext *tc, int tcIndex)
+{
+ if (tcIndex >= threadContexts.size()) {
+ panic("replaceThreadContext: bad tcIndex, %d >= %d\n",
+ tcIndex, threadContexts.size());
+ }
+
+ threadContexts[tcIndex] = tc;
+}
+
+// map simulator fd sim_fd to target fd tgt_fd
+void
+Process::dup_fd(int sim_fd, int tgt_fd)
+{
+ if (tgt_fd < 0 || tgt_fd > MAX_FD)
+ panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
+
+ fd_map[tgt_fd] = sim_fd;
+}
+
+
+// generate new target fd for sim_fd
+int
+Process::alloc_fd(int sim_fd)
+{
+ // in case open() returns an error, don't allocate a new fd
+ if (sim_fd == -1)
+ return -1;
+
+ // find first free target fd
+ for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) {
+ if (fd_map[free_fd] == -1) {
+ fd_map[free_fd] = sim_fd;
+ return free_fd;
+ }
+ }
+
+ panic("Process::alloc_fd: out of file descriptors!");
+}
+
+
+// free target fd (e.g., after close)
+void
+Process::free_fd(int tgt_fd)
+{
+ if (fd_map[tgt_fd] == -1)
+ warn("Process::free_fd: request to free unused fd %d", tgt_fd);
+
+ fd_map[tgt_fd] = -1;
+}
+
+
+// look up simulator fd for given target fd
+int
+Process::sim_fd(int tgt_fd)
+{
+ if (tgt_fd > MAX_FD)
+ return -1;
+
+ return fd_map[tgt_fd];
+}
+
+
+
+//
+// need to declare these here since there is no concrete Process type
+// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call,
+// which is where these get declared for concrete types).
+//
+DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process)
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// LiveProcess member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+
+void
+copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
+ TranslatingPort* memPort)
+{
+ Addr data_ptr_swap;
+ for (int i = 0; i < strings.size(); ++i) {
+ data_ptr_swap = htog(data_ptr);
+ memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr));
+ memPort->writeString(data_ptr, strings[i].c_str());
+ array_ptr += sizeof(Addr);
+ data_ptr += strings[i].size() + 1;
+ }
+ // add NULL terminator
+ data_ptr = 0;
+
+ memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr));
+}
+
+LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile,
+ System *_system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ vector<string> &_argv, vector<string> &_envp,
+ uint64_t _uid, uint64_t _euid,
+ uint64_t _gid, uint64_t _egid,
+ uint64_t _pid, uint64_t _ppid)
+ : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd),
+ objFile(_objFile), argv(_argv), envp(_envp)
+{
+ __uid = _uid;
+ __euid = _euid;
+ __gid = _gid;
+ __egid = _egid;
+ __pid = _pid;
+ __ppid = _ppid;
+
+ prog_fname = argv[0];
+
+ // load up symbols, if any... these may be used for debugging or
+ // profiling.
+ if (!debugSymbolTable) {
+ debugSymbolTable = new SymbolTable();
+ if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
+ !objFile->loadLocalSymbols(debugSymbolTable)) {
+ // didn't load any symbols
+ delete debugSymbolTable;
+ debugSymbolTable = NULL;
+ }
+ }
+}
+
+void
+LiveProcess::argsInit(int intSize, int pageSize)
+{
+ Process::startup();
+
+ // load object file into target memory
+ objFile->loadSections(initVirtMem);
+
+ // Calculate how much space we need for arg & env arrays.
+ int argv_array_size = intSize * (argv.size() + 1);
+ int envp_array_size = intSize * (envp.size() + 1);
+ int arg_data_size = 0;
+ for (int i = 0; i < argv.size(); ++i) {
+ arg_data_size += argv[i].size() + 1;
+ }
+ int env_data_size = 0;
+ for (int i = 0; i < envp.size(); ++i) {
+ env_data_size += envp[i].size() + 1;
+ }
+
+ int space_needed =
+ argv_array_size + envp_array_size + arg_data_size + env_data_size;
+ if (space_needed < 32*1024)
+ space_needed = 32*1024;
+
+ // set bottom of stack
+ stack_min = stack_base - space_needed;
+ // align it
+ stack_min = roundDown(stack_min, pageSize);
+ stack_size = stack_base - stack_min;
+ // map memory
+ pTable->allocate(stack_min, roundUp(stack_size, pageSize));
+
+ // map out initial stack contents
+ Addr argv_array_base = stack_min + intSize; // room for argc
+ Addr envp_array_base = argv_array_base + argv_array_size;
+ Addr arg_data_base = envp_array_base + envp_array_size;
+ Addr env_data_base = arg_data_base + arg_data_size;
+
+ // write contents to stack
+ uint64_t argc = argv.size();
+ if (intSize == 8)
+ argc = htog((uint64_t)argc);
+ else if (intSize == 4)
+ argc = htog((uint32_t)argc);
+ else
+ panic("Unknown int size");
+
+ initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize);
+
+ copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
+ copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
+
+ threadContexts[0]->setIntReg(ArgumentReg0, argc);
+ threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
+ threadContexts[0]->setIntReg(StackPointerReg, stack_min);
+
+ Addr prog_entry = objFile->entryPoint();
+ threadContexts[0]->setPC(prog_entry);
+ threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+
+#if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc
+ threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+#endif
+
+ num_processes++;
+}
+
+void
+LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
+{
+ num_syscalls++;
+
+ SyscallDesc *desc = getDesc(callnum);
+ if (desc == NULL)
+ fatal("Syscall %d out of range", callnum);
+
+ desc->doSyscall(callnum, this, tc);
+}
+
+LiveProcess *
+LiveProcess::create(const std::string &nm, System *system, int stdin_fd,
+ int stdout_fd, int stderr_fd, std::string executable,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp,
+ uint64_t _uid, uint64_t _euid,
+ uint64_t _gid, uint64_t _egid,
+ uint64_t _pid, uint64_t _ppid)
+{
+ LiveProcess *process = NULL;
+
+ ObjectFile *objFile = createObjectFile(executable);
+ if (objFile == NULL) {
+ fatal("Can't load object file %s", executable);
+ }
+
+#if THE_ISA == ALPHA_ISA
+ if (objFile->getArch() != ObjectFile::Alpha)
+ fatal("Object file architecture does not match compiled ISA (Alpha).");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Tru64:
+ process = new AlphaTru64Process(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp,
+ _uid, _euid, _gid, _egid, _pid, _ppid);
+ break;
+
+ case ObjectFile::Linux:
+ process = new AlphaLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp,
+ _uid, _euid, _gid, _egid, _pid, _ppid);
+ break;
+
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+#elif THE_ISA == SPARC_ISA
+ if (objFile->getArch() != ObjectFile::SPARC)
+ fatal("Object file architecture does not match compiled ISA (SPARC).");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Linux:
+ process = new SparcLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp,
+ _uid, _euid, _gid, _egid, _pid, _ppid);
+ break;
+
+
+ case ObjectFile::Solaris:
+ process = new SparcSolarisProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp,
+ _uid, _euid, _gid, _egid, _pid, _ppid);
+ break;
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+#elif THE_ISA == MIPS_ISA
+ if (objFile->getArch() != ObjectFile::Mips)
+ fatal("Object file architecture does not match compiled ISA (MIPS).");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Linux:
+ process = new MipsLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp,
+ _uid, _euid, _gid, _egid, _pid, _ppid);
+ break;
+
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+#else
+#error "THE_ISA not set"
+#endif
+
+
+ if (process == NULL)
+ fatal("Unknown error creating process object.");
+ return process;
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+ VectorParam<string> cmd;
+ Param<string> executable;
+ Param<string> input;
+ Param<string> output;
+ VectorParam<string> env;
+ SimObjectParam<System *> system;
+ Param<uint64_t> uid;
+ Param<uint64_t> euid;
+ Param<uint64_t> gid;
+ Param<uint64_t> egid;
+ Param<uint64_t> pid;
+ Param<uint64_t> ppid;
+
+END_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+ INIT_PARAM(cmd, "command line (executable plus arguments)"),
+ INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
+ INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
+ INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
+ INIT_PARAM(env, "environment settings"),
+ INIT_PARAM(system, "system"),
+ INIT_PARAM(uid, "user id"),
+ INIT_PARAM(euid, "effective user id"),
+ INIT_PARAM(gid, "group id"),
+ INIT_PARAM(egid, "effective group id"),
+ INIT_PARAM(pid, "process id"),
+ INIT_PARAM(ppid, "parent process id")
+
+END_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+CREATE_SIM_OBJECT(LiveProcess)
+{
+ string in = input;
+ string out = output;
+
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd, stdout_fd, stderr_fd;
+
+ if (in == "stdin" || in == "cin")
+ stdin_fd = STDIN_FILENO;
+ else
+ stdin_fd = Process::openInputFile(input);
+
+ if (out == "stdout" || out == "cout")
+ stdout_fd = STDOUT_FILENO;
+ else if (out == "stderr" || out == "cerr")
+ stdout_fd = STDERR_FILENO;
+ else
+ stdout_fd = Process::openOutputFile(out);
+
+ stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+
+ return LiveProcess::create(getInstanceName(), system,
+ stdin_fd, stdout_fd, stderr_fd,
+ (string)executable == "" ? cmd[0] : executable,
+ cmd, env,
+ uid, euid, gid, egid, pid, ppid);
+}
+
+
+REGISTER_SIM_OBJECT("LiveProcess", LiveProcess)
diff --git a/src/sim/process.hh b/src/sim/process.hh
new file mode 100644
index 000000000..b2777170f
--- /dev/null
+++ b/src/sim/process.hh
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
+ */
+
+#ifndef __PROCESS_HH__
+#define __PROCESS_HH__
+
+//
+// The purpose of this code is to fake the loader & syscall mechanism
+// when there's no OS: thus there's no reason to use it in FULL_SYSTEM
+// mode when we do have an OS.
+//
+#include "config/full_system.hh"
+
+#if !FULL_SYSTEM
+
+#include <vector>
+
+#include "base/statistics.hh"
+#include "sim/sim_object.hh"
+
+class ThreadContext;
+class SyscallDesc;
+class PageTable;
+class TranslatingPort;
+class System;
+
+void
+copyStringArray(std::vector<std::string> &strings, Addr array_ptr,
+ Addr data_ptr, TranslatingPort* memPort);
+
+class Process : public SimObject
+{
+ public:
+
+ /// Pointer to object representing the system this process is
+ /// running on.
+ System *system;
+
+ // have we initialized a thread context from this process? If
+ // yes, subsequent contexts are assumed to be for dynamically
+ // created threads and are not initialized.
+ bool initialContextLoaded;
+
+ // thread contexts associated with this process
+ std::vector<ThreadContext *> threadContexts;
+
+ // number of CPUs (esxec contexts, really) assigned to this process.
+ unsigned int numCpus() { return threadContexts.size(); }
+
+ // record of blocked context
+ struct WaitRec
+ {
+ Addr waitChan;
+ ThreadContext *waitingContext;
+
+ WaitRec(Addr chan, ThreadContext *ctx)
+ : waitChan(chan), waitingContext(ctx)
+ { }
+ };
+
+ // list of all blocked contexts
+ std::list<WaitRec> waitList;
+
+ Addr brk_point; // top of the data segment
+
+ Addr stack_base; // stack segment base (highest address)
+ unsigned stack_size; // initial stack size
+ Addr stack_min; // lowest address accessed on the stack
+
+ // addr to use for next stack region (for multithreaded apps)
+ Addr next_thread_stack_base;
+
+ // Base of region for mmaps (when user doesn't specify an address).
+ Addr mmap_start;
+ Addr mmap_end;
+
+ // Base of region for nxm data
+ Addr nxm_start;
+ Addr nxm_end;
+
+ std::string prog_fname; // file name
+
+ Stats::Scalar<> num_syscalls; // number of syscalls executed
+
+
+ protected:
+ // constructor
+ Process(const std::string &nm,
+ System *_system,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd);
+
+ // post initialization startup
+ virtual void startup();
+
+ protected:
+ /// Memory object for initialization (image loading)
+ TranslatingPort *initVirtMem;
+
+ public:
+ PageTable *pTable;
+
+ private:
+ // file descriptor remapping support
+ static const int MAX_FD = 256; // max legal fd value
+ int fd_map[MAX_FD+1];
+
+ public:
+ // static helper functions to generate file descriptors for constructor
+ static int openInputFile(const std::string &filename);
+ static int openOutputFile(const std::string &filename);
+
+ // override of virtual SimObject method: register statistics
+ virtual void regStats();
+
+ // register a thread context for this process.
+ // returns tc's cpu number (index into threadContexts[])
+ int registerThreadContext(ThreadContext *tc);
+
+
+ void replaceThreadContext(ThreadContext *tc, int tcIndex);
+
+ // map simulator fd sim_fd to target fd tgt_fd
+ void dup_fd(int sim_fd, int tgt_fd);
+
+ // generate new target fd for sim_fd
+ int alloc_fd(int sim_fd);
+
+ // free target fd (e.g., after close)
+ void free_fd(int tgt_fd);
+
+ // look up simulator fd for given target fd
+ int sim_fd(int tgt_fd);
+
+ virtual void syscall(int64_t callnum, ThreadContext *tc) = 0;
+};
+
+//
+// "Live" process with system calls redirected to host system
+//
+class ObjectFile;
+class LiveProcess : public Process
+{
+ protected:
+ ObjectFile *objFile;
+ std::vector<std::string> argv;
+ std::vector<std::string> envp;
+
+ LiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp,
+ uint64_t _uid, uint64_t _euid,
+ uint64_t _gid, uint64_t _egid,
+ uint64_t _pid, uint64_t _ppid);
+
+ virtual void argsInit(int intSize, int pageSize);
+
+ // Id of the owner of the process
+ uint64_t __uid;
+ uint64_t __euid;
+ uint64_t __gid;
+ uint64_t __egid;
+
+ // pid of the process and it's parent
+ uint64_t __pid;
+ uint64_t __ppid;
+
+ public:
+
+ inline uint64_t uid() {return __uid;}
+ inline uint64_t euid() {return __euid;}
+ inline uint64_t gid() {return __gid;}
+ inline uint64_t egid() {return __egid;}
+ inline uint64_t pid() {return __pid;}
+ inline uint64_t ppid() {return __ppid;}
+
+ virtual void syscall(int64_t callnum, ThreadContext *tc);
+
+ virtual SyscallDesc* getDesc(int callnum) = 0;
+
+ // this function is used to create the LiveProcess object, since
+ // we can't tell which subclass of LiveProcess to use until we
+ // open and look at the object file.
+ static LiveProcess *create(const std::string &nm,
+ System *_system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::string executable,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp,
+ uint64_t _uid, uint64_t _euid,
+ uint64_t _gid, uint64_t _egid,
+ uint64_t _pid, uint64_t _ppid);
+};
+
+
+#endif // !FULL_SYSTEM
+
+#endif // __PROCESS_HH__
diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc
new file mode 100644
index 000000000..aae2f6021
--- /dev/null
+++ b/src/sim/pseudo_inst.cc
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "sim/pseudo_inst.hh"
+#include "arch/vtophys.hh"
+#include "base/annotate.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/quiesce_event.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/param.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_exit.hh"
+#include "sim/stat_control.hh"
+#include "sim/stats.hh"
+#include "sim/system.hh"
+#include "sim/debug.hh"
+#include "sim/vptr.hh"
+
+using namespace std;
+
+using namespace Stats;
+using namespace TheISA;
+
+namespace AlphaPseudo
+{
+ bool doStatisticsInsts;
+ bool doCheckpointInsts;
+ bool doQuiesce;
+
+ void
+ arm(ThreadContext *tc)
+ {
+ if (tc->getKernelStats())
+ tc->getKernelStats()->arm();
+ }
+
+ void
+ quiesce(ThreadContext *tc)
+ {
+ if (!doQuiesce)
+ return;
+
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
+ }
+
+ void
+ quiesceNs(ThreadContext *tc, uint64_t ns)
+ {
+ if (!doQuiesce || ns == 0)
+ return;
+
+ EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
+
+ if (quiesceEvent->scheduled())
+ quiesceEvent->reschedule(curTick + Clock::Int::ns * ns);
+ else
+ quiesceEvent->schedule(curTick + Clock::Int::ns * ns);
+
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
+ }
+
+ void
+ quiesceCycles(ThreadContext *tc, uint64_t cycles)
+ {
+ if (!doQuiesce || cycles == 0)
+ return;
+
+ EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
+
+ if (quiesceEvent->scheduled())
+ quiesceEvent->reschedule(curTick +
+ tc->getCpuPtr()->cycles(cycles));
+ else
+ quiesceEvent->schedule(curTick +
+ tc->getCpuPtr()->cycles(cycles));
+
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
+ }
+
+ uint64_t
+ quiesceTime(ThreadContext *tc)
+ {
+ return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns;
+ }
+
+ void
+ ivlb(ThreadContext *tc)
+ {
+ if (tc->getKernelStats())
+ tc->getKernelStats()->ivlb();
+ }
+
+ void
+ ivle(ThreadContext *tc)
+ {
+ }
+
+ void
+ m5exit_old(ThreadContext *tc)
+ {
+ exitSimLoop(curTick, "m5_exit_old instruction encountered");
+ }
+
+ void
+ m5exit(ThreadContext *tc, Tick delay)
+ {
+ Tick when = curTick + delay * Clock::Int::ns;
+ exitSimLoop(when, "m5_exit instruction encountered");
+ }
+
+ void
+ loadsymbol(ExecContext *xc)
+ {
+ const string &filename = xc->getCpuPtr()->system->params()->symbolfile;
+ if (filename.empty()) {
+ return;
+ }
+
+ std::string buffer;
+ ifstream file(filename.c_str());
+
+ if (!file)
+ fatal("file error: Can't open symbol table file %s\n", filename);
+
+ while (!file.eof()) {
+ getline(file, buffer);
+
+ if (buffer.empty())
+ continue;
+
+ int idx = buffer.find(' ');
+ if (idx == string::npos)
+ continue;
+
+ string address = "0x" + buffer.substr(0, idx);
+ eat_white(address);
+ if (address.empty())
+ continue;
+
+ // Skip over letter and space
+ string symbol = buffer.substr(idx + 3);
+ eat_white(symbol);
+ if (symbol.empty())
+ continue;
+
+ Addr addr;
+ if (!to_number(address, addr))
+ continue;
+
+ if (!xc->getSystemPtr()->kernelSymtab->insert(addr, symbol))
+ continue;
+
+
+ DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
+ }
+ file.close();
+ }
+
+ void
+ resetstats(ThreadContext *tc, Tick delay, Tick period)
+ {
+ if (!doStatisticsInsts)
+ return;
+
+
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
+
+ using namespace Stats;
+ SetupEvent(Reset, when, repeat);
+ }
+
+ void
+ dumpstats(ThreadContext *tc, Tick delay, Tick period)
+ {
+ if (!doStatisticsInsts)
+ return;
+
+
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
+
+ using namespace Stats;
+ SetupEvent(Dump, when, repeat);
+ }
+
+ void
+ addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
+ {
+ char symb[100];
+ CopyStringOut(tc, symb, symbolAddr, 100);
+ std::string symbol(symb);
+
+ DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
+
+ tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
+ }
+
+ void
+ anBegin(ThreadContext *tc, uint64_t cur)
+ {
+ Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur &
+ 0xFFFFFFFF, 0,0);
+ }
+
+ void
+ anWait(ThreadContext *tc, uint64_t cur, uint64_t wait)
+ {
+ Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur &
+ 0xFFFFFFFF, wait >> 32, wait & 0xFFFFFFFF);
+ }
+
+
+ void
+ dumpresetstats(ThreadContext *tc, Tick delay, Tick period)
+ {
+ if (!doStatisticsInsts)
+ return;
+
+
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
+
+ using namespace Stats;
+ SetupEvent(Dump|Reset, when, repeat);
+ }
+
+ void
+ m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
+ {
+ if (!doCheckpointInsts)
+ return;
+ exitSimLoop("checkpoint");
+ }
+
+ uint64_t
+ readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
+ {
+ const string &file = tc->getCpuPtr()->system->params()->readfile;
+ if (file.empty()) {
+ return ULL(0);
+ }
+
+ uint64_t result = 0;
+
+ int fd = ::open(file.c_str(), O_RDONLY, 0);
+ if (fd < 0)
+ panic("could not open file %s\n", file);
+
+ if (::lseek(fd, offset, SEEK_SET) < 0)
+ panic("could not seek: %s", strerror(errno));
+
+ char *buf = new char[len];
+ char *p = buf;
+ while (len > 0) {
+ int bytes = ::read(fd, p, len);
+ if (bytes <= 0)
+ break;
+
+ p += bytes;
+ result += bytes;
+ len -= bytes;
+ }
+
+ close(fd);
+ CopyIn(tc, vaddr, buf, result);
+ delete [] buf;
+ return result;
+ }
+
+ class Context : public ParamContext
+ {
+ public:
+ Context(const string &section) : ParamContext(section) {}
+ void checkParams();
+ };
+
+ Context context("pseudo_inst");
+
+ Param<bool> __quiesce(&context, "quiesce",
+ "enable quiesce instructions",
+ true);
+ Param<bool> __statistics(&context, "statistics",
+ "enable statistics pseudo instructions",
+ true);
+ Param<bool> __checkpoint(&context, "checkpoint",
+ "enable checkpoint pseudo instructions",
+ true);
+
+ void
+ Context::checkParams()
+ {
+ doQuiesce = __quiesce;
+ doStatisticsInsts = __statistics;
+ doCheckpointInsts = __checkpoint;
+ }
+
+ void debugbreak(ThreadContext *tc)
+ {
+ debug_break();
+ }
+
+ void switchcpu(ThreadContext *tc)
+ {
+ exitSimLoop("switchcpu");
+ }
+}
diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh
new file mode 100644
index 000000000..d211de44e
--- /dev/null
+++ b/src/sim/pseudo_inst.hh
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+class ThreadContext;
+
+//We need the "Tick" and "Addr" data types from here
+#include "sim/host.hh"
+
+namespace AlphaPseudo
+{
+ /**
+ * @todo these externs are only here for a hack in fullCPU::takeOver...
+ */
+ extern bool doStatisticsInsts;
+ extern bool doCheckpointInsts;
+ extern bool doQuiesce;
+
+ void arm(ThreadContext *tc);
+ void quiesce(ThreadContext *tc);
+ void quiesceNs(ThreadContext *tc, uint64_t ns);
+ void quiesceCycles(ThreadContext *tc, uint64_t cycles);
+ uint64_t quiesceTime(ThreadContext *tc);
+ void ivlb(ThreadContext *tc);
+ void ivle(ThreadContext *tc);
+ void m5exit(ThreadContext *tc, Tick delay);
+ void m5exit_old(ThreadContext *tc);
+ void loadsymbol(ThreadContext *xc);
+ void resetstats(ThreadContext *tc, Tick delay, Tick period);
+ void dumpstats(ThreadContext *tc, Tick delay, Tick period);
+ void dumpresetstats(ThreadContext *tc, Tick delay, Tick period);
+ void m5checkpoint(ThreadContext *tc, Tick delay, Tick period);
+ uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset);
+ void debugbreak(ThreadContext *tc);
+ void switchcpu(ThreadContext *tc);
+ void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr);
+ void anBegin(ThreadContext *tc, uint64_t cur);
+ void anWait(ThreadContext *tc, uint64_t cur, uint64_t wait);
+}
diff --git a/src/sim/root.cc b/src/sim/root.cc
new file mode 100644
index 000000000..ec5e2f7e2
--- /dev/null
+++ b/src/sim/root.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
+ */
+
+#include <cstring>
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+Tick curTick = 0;
+ostream *outputStream;
+ostream *configStream;
+
+/// The simulated frequency of curTick. (This is only here for a short time)
+Tick ticksPerSecond;
+
+namespace Clock {
+/// The simulated frequency of curTick. (In ticks per second)
+Tick Frequency;
+
+namespace Float {
+double s;
+double ms;
+double us;
+double ns;
+double ps;
+
+double Hz;
+double kHz;
+double MHz;
+double GHZ;
+/* namespace Float */ }
+
+namespace Int {
+Tick s;
+Tick ms;
+Tick us;
+Tick ns;
+Tick ps;
+/* namespace Float */ }
+
+/* namespace Clock */ }
+
+
+// Dummy Object
+class Root : public SimObject
+{
+ private:
+ Tick max_tick;
+ Tick progress_interval;
+
+ public:
+ Root(const std::string &name, Tick maxtick, Tick pi)
+ : SimObject(name), max_tick(maxtick), progress_interval(pi)
+ {}
+
+ virtual void startup();
+};
+
+void
+Root::startup()
+{
+ if (max_tick != 0)
+ exitSimLoop(curTick + max_tick, "reached maximum cycle count");
+
+ if (progress_interval != 0)
+ new ProgressEvent(&mainEventQueue, progress_interval);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root)
+
+ Param<Tick> clock;
+ Param<Tick> max_tick;
+ Param<Tick> progress_interval;
+ Param<string> output_file;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Root)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Root)
+
+ INIT_PARAM(clock, "tick frequency"),
+ INIT_PARAM(max_tick, "maximum simulation time"),
+ INIT_PARAM(progress_interval, "print a progress message"),
+ INIT_PARAM(output_file, "file to dump simulator output to")
+
+END_INIT_SIM_OBJECT_PARAMS(Root)
+
+CREATE_SIM_OBJECT(Root)
+{
+ static bool created = false;
+ if (created)
+ panic("only one root object allowed!");
+
+ created = true;
+
+ outputStream = simout.find(output_file);
+ Root *root = new Root(getInstanceName(), max_tick, progress_interval);
+
+ using namespace Clock;
+ Frequency = clock;
+ Float::s = static_cast<double>(Frequency);
+ Float::ms = Float::s / 1.0e3;
+ Float::us = Float::s / 1.0e6;
+ Float::ns = Float::s / 1.0e9;
+ Float::ps = Float::s / 1.0e12;
+
+ Float::Hz = 1.0 / Float::s;
+ Float::kHz = 1.0 / Float::ms;
+ Float::MHz = 1.0 / Float::us;
+ Float::GHZ = 1.0 / Float::ns;
+
+ Int::s = Frequency;
+ Int::ms = Int::s / 1000;
+ Int::us = Int::ms / 1000;
+ Int::ns = Int::us / 1000;
+ Int::ps = Int::ns / 1000;
+
+ return root;
+}
+
+REGISTER_SIM_OBJECT("Root", Root)
diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc
new file mode 100644
index 000000000..941f0b1c6
--- /dev/null
+++ b/src/sim/serialize.cc
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Erik Hallnor
+ * Steve Reinhardt
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "sim/eventq.hh"
+#include "sim/param.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+
+// For stat reset hack
+#include "sim/stat_control.hh"
+
+using namespace std;
+
+int Serializable::ckptMaxCount = 0;
+int Serializable::ckptCount = 0;
+int Serializable::ckptPrevCount = -1;
+
+void
+Serializable::nameOut(ostream &os)
+{
+ os << "\n[" << name() << "]\n";
+}
+
+void
+Serializable::nameOut(ostream &os, const string &_name)
+{
+ os << "\n[" << _name << "]\n";
+}
+
+template <class T>
+void
+paramOut(ostream &os, const std::string &name, const T &param)
+{
+ os << name << "=";
+ showParam(os, param);
+ os << "\n";
+}
+
+
+template <class T>
+void
+paramIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T &param)
+{
+ std::string str;
+ if (!cp->find(section, name, str) || !parseParam(str, param)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+}
+
+
+template <class T>
+void
+arrayParamOut(ostream &os, const std::string &name,
+ const T *param, int size)
+{
+ os << name << "=";
+ if (size > 0)
+ showParam(os, param[0]);
+ for (int i = 1; i < size; ++i) {
+ os << " ";
+ showParam(os, param[i]);
+ }
+ os << "\n";
+}
+
+
+template <class T>
+void
+arrayParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T *param, int size)
+{
+ std::string str;
+ if (!cp->find(section, name, str)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+
+ // code below stolen from VectorParam<T>::parse().
+ // it would be nice to unify these somehow...
+
+ vector<string> tokens;
+
+ tokenize(tokens, str, ' ');
+
+ // Need this if we were doing a vector
+ // value.resize(tokens.size());
+
+ if (tokens.size() != size) {
+ fatal("Array size mismatch on %s:%s'\n", section, name);
+ }
+
+ for (int i = 0; i < tokens.size(); i++) {
+ // need to parse into local variable to handle vector<bool>,
+ // for which operator[] returns a special reference class
+ // that's not the same as 'bool&', (since it's a packed
+ // vector)
+ T scalar_value;
+ if (!parseParam(tokens[i], scalar_value)) {
+ string err("could not parse \"");
+
+ err += str;
+ err += "\"";
+
+ fatal(err);
+ }
+
+ // assign parsed value to vector
+ param[i] = scalar_value;
+ }
+}
+
+
+void
+objParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, Serializable * &param)
+{
+ if (!cp->findObj(section, name, param)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+}
+
+
+#define INSTANTIATE_PARAM_TEMPLATES(type) \
+template void \
+paramOut(ostream &os, const std::string &name, type const &param); \
+template void \
+paramIn(Checkpoint *cp, const std::string &section, \
+ const std::string &name, type & param); \
+template void \
+arrayParamOut(ostream &os, const std::string &name, \
+ type const *param, int size); \
+template void \
+arrayParamIn(Checkpoint *cp, const std::string &section, \
+ const std::string &name, type *param, int size);
+
+INSTANTIATE_PARAM_TEMPLATES(signed char)
+INSTANTIATE_PARAM_TEMPLATES(unsigned char)
+INSTANTIATE_PARAM_TEMPLATES(signed short)
+INSTANTIATE_PARAM_TEMPLATES(unsigned short)
+INSTANTIATE_PARAM_TEMPLATES(signed int)
+INSTANTIATE_PARAM_TEMPLATES(unsigned int)
+INSTANTIATE_PARAM_TEMPLATES(signed long)
+INSTANTIATE_PARAM_TEMPLATES(unsigned long)
+INSTANTIATE_PARAM_TEMPLATES(signed long long)
+INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
+INSTANTIATE_PARAM_TEMPLATES(bool)
+INSTANTIATE_PARAM_TEMPLATES(string)
+
+
+/////////////////////////////
+
+/// Container for serializing global variables (not associated with
+/// any serialized object).
+class Globals : public Serializable
+{
+ public:
+ const string name() const;
+ void serialize(ostream &os);
+ void unserialize(Checkpoint *cp);
+};
+
+/// The one and only instance of the Globals class.
+Globals globals;
+
+const string
+Globals::name() const
+{
+ return "Globals";
+}
+
+void
+Globals::serialize(ostream &os)
+{
+ nameOut(os);
+ SERIALIZE_SCALAR(curTick);
+
+ nameOut(os, "MainEventQueue");
+ mainEventQueue.serialize(os);
+}
+
+void
+Globals::unserialize(Checkpoint *cp)
+{
+ const string &section = name();
+ UNSERIALIZE_SCALAR(curTick);
+
+ mainEventQueue.unserialize(cp, "MainEventQueue");
+}
+
+void
+Serializable::serializeAll(const std::string &cpt_dir)
+{
+ setCheckpointDir(cpt_dir);
+ string dir = Checkpoint::dir();
+ if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
+ fatal("couldn't mkdir %s\n", dir);
+
+ string cpt_file = dir + Checkpoint::baseFilename;
+ ofstream outstream(cpt_file.c_str());
+ time_t t = time(NULL);
+ outstream << "// checkpoint generated: " << ctime(&t);
+
+ globals.serialize(outstream);
+ SimObject::serializeAll(outstream);
+}
+
+void
+Serializable::unserializeAll(const std::string &cpt_dir)
+{
+ setCheckpointDir(cpt_dir);
+ string dir = Checkpoint::dir();
+ string cpt_file = dir + Checkpoint::baseFilename;
+ string section = "";
+
+ DPRINTFR(Config, "Loading checkpoint dir '%s'\n",
+ dir);
+ Checkpoint *cp = new Checkpoint(dir, section);
+ unserializeGlobals(cp);
+
+ SimObject::unserializeAll(cp);
+}
+
+void
+Serializable::unserializeGlobals(Checkpoint *cp)
+{
+ globals.unserialize(cp);
+}
+
+const char *Checkpoint::baseFilename = "m5.cpt";
+
+static string checkpointDirBase;
+
+void
+setCheckpointDir(const std::string &name)
+{
+ checkpointDirBase = name;
+ if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
+ checkpointDirBase += "/";
+}
+
+string
+Checkpoint::dir()
+{
+ // use csprintf to insert curTick into directory name if it
+ // appears to have a format placeholder in it.
+ return (checkpointDirBase.find("%") != string::npos) ?
+ csprintf(checkpointDirBase, curTick) : checkpointDirBase;
+}
+
+void
+debug_serialize(const std::string &cpt_dir)
+{
+ Serializable::serializeAll(cpt_dir);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SerializableClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SerializableBuilder creation functions.
+// Need to make this a pointer so we can force initialization on the
+// first reference; otherwise, some SerializableClass constructors
+// may be invoked before the classMap constructor.
+map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0;
+
+// SerializableClass constructor: add mapping to classMap
+SerializableClass::SerializableClass(const string &className,
+ CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SerializableClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+Serializable *
+SerializableClass::createObject(Checkpoint *cp,
+ const std::string &section)
+{
+ string className;
+
+ if (!cp->find(section, "type", className)) {
+ fatal("Serializable::create: no 'type' entry in section '%s'.\n",
+ section);
+ }
+
+ CreateFunc createFunc = (*classMap)[className];
+
+ if (createFunc == NULL) {
+ fatal("Serializable::create: no create function for class '%s'.\n",
+ className);
+ }
+
+ Serializable *object = createFunc(cp, section);
+
+ assert(object != NULL);
+
+ return object;
+}
+
+
+Serializable *
+Serializable::create(Checkpoint *cp, const std::string &section)
+{
+ Serializable *object = SerializableClass::createObject(cp, section);
+ object->unserialize(cp, section);
+ return object;
+}
+
+
+Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path)
+ : db(new IniFile), basePath(path), cptDir(cpt_dir)
+{
+ string filename = cpt_dir + "/" + Checkpoint::baseFilename;
+ if (!db->load(filename)) {
+ fatal("Can't load checkpoint file '%s'\n", filename);
+ }
+}
+
+
+bool
+Checkpoint::find(const std::string &section, const std::string &entry,
+ std::string &value)
+{
+ return db->find(section, entry, value);
+}
+
+
+bool
+Checkpoint::findObj(const std::string &section, const std::string &entry,
+ Serializable *&value)
+{
+ string path;
+
+ if (!db->find(section, entry, path))
+ return false;
+
+ if ((value = objMap[path]) != NULL)
+ return true;
+
+ return false;
+}
+
+
+bool
+Checkpoint::sectionExists(const std::string &section)
+{
+ return db->sectionExists(section);
+}
+
+/** Hacked stat reset event */
+
+class StatresetParamContext : public ParamContext
+{
+ public:
+ StatresetParamContext(const string &section);
+ ~StatresetParamContext();
+ void startup();
+};
+
+StatresetParamContext statParams("statsreset");
+
+Param<Tick> reset_cycle(&statParams, "reset_cycle",
+ "Cycle to reset stats on", 0);
+
+StatresetParamContext::StatresetParamContext(const string &section)
+ : ParamContext(section)
+{ }
+
+StatresetParamContext::~StatresetParamContext()
+{
+}
+
+void
+StatresetParamContext::startup()
+{
+ if (reset_cycle > 0) {
+ Stats::SetupEvent(Stats::Reset, curTick + reset_cycle, 0);
+ cprintf("Stats reset event scheduled for %lli\n",
+ curTick + reset_cycle);
+ }
+}
diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh
new file mode 100644
index 000000000..880fb0785
--- /dev/null
+++ b/src/sim/serialize.hh
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Erik Hallnor
+ * Steve Reinhardt
+ */
+
+/* @file
+ * Serialization Interface Declarations
+ */
+
+#ifndef __SERIALIZE_HH__
+#define __SERIALIZE_HH__
+
+
+#include <list>
+#include <iostream>
+#include <map>
+
+#include "sim/host.hh"
+
+class IniFile;
+class Serializable;
+class Checkpoint;
+
+template <class T>
+void paramOut(std::ostream &os, const std::string &name, const T &param);
+
+template <class T>
+void paramIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T &param);
+
+template <class T>
+void arrayParamOut(std::ostream &os, const std::string &name,
+ const T *param, int size);
+
+template <class T>
+void arrayParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T *param, int size);
+
+void
+objParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, Serializable * &param);
+
+
+//
+// These macros are streamlined to use in serialize/unserialize
+// functions. It's assumed that serialize() has a parameter 'os' for
+// the ostream, and unserialize() has parameters 'cp' and 'section'.
+#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar)
+
+#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar)
+
+// ENUMs are like SCALARs, but we cast them to ints on the way out
+#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar)
+
+#define UNSERIALIZE_ENUM(scalar) \
+ do { \
+ int tmp; \
+ paramIn(cp, section, #scalar, tmp); \
+ scalar = (typeof(scalar))tmp; \
+ } while (0)
+
+#define SERIALIZE_ARRAY(member, size) \
+ arrayParamOut(os, #member, member, size)
+
+#define UNSERIALIZE_ARRAY(member, size) \
+ arrayParamIn(cp, section, #member, member, size)
+
+#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name())
+
+#define UNSERIALIZE_OBJPTR(objptr) \
+ do { \
+ Serializable *sptr; \
+ objParamIn(cp, section, #objptr, sptr); \
+ objptr = dynamic_cast<typeof(objptr)>(sptr); \
+ } while (0)
+
+/*
+ * Basic support for object serialization.
+ */
+class Serializable
+{
+ protected:
+ void nameOut(std::ostream &os);
+ void nameOut(std::ostream &os, const std::string &_name);
+
+ public:
+ Serializable() {}
+ virtual ~Serializable() {}
+
+ // manditory virtual function, so objects must provide names
+ virtual const std::string name() const = 0;
+
+ virtual void serialize(std::ostream &os) {}
+ virtual void unserialize(Checkpoint *cp, const std::string &section) {}
+
+ static Serializable *create(Checkpoint *cp,
+ const std::string &section);
+
+ static int ckptCount;
+ static int ckptMaxCount;
+ static int ckptPrevCount;
+ static void serializeAll(const std::string &cpt_dir);
+ static void unserializeAll(const std::string &cpt_dir);
+ static void unserializeGlobals(Checkpoint *cp);
+};
+
+//
+// A SerializableBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a Serializable. This
+// evaluation context corresponds to a section in the .ini file (as
+// with the base ParamContext) plus an optional node in the
+// configuration hierarchy (the configNode member) for resolving
+// Serializable references. SerializableBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// Serializable (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SerializableClass::createObject().
+//
+class SerializableBuilder
+{
+ public:
+
+ SerializableBuilder() {}
+
+ virtual ~SerializableBuilder() {}
+
+ // Create the actual Serializable corresponding to the parameter
+ // values in this context. This function is overridden in derived
+ // classes to call a specific constructor for a particular
+ // subclass of Serializable.
+ virtual Serializable *create() = 0;
+};
+
+//
+// An instance of SerializableClass corresponds to a class derived from
+// Serializable. The SerializableClass instance serves to bind the string
+// name (found in the config file) to a function that creates an
+// instance of the appropriate derived class.
+//
+// This would be much cleaner in Smalltalk or Objective-C, where types
+// are first-class objects themselves.
+//
+class SerializableClass
+{
+ public:
+
+ // Type CreateFunc is a pointer to a function that creates a new
+ // simulation object builder based on a .ini-file parameter
+ // section (specified by the first string argument), a unique name
+ // for the object (specified by the second string argument), and
+ // an optional config hierarchy node (specified by the third
+ // argument). A pointer to the new SerializableBuilder is returned.
+ typedef Serializable *(*CreateFunc)(Checkpoint *cp,
+ const std::string &section);
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SerializableClass baseCacheSerializableClass("BaseCacheSerializable",
+ // newBaseCacheSerializableBuilder);
+ //
+ SerializableClass(const std::string &className, CreateFunc createFunc);
+
+ // create Serializable given name of class and pointer to
+ // configuration hierarchy node
+ static Serializable *createObject(Checkpoint *cp,
+ const std::string &section);
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SerializableBuilder and SerializableClass objects
+//
+
+#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \
+SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ OBJ_CLASS::createForUnserialize);
+
+void
+setCheckpointDir(const std::string &name);
+
+class Checkpoint
+{
+ private:
+
+ IniFile *db;
+ const std::string basePath;
+ std::map<std::string, Serializable*> objMap;
+
+ public:
+ Checkpoint(const std::string &cpt_dir, const std::string &path);
+
+ const std::string cptDir;
+
+ bool find(const std::string &section, const std::string &entry,
+ std::string &value);
+
+ bool findObj(const std::string &section, const std::string &entry,
+ Serializable *&value);
+
+ bool sectionExists(const std::string &section);
+
+ // The following static functions have to do with checkpoint
+ // creation rather than restoration. This class makes a handy
+ // namespace for them though.
+
+ // Export current checkpoint directory name so other objects can
+ // derive filenames from it (e.g., memory). The return value is
+ // guaranteed to end in '/' so filenames can be directly appended.
+ // This function is only valid while a checkpoint is being created.
+ static std::string dir();
+
+ // Filename for base checkpoint file within directory.
+ static const char *baseFilename;
+};
+
+#endif // __SERIALIZE_HH__
diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc
new file mode 100644
index 000000000..d9e8bdeaa
--- /dev/null
+++ b/src/sim/sim_events.cc
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#include <string>
+
+#include "base/callback.hh"
+#include "base/hostinfo.hh"
+#include "sim/eventq.hh"
+#include "sim/param.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/startup.hh"
+#include "sim/stats.hh"
+
+using namespace std;
+
+//
+// handle termination event
+//
+void
+SimLoopExitEvent::process()
+{
+ // if this got scheduled on a different queue (e.g. the committed
+ // instruction queue) then make a corresponding event on the main
+ // queue.
+ if (theQueue() != &mainEventQueue) {
+ exitSimLoop(cause, code);
+ delete this;
+ }
+
+ // otherwise do nothing... the IsExitEvent flag takes care of
+ // exiting the simulation loop and returning this object to Python
+}
+
+
+const char *
+SimLoopExitEvent::description()
+{
+ return "simulation loop exit";
+}
+
+void
+exitSimLoop(Tick when, const std::string &message, int exit_code)
+{
+ new SimLoopExitEvent(when, message, exit_code);
+}
+
+void
+exitSimLoop(const std::string &message, int exit_code)
+{
+ exitSimLoop(curTick, message, exit_code);
+}
+
+void
+CountedDrainEvent::process()
+{
+ if (--count == 0) {
+ exitSimLoop("Finished drain");
+ }
+}
+
+//
+// constructor: automatically schedules at specified time
+//
+CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause,
+ Tick _when, int &_downCounter)
+ : Event(q, Sim_Exit_Pri),
+ cause(_cause),
+ downCounter(_downCounter)
+{
+ // catch stupid mistakes
+ assert(downCounter > 0);
+
+ schedule(_when);
+}
+
+
+//
+// handle termination event
+//
+void
+CountedExitEvent::process()
+{
+ if (--downCounter == 0) {
+ exitSimLoop(cause, 0);
+ }
+}
+
+
+const char *
+CountedExitEvent::description()
+{
+ return "counted exit";
+}
+
+#ifdef CHECK_SWAP_CYCLES
+new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES);
+#endif
+
+void
+CheckSwapEvent::process()
+{
+ /* Check the amount of free swap space */
+ long swap;
+
+ /* returns free swap in KBytes */
+ swap = procInfo("/proc/meminfo", "SwapFree:");
+
+ if (swap < 1000)
+ ccprintf(cerr, "\a\a\aWarning! Swap space is low (%d)\n", swap);
+
+ if (swap < 100) {
+ cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
+ exitSimLoop("Lack of swap space");
+ }
+
+ schedule(curTick + interval);
+}
+
+const char *
+CheckSwapEvent::description()
+{
+ return "check swap";
+}
+
+//
+// handle progress event: print message and reschedule
+//
+void
+ProgressEvent::process()
+{
+ DPRINTFN("ProgressEvent\n");
+ // reschedule for next interval
+ schedule(curTick + interval);
+}
+
+
+const char *
+ProgressEvent::description()
+{
+ return "progress message";
+}
diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh
new file mode 100644
index 000000000..3c4a9dd05
--- /dev/null
+++ b/src/sim/sim_events.hh
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __SIM_SIM_EVENTS_HH__
+#define __SIM_SIM_EVENTS_HH__
+
+#include "sim/eventq.hh"
+
+//
+// Event to terminate simulation at a particular cycle/instruction
+//
+class SimLoopExitEvent : public Event
+{
+ private:
+ // string explaining why we're terminating
+ std::string cause;
+ int code;
+
+ public:
+ // Default constructor. Only really used for derived classes.
+ SimLoopExitEvent()
+ : Event(&mainEventQueue, Sim_Exit_Pri)
+ { }
+
+ SimLoopExitEvent(Tick _when, const std::string &_cause, int c = 0)
+ : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
+ code(c)
+ { setFlags(IsExitEvent); schedule(_when); }
+
+ SimLoopExitEvent(EventQueue *q,
+ Tick _when, const std::string &_cause, int c = 0)
+ : Event(q, Sim_Exit_Pri), cause(_cause), code(c)
+ { setFlags(IsExitEvent); schedule(_when); }
+
+ std::string getCause() { return cause; }
+ int getCode() { return code; }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+class CountedDrainEvent : public SimLoopExitEvent
+{
+ private:
+ // Count of how many objects have not yet drained
+ int count;
+ public:
+ CountedDrainEvent()
+ : count(0)
+ { }
+ void process();
+
+ void setCount(int _count) { count = _count; }
+
+ int getCount() { return count; }
+};
+
+//
+// Event class to terminate simulation after 'n' related events have
+// occurred using a shared counter: used to terminate when *all*
+// threads have reached a particular instruction count
+//
+class CountedExitEvent : public Event
+{
+ private:
+ std::string cause; // string explaining why we're terminating
+ int &downCounter; // decrement & terminate if zero
+
+ public:
+ CountedExitEvent(EventQueue *q, const std::string &_cause,
+ Tick _when, int &_downCounter);
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+//
+// Event to check swap usage
+//
+class CheckSwapEvent : public Event
+{
+ private:
+ int interval;
+
+ public:
+ CheckSwapEvent(EventQueue *q, int ival)
+ : Event(q), interval(ival)
+ { schedule(curTick + interval); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+//
+// Progress event: print out cycle every so often so we know we're
+// making forward progress.
+//
+class ProgressEvent : public Event
+{
+ protected:
+ Tick interval;
+
+ public:
+ ProgressEvent(EventQueue *q, Tick ival)
+ : Event(q), interval(ival)
+ { schedule(curTick + interval); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+#endif // __SIM_SIM_EVENTS_HH__
diff --git a/src/sim/sim_exit.hh b/src/sim/sim_exit.hh
new file mode 100644
index 000000000..545bf4ae0
--- /dev/null
+++ b/src/sim/sim_exit.hh
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
+ */
+
+#ifndef __SIM_EXIT_HH__
+#define __SIM_EXIT_HH__
+
+#include <string>
+
+#include "sim/host.hh"
+
+// forward declaration
+class Callback;
+
+/// Register a callback to be called when Python exits. Defined in
+/// sim/main.cc.
+void registerExitCallback(Callback *);
+
+/// Schedule an event to exit the simulation loop (returning to
+/// Python) at the indicated tick. The message and exit_code
+/// parameters are saved in the SimLoopExitEvent to indicate why the
+/// exit occurred.
+void exitSimLoop(Tick when, const std::string &message, int exit_code = 0);
+
+/// Schedule an event to exit the simulation loop (returning to
+/// Python) at the end of the current cycle (curTick). The message
+/// and exit_code parameters are saved in the SimLoopExitEvent to
+/// indicate why the exit occurred.
+void exitSimLoop(const std::string &cause, int exit_code = 0);
+
+#endif // __SIM_EXIT_HH__
diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc
new file mode 100644
index 000000000..d12b06b7a
--- /dev/null
+++ b/src/sim/sim_object.cc
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Nathan Binkert
+ */
+
+#include <assert.h>
+
+#include "base/callback.hh"
+#include "base/inifile.hh"
+#include "base/match.hh"
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "base/stats/events.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+#include "sim/param.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObject member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// static list of all SimObjects, used for initialization etc.
+//
+SimObject::SimObjectList SimObject::simObjectList;
+
+namespace Stats {
+ extern ObjectMatch event_ignore;
+}
+
+//
+// SimObject constructor: used to maintain static simObjectList
+//
+SimObject::SimObject(Params *p)
+ : _params(p)
+{
+#ifdef DEBUG
+ doDebugBreak = false;
+#endif
+
+ doRecordEvent = !Stats::event_ignore.match(name());
+ simObjectList.push_back(this);
+ state = Running;
+}
+
+//
+// SimObject constructor: used to maintain static simObjectList
+//
+SimObject::SimObject(const string &_name)
+ : _params(new Params)
+{
+ _params->name = _name;
+#ifdef DEBUG
+ doDebugBreak = false;
+#endif
+
+ doRecordEvent = !Stats::event_ignore.match(name());
+ simObjectList.push_back(this);
+ state = Running;
+}
+
+void
+SimObject::connect()
+{
+}
+
+void
+SimObject::init()
+{
+}
+
+//
+// no default statistics, so nothing to do in base implementation
+//
+void
+SimObject::regStats()
+{
+}
+
+void
+SimObject::regFormulas()
+{
+}
+
+void
+SimObject::resetStats()
+{
+}
+
+//
+// static function:
+// call regStats() on all SimObjects and then regFormulas() on all
+// SimObjects.
+//
+struct SimObjectResetCB : public Callback
+{
+ virtual void process() { SimObject::resetAllStats(); }
+};
+
+namespace {
+ static SimObjectResetCB StatResetCB;
+}
+
+void
+SimObject::regAllStats()
+{
+ SimObjectList::iterator i;
+ SimObjectList::iterator end = simObjectList.end();
+
+ /**
+ * @todo change cprintfs to DPRINTFs
+ */
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering stats for %s\n", (*i)->name());
+#endif
+ (*i)->regStats();
+ }
+
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering formulas for %s\n", (*i)->name());
+#endif
+ (*i)->regFormulas();
+ }
+
+ Stats::registerResetCallback(&StatResetCB);
+}
+
+//
+// static function: call connect() on all SimObjects.
+//
+void
+SimObject::connectAll()
+{
+ SimObjectList::iterator i = simObjectList.begin();
+ SimObjectList::iterator end = simObjectList.end();
+
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->connect();
+ }
+}
+
+//
+// static function: call init() on all SimObjects.
+//
+void
+SimObject::initAll()
+{
+ SimObjectList::iterator i = simObjectList.begin();
+ SimObjectList::iterator end = simObjectList.end();
+
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->init();
+ }
+}
+
+//
+// static function: call resetStats() on all SimObjects.
+//
+void
+SimObject::resetAllStats()
+{
+ SimObjectList::iterator i = simObjectList.begin();
+ SimObjectList::iterator end = simObjectList.end();
+
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->resetStats();
+ }
+}
+
+//
+// static function: serialize all SimObjects.
+//
+void
+SimObject::serializeAll(ostream &os)
+{
+ SimObjectList::reverse_iterator ri = simObjectList.rbegin();
+ SimObjectList::reverse_iterator rend = simObjectList.rend();
+
+ for (; ri != rend; ++ri) {
+ SimObject *obj = *ri;
+ obj->nameOut(os);
+ obj->serialize(os);
+ }
+}
+
+void
+SimObject::unserializeAll(Checkpoint *cp)
+{
+ SimObjectList::reverse_iterator ri = simObjectList.rbegin();
+ SimObjectList::reverse_iterator rend = simObjectList.rend();
+
+ for (; ri != rend; ++ri) {
+ SimObject *obj = *ri;
+ DPRINTFR(Config, "Unserializing '%s'\n",
+ obj->name());
+ if(cp->sectionExists(obj->name()))
+ obj->unserialize(cp, obj->name());
+ else
+ warn("Not unserializing '%s': no section found in checkpoint.\n",
+ obj->name());
+ }
+}
+
+#ifdef DEBUG
+//
+// static function: flag which objects should have the debugger break
+//
+void
+SimObject::debugObjectBreak(const string &objs)
+{
+ SimObjectList::const_iterator i = simObjectList.begin();
+ SimObjectList::const_iterator end = simObjectList.end();
+
+ ObjectMatch match(objs);
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->doDebugBreak = match.match(obj->name());
+ }
+}
+
+void
+debugObjectBreak(const char *objs)
+{
+ SimObject::debugObjectBreak(string(objs));
+}
+#endif
+
+void
+SimObject::recordEvent(const std::string &stat)
+{
+ if (doRecordEvent)
+ Stats::recordEvent(stat);
+}
+
+unsigned int
+SimObject::drain(Event *drain_event)
+{
+ state = Drained;
+ return 0;
+}
+
+void
+SimObject::resume()
+{
+ state = Running;
+}
+
+void
+SimObject::setMemoryMode(State new_mode)
+{
+ panic("setMemoryMode() should only be called on systems");
+}
+
+void
+SimObject::switchOut()
+{
+ panic("Unimplemented!");
+}
+
+void
+SimObject::takeOverFrom(BaseCPU *cpu)
+{
+ panic("Unimplemented!");
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject)
diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh
new file mode 100644
index 000000000..38f2bdd23
--- /dev/null
+++ b/src/sim/sim_object.hh
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Nathan Binkert
+ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#ifndef __SIM_OBJECT_HH__
+#define __SIM_OBJECT_HH__
+
+#include <map>
+#include <list>
+#include <vector>
+#include <iostream>
+
+#include "sim/serialize.hh"
+#include "sim/startup.hh"
+
+class BaseCPU;
+class Event;
+
+/*
+ * Abstract superclass for simulation objects. Represents things that
+ * correspond to physical components and can be specified via the
+ * config file (CPUs, caches, etc.).
+ */
+class SimObject : public Serializable, protected StartupCallback
+{
+ public:
+ struct Params {
+ std::string name;
+ };
+
+ enum State {
+ Running,
+ Draining,
+ Drained
+ };
+ private:
+ State state;
+
+ protected:
+ Params *_params;
+
+ void changeState(State new_state) { state = new_state; }
+
+ public:
+ const Params *params() const { return _params; }
+
+ State getState() { return state; }
+
+ private:
+ typedef std::vector<SimObject *> SimObjectList;
+
+ // list of all instantiated simulation objects
+ static SimObjectList simObjectList;
+
+ public:
+ SimObject(Params *_params);
+ SimObject(const std::string &_name);
+
+ virtual ~SimObject() {}
+
+ virtual const std::string name() const { return params()->name; }
+
+ // initialization pass of all objects.
+ // Gets invoked after construction, before unserialize.
+ virtual void init();
+ virtual void connect();
+ static void initAll();
+ static void connectAll();
+
+ // register statistics for this object
+ virtual void regStats();
+ virtual void regFormulas();
+ virtual void resetStats();
+
+ // static: call reg_stats on all SimObjects
+ static void regAllStats();
+
+ // static: call resetStats on all SimObjects
+ static void resetAllStats();
+
+ // static: call nameOut() & serialize() on all SimObjects
+ static void serializeAll(std::ostream &);
+ static void unserializeAll(Checkpoint *cp);
+
+ // Methods to drain objects in order to take checkpoints
+ // Or switch from timing -> atomic memory model
+ // Drain returns 0 if the simobject can drain immediately or
+ // the number of times the drain_event's process function will be called
+ // before the object will be done draining. Normally this should be 1
+ virtual unsigned int drain(Event *drain_event);
+ virtual void resume();
+ virtual void setMemoryMode(State new_mode);
+ virtual void switchOut();
+ virtual void takeOverFrom(BaseCPU *cpu);
+
+#ifdef DEBUG
+ public:
+ bool doDebugBreak;
+ static void debugObjectBreak(const std::string &objs);
+#endif
+
+ public:
+ bool doRecordEvent;
+ void recordEvent(const std::string &stat);
+};
+
+#endif // __SIM_OBJECT_HH__
diff --git a/src/sim/startup.cc b/src/sim/startup.cc
new file mode 100644
index 000000000..838352107
--- /dev/null
+++ b/src/sim/startup.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Kevin Lim
+ */
+
+#include <list>
+
+#include "base/misc.hh"
+#include "sim/debug.hh"
+#include "sim/startup.hh"
+
+typedef std::list<StartupCallback *> startupq_t;
+
+startupq_t *startupq = NULL;
+
+StartupCallback::StartupCallback()
+{
+ if (startupq == NULL)
+ startupq = new startupq_t;
+ startupq->push_back(this);
+}
+
+StartupCallback::~StartupCallback()
+{
+ startupq->remove(this);
+}
+
+void StartupCallback::startup() { }
+
+void
+SimStartup()
+{
+ startupq_t::iterator i = startupq->begin();
+ startupq_t::iterator end = startupq->end();
+
+ while (i != end) {
+ (*i)->startup();
+ ++i;
+ }
+}
diff --git a/src/sim/startup.hh b/src/sim/startup.hh
new file mode 100644
index 000000000..cfc4450f4
--- /dev/null
+++ b/src/sim/startup.hh
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __SIM_STARTUP_HH__
+#define __SIM_STARTUP_HH__
+
+struct StartupCallback
+{
+ StartupCallback();
+ virtual ~StartupCallback();
+ virtual void startup();
+};
+
+void SimStartup();
+
+#endif // __SIM_STARTUP_HH__
diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc
new file mode 100644
index 000000000..dfed2a0c8
--- /dev/null
+++ b/src/sim/stat_control.cc
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+// This file will contain default statistics for the simulator that
+// don't really belong to a specific simulator object
+
+#include <fstream>
+#include <iostream>
+#include <list>
+
+#include "base/callback.hh"
+#include "base/hostinfo.hh"
+#include "base/statistics.hh"
+#include "base/str.hh"
+#include "base/time.hh"
+#include "base/stats/output.hh"
+#include "cpu/base.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+#include "sim/stat_control.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+Stats::Formula hostInstRate;
+Stats::Formula hostTickRate;
+Stats::Value hostMemory;
+Stats::Value hostSeconds;
+
+Stats::Value simTicks;
+Stats::Value simInsts;
+Stats::Value simFreq;
+Stats::Formula simSeconds;
+
+namespace Stats {
+
+Time statTime(true);
+Tick startTick;
+Tick lastDump(0);
+
+class SimTicksReset : public Callback
+{
+ public:
+ void process()
+ {
+ statTime.set();
+ startTick = curTick;
+ }
+};
+
+double
+statElapsedTime()
+{
+ Time now(true);
+ Time elapsed = now - statTime;
+ return elapsed();
+}
+
+Tick
+statElapsedTicks()
+{
+ return curTick - startTick;
+}
+
+SimTicksReset simTicksReset;
+
+void
+InitSimStats()
+{
+ simInsts
+ .functor(BaseCPU::numSimulatedInstructions)
+ .name("sim_insts")
+ .desc("Number of instructions simulated")
+ .precision(0)
+ .prereq(simInsts)
+ ;
+
+ simSeconds
+ .name("sim_seconds")
+ .desc("Number of seconds simulated")
+ ;
+
+ simFreq
+ .scalar(Clock::Frequency)
+ .name("sim_freq")
+ .desc("Frequency of simulated ticks")
+ ;
+
+ simTicks
+ .functor(statElapsedTicks)
+ .name("sim_ticks")
+ .desc("Number of ticks simulated")
+ ;
+
+ hostInstRate
+ .name("host_inst_rate")
+ .desc("Simulator instruction rate (inst/s)")
+ .precision(0)
+ .prereq(simInsts)
+ ;
+
+ hostMemory
+ .functor(memUsage)
+ .name("host_mem_usage")
+ .desc("Number of bytes of host memory used")
+ .prereq(hostMemory)
+ ;
+
+ hostSeconds
+ .functor(statElapsedTime)
+ .name("host_seconds")
+ .desc("Real time elapsed on the host")
+ .precision(2)
+ ;
+
+ hostTickRate
+ .name("host_tick_rate")
+ .desc("Simulator tick rate (ticks/s)")
+ .precision(0)
+ ;
+
+ simSeconds = simTicks / simFreq;
+ hostInstRate = simInsts / hostSeconds;
+ hostTickRate = simTicks / hostSeconds;
+
+ registerResetCallback(&simTicksReset);
+}
+
+class StatEvent : public Event
+{
+ protected:
+ int flags;
+ Tick repeat;
+
+ public:
+ StatEvent(EventQueue *queue, int _flags, Tick _when, Tick _repeat);
+ virtual void process();
+ virtual const char *description();
+};
+
+StatEvent::StatEvent(EventQueue *queue, int _flags, Tick _when, Tick _repeat)
+ : Event(queue, Stat_Event_Pri),
+ flags(_flags), repeat(_repeat)
+{
+ setFlags(AutoDelete);
+ schedule(_when);
+}
+
+const char *
+StatEvent::description()
+{
+ return "Statistics dump and/or reset";
+}
+
+void
+StatEvent::process()
+{
+ if (flags & Stats::Dump)
+ DumpNow();
+
+ if (flags & Stats::Reset) {
+ cprintf("Resetting stats!\n");
+ reset();
+ }
+
+ if (repeat)
+ schedule(curTick + repeat);
+}
+
+list<Output *> OutputList;
+
+void
+DumpNow()
+{
+ assert(lastDump <= curTick);
+ if (lastDump == curTick)
+ return;
+ lastDump = curTick;
+
+ list<Output *>::iterator i = OutputList.begin();
+ list<Output *>::iterator end = OutputList.end();
+ for (; i != end; ++i) {
+ Output *output = *i;
+ if (!output->valid())
+ continue;
+
+ output->output();
+ }
+}
+
+void
+SetupEvent(int flags, Tick when, Tick repeat, EventQueue *queue)
+{
+ if (queue == NULL)
+ queue = &mainEventQueue;
+
+ new StatEvent(queue, flags, when, repeat);
+}
+
+/* namespace Stats */ }
+
+void debugDumpStats()
+{
+ Stats::DumpNow();
+}
+
diff --git a/src/sim/stat_control.hh b/src/sim/stat_control.hh
new file mode 100644
index 000000000..67f7cc491
--- /dev/null
+++ b/src/sim/stat_control.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __SIM_STAT_CONTROL_HH__
+#define __SIM_STAT_CONTROL_HH__
+
+#include <fstream>
+#include <list>
+
+class EventQueue;
+
+namespace Stats {
+
+enum {
+ Reset = 0x1,
+ Dump = 0x2
+};
+
+class Output;
+extern std::list<Output *> OutputList;
+
+void DumpNow();
+void SetupEvent(int flags, Tick when, Tick repeat = 0, EventQueue *queue = NULL);
+
+void InitSimStats();
+
+/* namespace Stats */ }
+
+#endif // __SIM_STAT_CONTROL_HH__
diff --git a/src/sim/stats.hh b/src/sim/stats.hh
new file mode 100644
index 000000000..97251283d
--- /dev/null
+++ b/src/sim/stats.hh
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __SIM_STATS_HH__
+#define __SIM_STATS_HH__
+
+#include "base/statistics.hh"
+
+extern Stats::Formula simSeconds;
+extern Stats::Value simTicks;
+
+#endif // __SIM_SIM_STATS_HH__
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
new file mode 100644
index 000000000..9028d590b
--- /dev/null
+++ b/src/sim/syscall_emul.cc
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Ali Saidi
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+#include <iostream>
+
+#include "sim/syscall_emul.hh"
+#include "base/chunk_generator.hh"
+#include "base/trace.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/base.hh"
+#include "mem/page_table.hh"
+#include "sim/process.hh"
+
+#include "sim/sim_exit.hh"
+
+using namespace std;
+using namespace TheISA;
+
+void
+SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
+{
+ DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
+ curTick,tc->getCpuPtr()->name(), name,
+ tc->getSyscallArg(0),tc->getSyscallArg(1),
+ tc->getSyscallArg(2),tc->getSyscallArg(3));
+
+ SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
+
+ DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
+ curTick,tc->getCpuPtr()->name(), name, retval.value());
+
+ if (!(flags & SyscallDesc::SuppressReturnValue))
+ tc->setSyscallReturn(retval);
+}
+
+
+SyscallReturn
+unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
+
+ return 1;
+}
+
+
+SyscallReturn
+ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ warn("ignoring syscall %s(%d, %d, ...)", desc->name,
+ tc->getSyscallArg(0), tc->getSyscallArg(1));
+
+ return 0;
+}
+
+
+SyscallReturn
+exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ if (tc->exit()) {
+ exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff);
+ }
+
+ return 1;
+}
+
+
+SyscallReturn
+getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ return (int)VMPageSize;
+}
+
+
+SyscallReturn
+obreakFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ Addr junk;
+
+ // change brk addr to first arg
+ Addr new_brk = tc->getSyscallArg(0);
+ if (new_brk != 0) {
+ for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
+ VMPageSize); !gen.done(); gen.next()) {
+ if (!p->pTable->translate(gen.addr(), junk))
+ p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
+ VMPageSize);
+ }
+ p->brk_point = new_brk;
+ }
+ DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
+ return p->brk_point;
+}
+
+
+SyscallReturn
+closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ int target_fd = tc->getSyscallArg(0);
+ int status = close(p->sim_fd(target_fd));
+ if (status >= 0)
+ p->free_fd(target_fd);
+ return status;
+}
+
+
+SyscallReturn
+readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ int nbytes = tc->getSyscallArg(2);
+ BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+
+ int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
+
+ if (bytes_read != -1)
+ bufArg.copyOut(tc->getMemPort());
+
+ return bytes_read;
+}
+
+SyscallReturn
+writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ int nbytes = tc->getSyscallArg(2);
+ BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+
+ bufArg.copyIn(tc->getMemPort());
+
+ int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
+
+ fsync(fd);
+
+ return bytes_written;
+}
+
+
+SyscallReturn
+lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ uint64_t offs = tc->getSyscallArg(1);
+ int whence = tc->getSyscallArg(2);
+
+ off_t result = lseek(fd, offs, whence);
+
+ return (result == (off_t)-1) ? -errno : result;
+}
+
+
+SyscallReturn
+munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ // given that we don't really implement mmap, munmap is really easy
+ return 0;
+}
+
+
+const char *hostname = "m5.eecs.umich.edu";
+
+SyscallReturn
+gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ int name_len = tc->getSyscallArg(1);
+ BufferArg name(tc->getSyscallArg(0), name_len);
+
+ strncpy((char *)name.bufferPtr(), hostname, name_len);
+
+ name.copyOut(tc->getMemPort());
+
+ return 0;
+}
+
+SyscallReturn
+unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return (TheISA::IntReg)-EFAULT;
+
+ int result = unlink(path.c_str());
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ string old_name;
+
+ if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ string new_name;
+
+ if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1)))
+ return -EFAULT;
+
+ int64_t result = rename(old_name.c_str(), new_name.c_str());
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ off_t length = tc->getSyscallArg(1);
+
+ int result = truncate(path.c_str(), length);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+ftruncateFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
+{
+ int fd = process->sim_fd(tc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ off_t length = tc->getSyscallArg(1);
+
+ int result = ftruncate(fd, length);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ /* XXX endianess */
+ uint32_t owner = tc->getSyscallArg(1);
+ uid_t hostOwner = owner;
+ uint32_t group = tc->getSyscallArg(2);
+ gid_t hostGroup = group;
+
+ int result = chown(path.c_str(), hostOwner, hostGroup);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
+{
+ int fd = process->sim_fd(tc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ /* XXX endianess */
+ uint32_t owner = tc->getSyscallArg(1);
+ uid_t hostOwner = owner;
+ uint32_t group = tc->getSyscallArg(2);
+ gid_t hostGroup = group;
+
+ int result = fchown(fd, hostOwner, hostGroup);
+ return (result == -1) ? -errno : result;
+}
+
+
+SyscallReturn
+dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
+{
+ int fd = process->sim_fd(tc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ int result = dup(fd);
+ return (result == -1) ? -errno : process->alloc_fd(result);
+}
+
+
+SyscallReturn
+fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+
+ if (fd < 0 || process->sim_fd(fd) < 0)
+ return -EBADF;
+
+ int cmd = tc->getSyscallArg(1);
+ switch (cmd) {
+ case 0: // F_DUPFD
+ // if we really wanted to support this, we'd need to do it
+ // in the target fd space.
+ warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ case 1: // F_GETFD (get close-on-exec flag)
+ case 2: // F_SETFD (set close-on-exec flag)
+ return 0;
+
+ case 3: // F_GETFL (get file flags)
+ case 4: // F_SETFL (set file flags)
+ // not sure if this is totally valid, but we'll pass it through
+ // to the underlying OS
+ warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
+ return fcntl(process->sim_fd(fd), cmd);
+ // return 0;
+
+ case 7: // F_GETLK (get lock)
+ case 8: // F_SETLK (set lock)
+ case 9: // F_SETLKW (set lock and wait)
+ // don't mess with file locking... just act like it's OK
+ warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
+ return 0;
+
+ default:
+ warn("Unknown fcntl command %d\n", cmd);
+ return 0;
+ }
+}
+
+SyscallReturn
+fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+
+ if (fd < 0 || process->sim_fd(fd) < 0)
+ return -EBADF;
+
+ int cmd = tc->getSyscallArg(1);
+ switch (cmd) {
+ case 33: //F_GETLK64
+ warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ case 34: // F_SETLK64
+ case 35: // F_SETLKW64
+ warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ default:
+ // not sure if this is totally valid, but we'll pass it through
+ // to the underlying OS
+ warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
+ return fcntl(process->sim_fd(fd), cmd);
+ // return 0;
+ }
+}
+
+SyscallReturn
+pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fds[2], sim_fds[2];
+ int pipe_retval = pipe(fds);
+
+ if (pipe_retval < 0) {
+ // error
+ return pipe_retval;
+ }
+
+ sim_fds[0] = process->alloc_fd(fds[0]);
+ sim_fds[1] = process->alloc_fd(fds[1]);
+
+ // Alpha Linux convention for pipe() is that fd[0] is returned as
+ // the return value of the function, and fd[1] is returned in r20.
+ tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
+ return sim_fds[0];
+}
+
+
+SyscallReturn
+getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ // Make up a PID. There's no interprocess communication in
+ // fake_syscall mode, so there's no way for a process to know it's
+ // not getting a unique value.
+
+ tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
+ return process->pid();
+}
+
+
+SyscallReturn
+getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ // Make up a UID and EUID... it shouldn't matter, and we want the
+ // simulation to be deterministic.
+
+ // EUID goes in r20.
+ tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
+ return process->uid(); // UID
+}
+
+
+SyscallReturn
+getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ // Get current group ID. EGID goes in r20.
+ tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
+ return process->gid();
+}
+
+
+SyscallReturn
+setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ // can't fathom why a benchmark would call this.
+ warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0));
+ return 0;
+}
+
+SyscallReturn
+getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ // Make up a PID. There's no interprocess communication in
+ // fake_syscall mode, so there's no way for a process to know it's
+ // not getting a unique value.
+
+ tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
+ return process->pid();
+}
+
+SyscallReturn
+getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ return process->ppid();
+}
+
+SyscallReturn
+getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ return process->uid(); // UID
+}
+
+SyscallReturn
+geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ return process->euid(); // UID
+}
+
+SyscallReturn
+getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ return process->gid();
+}
+
+SyscallReturn
+getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ return process->egid();
+}
+
+
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
new file mode 100644
index 000000000..edd4e331d
--- /dev/null
+++ b/src/sim/syscall_emul.hh
@@ -0,0 +1,943 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Kevin Lim
+ */
+
+#ifndef __SIM_SYSCALL_EMUL_HH__
+#define __SIM_SYSCALL_EMUL_HH__
+
+#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
+ defined(__FreeBSD__) || defined(__CYGWIN__))
+
+///
+/// @file syscall_emul.hh
+///
+/// This file defines objects used to emulate syscalls from the target
+/// application on the host machine.
+
+#include <errno.h>
+#include <string>
+#ifdef __CYGWIN32__
+#include <sys/fcntl.h> // for O_BINARY
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+
+#include "sim/host.hh" // for Addr
+#include "base/chunk_generator.hh"
+#include "base/intmath.hh" // for RoundUp
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "mem/translating_port.hh"
+#include "mem/page_table.hh"
+#include "sim/process.hh"
+
+///
+/// System call descriptor.
+///
+class SyscallDesc {
+
+ public:
+
+ /// Typedef for target syscall handler functions.
+ typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
+ LiveProcess *, ThreadContext *);
+
+ const char *name; //!< Syscall name (e.g., "open").
+ FuncPtr funcPtr; //!< Pointer to emulation function.
+ int flags; //!< Flags (see Flags enum).
+
+ /// Flag values for controlling syscall behavior.
+ enum Flags {
+ /// Don't set return regs according to funcPtr return value.
+ /// Used for syscalls with non-standard return conventions
+ /// that explicitly set the ThreadContext regs (e.g.,
+ /// sigreturn).
+ SuppressReturnValue = 1
+ };
+
+ /// Constructor.
+ SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
+ : name(_name), funcPtr(_funcPtr), flags(_flags)
+ {
+ }
+
+ /// Emulate the syscall. Public interface for calling through funcPtr.
+ void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc);
+};
+
+
+class BaseBufferArg {
+
+ public:
+
+ BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
+ {
+ bufPtr = new uint8_t[size];
+ // clear out buffer: in case we only partially populate this,
+ // and then do a copyOut(), we want to make sure we don't
+ // introduce any random junk into the simulated address space
+ memset(bufPtr, 0, size);
+ }
+
+ virtual ~BaseBufferArg() { delete [] bufPtr; }
+
+ //
+ // copy data into simulator space (read from target memory)
+ //
+ virtual bool copyIn(TranslatingPort *memport)
+ {
+ memport->readBlob(addr, bufPtr, size);
+ return true; // no EFAULT detection for now
+ }
+
+ //
+ // copy data out of simulator space (write to target memory)
+ //
+ virtual bool copyOut(TranslatingPort *memport)
+ {
+ memport->writeBlob(addr, bufPtr, size);
+ return true; // no EFAULT detection for now
+ }
+
+ protected:
+ Addr addr;
+ int size;
+ uint8_t *bufPtr;
+};
+
+
+class BufferArg : public BaseBufferArg
+{
+ public:
+ BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
+ void *bufferPtr() { return bufPtr; }
+};
+
+template <class T>
+class TypedBufferArg : public BaseBufferArg
+{
+ public:
+ // user can optionally specify a specific number of bytes to
+ // allocate to deal with those structs that have variable-size
+ // arrays at the end
+ TypedBufferArg(Addr _addr, int _size = sizeof(T))
+ : BaseBufferArg(_addr, _size)
+ { }
+
+ // type case
+ operator T*() { return (T *)bufPtr; }
+
+ // dereference operators
+ T &operator*() { return *((T *)bufPtr); }
+ T* operator->() { return (T *)bufPtr; }
+ T &operator[](int i) { return ((T *)bufPtr)[i]; }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// The following emulation functions are generic enough that they
+// don't need to be recompiled for different emulated OS's. They are
+// defined in sim/syscall_emul.cc.
+//
+//////////////////////////////////////////////////////////////////////
+
+
+/// Handler for unimplemented syscalls that we haven't thought about.
+SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Handler for unimplemented syscalls that we never intend to
+/// implement (signal handling, etc.) and should not affect the correct
+/// behavior of the program. Print a warning only if the appropriate
+/// trace flag is enabled. Return success to the target program.
+SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target exit() handler: terminate simulation.
+SyscallReturn exitFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getpagesize() handler.
+SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target obreak() handler: set brk address.
+SyscallReturn obreakFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target close() handler.
+SyscallReturn closeFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target read() handler.
+SyscallReturn readFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target write() handler.
+SyscallReturn writeFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target lseek() handler.
+SyscallReturn lseekFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target munmap() handler.
+SyscallReturn munmapFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target gethostname() handler.
+SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target unlink() handler.
+SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target rename() handler.
+SyscallReturn renameFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
+/// Target truncate() handler.
+SyscallReturn truncateFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
+/// Target ftruncate() handler.
+SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
+/// Target chown() handler.
+SyscallReturn chownFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
+/// Target fchown() handler.
+SyscallReturn fchownFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target dup() handler.
+SyscallReturn dupFunc(SyscallDesc *desc, int num,
+ LiveProcess *process, ThreadContext *tc);
+
+/// Target fnctl() handler.
+SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
+ LiveProcess *process, ThreadContext *tc);
+
+/// Target fcntl64() handler.
+SyscallReturn fcntl64Func(SyscallDesc *desc, int num,
+ LiveProcess *process, ThreadContext *tc);
+
+/// Target setuid() handler.
+SyscallReturn setuidFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getpid() handler.
+SyscallReturn getpidFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getuid() handler.
+SyscallReturn getuidFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getgid() handler.
+SyscallReturn getgidFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getppid() handler.
+SyscallReturn getppidFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target geteuid() handler.
+SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getegid() handler.
+SyscallReturn getegidFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
+
+/// Pseudo Funcs - These functions use a different return convension,
+/// returning a second value in a register other than the normal return register
+SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
+ LiveProcess *process, ThreadContext *tc);
+
+/// Target getpidPseudo() handler.
+SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getuidPseudo() handler.
+SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target getgidPseudo() handler.
+SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
+/// A readable name for 1,000,000, for converting microseconds to seconds.
+const int one_million = 1000000;
+
+/// Approximate seconds since the epoch (1/1/1970). About a billion,
+/// by my reckoning. We want to keep this a constant (not use the
+/// real-world time) to keep simulations repeatable.
+const unsigned seconds_since_epoch = 1000000000;
+
+/// Helper function to convert current elapsed time to seconds and
+/// microseconds.
+template <class T1, class T2>
+void
+getElapsedTime(T1 &sec, T2 &usec)
+{
+ int elapsed_usecs = curTick / Clock::Int::us;
+ sec = elapsed_usecs / one_million;
+ usec = elapsed_usecs % one_million;
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// The following emulation functions are generic, but need to be
+// templated to account for differences in types, constants, etc.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if NO_STAT64
+ typedef struct stat hst_stat;
+ typedef struct stat hst_stat64;
+#else
+ typedef struct stat hst_stat;
+ typedef struct stat64 hst_stat64;
+#endif
+
+//// Helper function to convert a host stat buffer to a target stat
+//// buffer. Also copies the target buffer out to the simulated
+//// memory space. Used by stat(), fstat(), and lstat().
+
+template <typename target_stat, typename host_stat>
+static void
+convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
+{
+ if (fakeTTY)
+ tgt->st_dev = 0xA;
+ else
+ tgt->st_dev = host->st_dev;
+ tgt->st_dev = htog(tgt->st_dev);
+ tgt->st_ino = host->st_ino;
+ tgt->st_ino = htog(tgt->st_ino);
+ if (fakeTTY)
+ tgt->st_rdev = 0x880d;
+ else
+ tgt->st_rdev = host->st_rdev;
+ tgt->st_rdev = htog(tgt->st_rdev);
+ tgt->st_size = host->st_size;
+ tgt->st_size = htog(tgt->st_size);
+ tgt->st_atimeX = host->st_atime;
+ tgt->st_atimeX = htog(tgt->st_atimeX);
+ tgt->st_mtimeX = host->st_mtime;
+ tgt->st_mtimeX = htog(tgt->st_mtimeX);
+ tgt->st_ctimeX = host->st_ctime;
+ tgt->st_ctimeX = htog(tgt->st_ctimeX);
+ tgt->st_blksize = host->st_blksize;
+ tgt->st_blksize = htog(tgt->st_blksize);
+ tgt->st_blocks = host->st_blocks;
+ tgt->st_blocks = htog(tgt->st_blocks);
+}
+
+// Same for stat64
+
+template <typename target_stat, typename host_stat64>
+static void
+convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
+{
+ convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
+#if defined(STAT_HAVE_NSEC)
+ tgt->st_atime_nsec = host->st_atime_nsec;
+ tgt->st_atime_nsec = htog(tgt->st_atime_nsec);
+ tgt->st_mtime_nsec = host->st_mtime_nsec;
+ tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec);
+ tgt->st_ctime_nsec = host->st_ctime_nsec;
+ tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec);
+#else
+ tgt->st_atime_nsec = 0;
+ tgt->st_mtime_nsec = 0;
+ tgt->st_ctime_nsec = 0;
+#endif
+}
+
+//Here are a couple convenience functions
+template<class OS>
+static void
+copyOutStatBuf(TranslatingPort * mem, Addr addr,
+ hst_stat *host, bool fakeTTY = false)
+{
+ typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
+ tgt_stat_buf tgt(addr);
+ convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
+ tgt.copyOut(mem);
+}
+
+template<class OS>
+static void
+copyOutStat64Buf(TranslatingPort * mem, Addr addr,
+ hst_stat64 *host, bool fakeTTY = false)
+{
+ typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
+ tgt_stat_buf tgt(addr);
+ convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
+ tgt.copyOut(mem);
+}
+
+/// Target ioctl() handler. For the most part, programs call ioctl()
+/// only to find out if their stdout is a tty, to determine whether to
+/// do line or block buffering.
+template <class OS>
+SyscallReturn
+ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+ unsigned req = tc->getSyscallArg(1);
+
+ DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
+
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+ switch (req) {
+ case OS::TIOCISATTY:
+ case OS::TIOCGETP:
+ case OS::TIOCSETP:
+ case OS::TIOCSETN:
+ case OS::TIOCSETC:
+ case OS::TIOCGETC:
+ case OS::TIOCGETS:
+ case OS::TIOCGETA:
+ return -ENOTTY;
+
+ default:
+ fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
+ fd, req, tc->readPC());
+ }
+}
+
+/// Target open() handler.
+template <class OS>
+SyscallReturn
+openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ std::string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ if (path == "/dev/sysdev0") {
+ // This is a memory-mapped high-resolution timer device on Alpha.
+ // We don't support it, so just punt.
+ warn("Ignoring open(%s, ...)\n", path);
+ return -ENOENT;
+ }
+
+ int tgtFlags = tc->getSyscallArg(1);
+ int mode = tc->getSyscallArg(2);
+ int hostFlags = 0;
+
+ // translate open flags
+ for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
+ if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
+ tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
+ hostFlags |= OS::openFlagTable[i].hostFlag;
+ }
+ }
+
+ // any target flags left?
+ if (tgtFlags != 0)
+ warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
+
+#ifdef __CYGWIN32__
+ hostFlags |= O_BINARY;
+#endif
+
+ DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
+
+ // open the file
+ int fd = open(path.c_str(), hostFlags, mode);
+
+ return (fd == -1) ? -errno : process->alloc_fd(fd);
+}
+
+
+/// Target chmod() handler.
+template <class OS>
+SyscallReturn
+chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ std::string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ uint32_t mode = tc->getSyscallArg(1);
+ mode_t hostMode = 0;
+
+ // XXX translate mode flags via OS::something???
+ hostMode = mode;
+
+ // do the chmod
+ int result = chmod(path.c_str(), hostMode);
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+
+
+/// Target fchmod() handler.
+template <class OS>
+SyscallReturn
+fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+ uint32_t mode = tc->getSyscallArg(1);
+ mode_t hostMode = 0;
+
+ // XXX translate mode flags via OS::someting???
+ hostMode = mode;
+
+ // do the fchmod
+ int result = fchmod(process->sim_fd(fd), hostMode);
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+
+
+/// Target stat() handler.
+template <class OS>
+SyscallReturn
+statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ std::string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = stat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+
+/// Target fstat64() handler.
+template <class OS>
+SyscallReturn
+fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+#if NO_STAT64
+ struct stat hostBuf;
+ int result = fstat(process->sim_fd(fd), &hostBuf);
+#else
+ struct stat64 hostBuf;
+ int result = fstat64(process->sim_fd(fd), &hostBuf);
+#endif
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
+ &hostBuf, (fd == 1));
+
+ return 0;
+}
+
+
+/// Target lstat() handler.
+template <class OS>
+SyscallReturn
+lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ std::string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = lstat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+/// Target lstat64() handler.
+template <class OS>
+SyscallReturn
+lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ std::string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+#if NO_STAT64
+ struct stat hostBuf;
+ int result = lstat(path.c_str(), &hostBuf);
+#else
+ struct stat64 hostBuf;
+ int result = lstat64(path.c_str(), &hostBuf);
+#endif
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+/// Target fstat() handler.
+template <class OS>
+SyscallReturn
+fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = process->sim_fd(tc->getSyscallArg(0));
+
+ DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
+
+ if (fd < 0)
+ return -EBADF;
+
+ struct stat hostBuf;
+ int result = fstat(fd, &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
+ &hostBuf, (fd == 1));
+
+ return 0;
+}
+
+
+/// Target statfs() handler.
+template <class OS>
+SyscallReturn
+statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ std::string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ struct statfs hostBuf;
+ int result = statfs(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStatfsBuf(tc->getMemPort(),
+ (Addr)(tc->getSyscallArg(1)), &hostBuf);
+
+ return 0;
+}
+
+
+/// Target fstatfs() handler.
+template <class OS>
+SyscallReturn
+fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = process->sim_fd(tc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ struct statfs hostBuf;
+ int result = fstatfs(fd, &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1),
+ &hostBuf);
+
+ return 0;
+}
+
+
+/// Target writev() handler.
+template <class OS>
+SyscallReturn
+writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+ TranslatingPort *p = tc->getMemPort();
+ uint64_t tiov_base = tc->getSyscallArg(1);
+ size_t count = tc->getSyscallArg(2);
+ struct iovec hiov[count];
+ for (int i = 0; i < count; ++i)
+ {
+ typename OS::tgt_iovec tiov;
+
+ p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
+ (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
+ hiov[i].iov_len = gtoh(tiov.iov_len);
+ hiov[i].iov_base = new char [hiov[i].iov_len];
+ p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
+ hiov[i].iov_len);
+ }
+
+ int result = writev(process->sim_fd(fd), hiov, count);
+
+ for (int i = 0; i < count; ++i)
+ {
+ delete [] (char *)hiov[i].iov_base;
+ }
+
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+
+
+/// Target mmap() handler.
+///
+/// We don't really handle mmap(). If the target is mmaping an
+/// anonymous region or /dev/zero, we can get away with doing basically
+/// nothing (since memory is initialized to zero and the simulator
+/// doesn't really check addresses anyway). Always print a warning,
+/// since this could be seriously broken if we're not mapping
+/// /dev/zero.
+//
+/// Someday we should explicitly check for /dev/zero in open, flag the
+/// file descriptor, and fail (or implement!) a non-anonymous mmap to
+/// anything else.
+template <class OS>
+SyscallReturn
+mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ Addr start = tc->getSyscallArg(0);
+ uint64_t length = tc->getSyscallArg(1);
+ // int prot = tc->getSyscallArg(2);
+ int flags = tc->getSyscallArg(3);
+ // int fd = p->sim_fd(tc->getSyscallArg(4));
+ // int offset = tc->getSyscallArg(5);
+
+ if ((start % TheISA::VMPageSize) != 0 ||
+ (length % TheISA::VMPageSize) != 0) {
+ warn("mmap failing: arguments not page-aligned: "
+ "start 0x%x length 0x%x",
+ start, length);
+ return -EINVAL;
+ }
+
+ if (start != 0) {
+ warn("mmap: ignoring suggested map address 0x%x, using 0x%x",
+ start, p->mmap_end);
+ }
+
+ // pick next address from our "mmap region"
+ start = p->mmap_end;
+ p->pTable->allocate(start, length);
+ p->mmap_end += length;
+
+ if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
+ warn("allowing mmap of file @ fd %d. "
+ "This will break if not /dev/zero.", tc->getSyscallArg(4));
+ }
+
+ return start;
+}
+
+/// Target getrlimit() handler.
+template <class OS>
+SyscallReturn
+getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ unsigned resource = tc->getSyscallArg(0);
+ TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1));
+
+ switch (resource) {
+ case OS::TGT_RLIMIT_STACK:
+ // max stack size in bytes: make up a number (2MB for now)
+ rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
+ rlp->rlim_cur = htog(rlp->rlim_cur);
+ rlp->rlim_max = htog(rlp->rlim_max);
+ break;
+
+ default:
+ std::cerr << "getrlimitFunc: unimplemented resource " << resource
+ << std::endl;
+ abort();
+ break;
+ }
+
+ rlp.copyOut(tc->getMemPort());
+ return 0;
+}
+
+/// Target gettimeofday() handler.
+template <class OS>
+SyscallReturn
+gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0));
+
+ getElapsedTime(tp->tv_sec, tp->tv_usec);
+ tp->tv_sec += seconds_since_epoch;
+ tp->tv_sec = htog(tp->tv_sec);
+ tp->tv_usec = htog(tp->tv_usec);
+
+ tp.copyOut(tc->getMemPort());
+
+ return 0;
+}
+
+
+/// Target utimes() handler.
+template <class OS>
+SyscallReturn
+utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ std::string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1));
+ tp.copyIn(tc->getMemPort());
+
+ struct timeval hostTimeval[2];
+ for (int i = 0; i < 2; ++i)
+ {
+ hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec);
+ hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec);
+ }
+ int result = utimes(path.c_str(), hostTimeval);
+
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+/// Target getrusage() function.
+template <class OS>
+SyscallReturn
+getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN
+ TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1));
+
+ if (who != OS::TGT_RUSAGE_SELF) {
+ // don't really handle THREAD or CHILDREN, but just warn and
+ // plow ahead
+ warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.",
+ who);
+ }
+
+ getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
+ rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
+ rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
+
+ rup->ru_stime.tv_sec = 0;
+ rup->ru_stime.tv_usec = 0;
+ rup->ru_maxrss = 0;
+ rup->ru_ixrss = 0;
+ rup->ru_idrss = 0;
+ rup->ru_isrss = 0;
+ rup->ru_minflt = 0;
+ rup->ru_majflt = 0;
+ rup->ru_nswap = 0;
+ rup->ru_inblock = 0;
+ rup->ru_oublock = 0;
+ rup->ru_msgsnd = 0;
+ rup->ru_msgrcv = 0;
+ rup->ru_nsignals = 0;
+ rup->ru_nvcsw = 0;
+ rup->ru_nivcsw = 0;
+
+ rup.copyOut(tc->getMemPort());
+
+ return 0;
+}
+
+
+
+
+#endif // __SIM_SYSCALL_EMUL_HH__
diff --git a/src/sim/system.cc b/src/sim/system.cc
new file mode 100644
index 000000000..ad70b9b03
--- /dev/null
+++ b/src/sim/system.cc
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Lisa Hsu
+ * Nathan Binkert
+ * Ali Saidi
+ */
+
+#include "arch/isa_traits.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/trace.hh"
+#include "cpu/thread_context.hh"
+#include "mem/mem_object.hh"
+#include "mem/physical.hh"
+#include "sim/builder.hh"
+#include "sim/byteswap.hh"
+#include "sim/system.hh"
+#if FULL_SYSTEM
+#include "arch/vtophys.hh"
+#include "base/remote_gdb.hh"
+#include "kern/kernel_stats.hh"
+#endif
+
+using namespace std;
+using namespace TheISA;
+
+vector<System *> System::systemList;
+
+int System::numSystemsRunning = 0;
+
+System::System(Params *p)
+ : SimObject(p->name), physmem(p->physmem), numcpus(0),
+#if FULL_SYSTEM
+ init_param(p->init_param),
+ functionalPort(p->name + "-fport"),
+ virtPort(p->name + "-vport"),
+#else
+ page_ptr(0),
+#endif
+ memoryMode(p->mem_mode), _params(p)
+{
+ // add self to global system list
+ systemList.push_back(this);
+
+#if FULL_SYSTEM
+ kernelSymtab = new SymbolTable;
+ debugSymbolTable = new SymbolTable;
+
+
+ /**
+ * Get a functional port to memory
+ */
+ Port *mem_port;
+ mem_port = physmem->getPort("functional");
+ functionalPort.setPeer(mem_port);
+ mem_port->setPeer(&functionalPort);
+
+ mem_port = physmem->getPort("functional");
+ virtPort.setPeer(mem_port);
+ mem_port->setPeer(&virtPort);
+
+
+ /**
+ * Load the kernel code into memory
+ */
+ // Load kernel code
+ kernel = createObjectFile(params()->kernel_path);
+ if (kernel == NULL)
+ fatal("Could not load kernel file %s", params()->kernel_path);
+
+ // Load program sections into memory
+ kernel->loadSections(&functionalPort, LoadAddrMask);
+
+ // setup entry points
+ kernelStart = kernel->textBase();
+ kernelEnd = kernel->bssBase() + kernel->bssSize();
+ kernelEntry = kernel->entryPoint();
+
+ // load symbols
+ if (!kernel->loadGlobalSymbols(kernelSymtab))
+ panic("could not load kernel symbols\n");
+
+ if (!kernel->loadLocalSymbols(kernelSymtab))
+ panic("could not load kernel local symbols\n");
+
+ if (!kernel->loadGlobalSymbols(debugSymbolTable))
+ panic("could not load kernel symbols\n");
+
+ if (!kernel->loadLocalSymbols(debugSymbolTable))
+ panic("could not load kernel local symbols\n");
+
+ DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
+ DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);
+ DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
+ DPRINTF(Loader, "Kernel loaded...\n");
+#endif // FULL_SYSTEM
+
+ // increment the number of running systms
+ numSystemsRunning++;
+}
+
+System::~System()
+{
+#if FULL_SYSTEM
+ delete kernelSymtab;
+ delete kernel;
+#else
+ panic("System::fixFuncEventAddr needs to be rewritten "
+ "to work with syscall emulation");
+#endif // FULL_SYSTEM}
+}
+
+#if FULL_SYSTEM
+
+
+int rgdb_wait = -1;
+
+#endif // FULL_SYSTEM
+
+
+void
+System::setMemoryMode(MemoryMode mode)
+{
+ assert(getState() == Drained);
+ memoryMode = mode;
+}
+
+int
+System::registerThreadContext(ThreadContext *tc, int id)
+{
+ if (id == -1) {
+ for (id = 0; id < threadContexts.size(); id++) {
+ if (!threadContexts[id])
+ break;
+ }
+ }
+
+ if (threadContexts.size() <= id)
+ threadContexts.resize(id + 1);
+
+ if (threadContexts[id])
+ panic("Cannot have two CPUs with the same id (%d)\n", id);
+
+ threadContexts[id] = tc;
+ numcpus++;
+
+#if FULL_SYSTEM
+ RemoteGDB *rgdb = new RemoteGDB(this, tc);
+ GDBListener *gdbl = new GDBListener(rgdb, 7000 + id);
+ gdbl->listen();
+ /**
+ * Uncommenting this line waits for a remote debugger to connect
+ * to the simulator before continuing.
+ */
+ if (rgdb_wait != -1 && rgdb_wait == id)
+ gdbl->accept();
+
+ if (remoteGDB.size() <= id) {
+ remoteGDB.resize(id + 1);
+ }
+
+ remoteGDB[id] = rgdb;
+#endif // FULL_SYSTEM
+
+ return id;
+}
+
+void
+System::startup()
+{
+ int i;
+ for (i = 0; i < threadContexts.size(); i++)
+ threadContexts[i]->activate(0);
+}
+
+void
+System::replaceThreadContext(ThreadContext *tc, int id)
+{
+ if (id >= threadContexts.size()) {
+ panic("replaceThreadContext: bad id, %d >= %d\n",
+ id, threadContexts.size());
+ }
+
+ threadContexts[id] = tc;
+#if FULL_SYSTEM
+ remoteGDB[id]->replaceThreadContext(tc);
+#endif // FULL_SYSTEM
+}
+
+#if !FULL_SYSTEM
+Addr
+System::new_page()
+{
+ Addr return_addr = page_ptr << LogVMPageSize;
+ ++page_ptr;
+ return return_addr;
+}
+#endif
+
+void
+System::serialize(ostream &os)
+{
+#if FULL_SYSTEM
+ kernelSymtab->serialize("kernel_symtab", os);
+#endif // FULL_SYSTEM
+}
+
+
+void
+System::unserialize(Checkpoint *cp, const string &section)
+{
+#if FULL_SYSTEM
+ kernelSymtab->unserialize("kernel_symtab", cp, section);
+#endif // FULL_SYSTEM
+}
+
+void
+System::printSystems()
+{
+ vector<System *>::iterator i = systemList.begin();
+ vector<System *>::iterator end = systemList.end();
+ for (; i != end; ++i) {
+ System *sys = *i;
+ cerr << "System " << sys->name() << ": " << hex << sys << endl;
+ }
+}
+
+void
+printSystems()
+{
+ System::printSystems();
+}
+
+const char *System::MemoryModeStrings[3] = {"invalid", "atomic",
+ "timing"};
+
+#if FULL_SYSTEM
+
+// In full system mode, only derived classes (e.g. AlphaLinuxSystem)
+// can be created directly.
+
+DEFINE_SIM_OBJECT_CLASS_NAME("System", System)
+
+#else
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(System)
+
+ SimObjectParam<PhysicalMemory *> physmem;
+ SimpleEnumParam<System::MemoryMode> mem_mode;
+
+END_DECLARE_SIM_OBJECT_PARAMS(System)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(System)
+
+ INIT_PARAM(physmem, "physical memory"),
+ INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)",
+ System::MemoryModeStrings)
+
+END_INIT_SIM_OBJECT_PARAMS(System)
+
+CREATE_SIM_OBJECT(System)
+{
+ System::Params *p = new System::Params;
+ p->name = getInstanceName();
+ p->physmem = physmem;
+ p->mem_mode = mem_mode;
+ return new System(p);
+}
+
+REGISTER_SIM_OBJECT("System", System)
+
+#endif
diff --git a/src/sim/system.hh b/src/sim/system.hh
new file mode 100644
index 000000000..3ab1d81f2
--- /dev/null
+++ b/src/sim/system.hh
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Lisa Hsu
+ * Nathan Binkert
+ */
+
+#ifndef __SYSTEM_HH__
+#define __SYSTEM_HH__
+
+#include <string>
+#include <vector>
+
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/pc_event.hh"
+#include "mem/port.hh"
+#include "sim/sim_object.hh"
+#if FULL_SYSTEM
+#include "kern/system_events.hh"
+#include "mem/vport.hh"
+#endif
+
+class BaseCPU;
+class ThreadContext;
+class ObjectFile;
+class PhysicalMemory;
+
+#if FULL_SYSTEM
+class Platform;
+class GDBListener;
+class RemoteGDB;
+#endif
+
+class System : public SimObject
+{
+ public:
+ enum MemoryMode {
+ Invalid=0,
+ Atomic,
+ Timing
+ };
+
+ static const char *MemoryModeStrings[3];
+
+
+ MemoryMode getMemoryMode() { assert(memoryMode); return memoryMode; }
+
+ /** Change the memory mode of the system. This should only be called by the
+ * python!!
+ * @param mode Mode to change to (atomic/timing)
+ */
+ void setMemoryMode(MemoryMode mode);
+
+ PhysicalMemory *physmem;
+ PCEventQueue pcEventQueue;
+
+ std::vector<ThreadContext *> threadContexts;
+ int numcpus;
+
+ int getNumCPUs()
+ {
+ if (numcpus != threadContexts.size())
+ panic("cpu array not fully populated!");
+
+ return numcpus;
+ }
+
+#if FULL_SYSTEM
+ Platform *platform;
+ uint64_t init_param;
+
+ /** Port to physical memory used for writing object files into ram at
+ * boot.*/
+ FunctionalPort functionalPort;
+ VirtualPort virtPort;
+
+ /** kernel symbol table */
+ SymbolTable *kernelSymtab;
+
+ /** Object pointer for the kernel code */
+ ObjectFile *kernel;
+
+ /** Begining of kernel code */
+ Addr kernelStart;
+
+ /** End of kernel code */
+ Addr kernelEnd;
+
+ /** Entry point in the kernel to start at */
+ Addr kernelEntry;
+
+#else
+
+ int page_ptr;
+
+
+#endif // FULL_SYSTEM
+
+ protected:
+
+ MemoryMode memoryMode;
+
+#if FULL_SYSTEM
+ /**
+ * Fix up an address used to match PCs for hooking simulator
+ * events on to target function executions. See comment in
+ * system.cc for details.
+ */
+ virtual Addr fixFuncEventAddr(Addr addr) = 0;
+
+ /**
+ * Add a function-based event to the given function, to be looked
+ * up in the specified symbol table.
+ */
+ template <class T>
+ T *addFuncEvent(SymbolTable *symtab, const char *lbl)
+ {
+ Addr addr = 0; // initialize only to avoid compiler warning
+
+ if (symtab->findAddress(lbl, addr)) {
+ T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr));
+ return ev;
+ }
+
+ return NULL;
+ }
+
+ /** Add a function-based event to kernel code. */
+ template <class T>
+ T *addKernelFuncEvent(const char *lbl)
+ {
+ return addFuncEvent<T>(kernelSymtab, lbl);
+ }
+
+#endif
+ public:
+#if FULL_SYSTEM
+ std::vector<RemoteGDB *> remoteGDB;
+ std::vector<GDBListener *> gdbListen;
+ virtual bool breakpoint() = 0;
+#endif // FULL_SYSTEM
+
+ public:
+ struct Params
+ {
+ std::string name;
+ PhysicalMemory *physmem;
+ MemoryMode mem_mode;
+
+#if FULL_SYSTEM
+ Tick boot_cpu_frequency;
+ std::string boot_osflags;
+ uint64_t init_param;
+
+ std::string kernel_path;
+ std::string readfile;
+ std::string symbolfile;
+#endif
+ };
+
+ protected:
+ Params *_params;
+
+ public:
+ System(Params *p);
+ ~System();
+
+ void startup();
+
+ const Params *params() const { return (const Params *)_params; }
+
+ public:
+
+#if FULL_SYSTEM
+ /**
+ * Returns the addess the kernel starts at.
+ * @return address the kernel starts at
+ */
+ Addr getKernelStart() const { return kernelStart; }
+
+ /**
+ * Returns the addess the kernel ends at.
+ * @return address the kernel ends at
+ */
+ Addr getKernelEnd() const { return kernelEnd; }
+
+ /**
+ * Returns the addess the entry point to the kernel code.
+ * @return entry point of the kernel code
+ */
+ Addr getKernelEntry() const { return kernelEntry; }
+
+#else
+
+ Addr new_page();
+
+#endif // FULL_SYSTEM
+
+ int registerThreadContext(ThreadContext *tc, int tcIndex);
+ void replaceThreadContext(ThreadContext *tc, int tcIndex);
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ public:
+ ////////////////////////////////////////////
+ //
+ // STATIC GLOBAL SYSTEM LIST
+ //
+ ////////////////////////////////////////////
+
+ static std::vector<System *> systemList;
+ static int numSystemsRunning;
+
+ static void printSystems();
+
+
+};
+
+#endif // __SYSTEM_HH__
diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh
new file mode 100644
index 000000000..bcc22f0ca
--- /dev/null
+++ b/src/sim/vptr.hh
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __ARCH_ALPHA_VPTR_HH__
+#define __ARCH_ALPHA_VPTR_HH__
+
+#include "arch/vtophys.hh"
+#include "arch/isa_traits.hh"
+
+class ThreadContext;
+
+template <class T>
+class VPtr
+{
+ public:
+ typedef T Type;
+
+ private:
+ ThreadContext *tc;
+ Addr ptr;
+
+ public:
+ ThreadContext *GetTC() const { return tc; }
+ Addr GetPointer() const { return ptr; }
+
+ public:
+ explicit VPtr(ThreadContext *_tc, Addr p = 0) : tc(_tc), ptr(p) { }
+ template <class U>
+ VPtr(const VPtr<U> &vp) : tc(vp.GetTC()), ptr(vp.GetPointer()) {}
+ ~VPtr() {}
+
+ bool operator!() const
+ {
+ return ptr == 0;
+ }
+
+ VPtr<T> operator+(int offset)
+ {
+ VPtr<T> ptr(*this);
+ ptr += offset;
+
+ return ptr;
+ }
+
+ const VPtr<T> &operator+=(int offset)
+ {
+ ptr += offset;
+ assert((ptr & (TheISA::PageBytes - 1)) + sizeof(T)
+ < TheISA::PageBytes);
+
+ return *this;
+ }
+
+ const VPtr<T> &operator=(Addr p)
+ {
+ assert((p & (TheISA::PageBytes - 1)) + sizeof(T)
+ < TheISA::PageBytes);
+ ptr = p;
+
+ return *this;
+ }
+
+ template <class U>
+ const VPtr<T> &operator=(const VPtr<U> &vp)
+ {
+ tc = vp.GetTC();
+ ptr = vp.GetPointer();
+
+ return *this;
+ }
+
+ operator T *()
+ {
+ panic("Needs to be rewritten\n");
+/* void *addr = vtomem(tc, ptr, sizeof(T));
+ return (T *)addr;
+ */
+ }
+
+ T *operator->()
+ {
+ panic("Needs to be rewritten\n");
+/* void *addr = vtomem(tc, ptr, sizeof(T));
+ return (T *)addr;
+ */
+ }
+
+ T &operator*()
+ {
+ panic("Needs to be rewritten\n");
+/* void *addr = vtomem(tc, ptr, sizeof(T));
+ return *(T *)addr;
+ */
+ }
+};
+
+#endif // __ARCH_ALPHA_VPTR_HH__