summaryrefslogtreecommitdiff
path: root/sim
diff options
context:
space:
mode:
Diffstat (limited to 'sim')
-rw-r--r--sim/builder.cc66
-rw-r--r--sim/builder.hh46
-rw-r--r--sim/eventq.hh34
-rw-r--r--sim/main.cc246
-rw-r--r--sim/param.cc63
-rw-r--r--sim/param.hh9
-rw-r--r--sim/process.cc68
-rw-r--r--sim/process.hh15
-rw-r--r--sim/pyconfig/SConscript195
-rw-r--r--sim/pyconfig/m5config.py1303
-rw-r--r--sim/pyconfig/m5configbase.py723
-rw-r--r--sim/serialize.cc8
-rw-r--r--sim/startup.cc24
-rw-r--r--sim/syscall_emul.cc41
-rw-r--r--sim/syscall_emul.hh138
-rw-r--r--sim/universe.cc123
16 files changed, 1909 insertions, 1193 deletions
diff --git a/sim/builder.cc b/sim/builder.cc
index fa5c113a7..011694797 100644
--- a/sim/builder.cc
+++ b/sim/builder.cc
@@ -39,14 +39,9 @@
using namespace std;
-SimObjectBuilder::SimObjectBuilder(const string &_configClass,
- const string &_instanceName,
- ConfigNode *_configNode,
- const string &_simObjClassName)
- : ParamContext(_configClass, NoAutoInit),
- instanceName(_instanceName),
- configNode(_configNode),
- simObjClassName(_simObjClassName)
+SimObjectBuilder::SimObjectBuilder(ConfigNode *_configNode)
+ : ParamContext(_configNode->getPath(), NoAutoInit),
+ configNode(_configNode)
{
}
@@ -72,13 +67,8 @@ SimObjectBuilder::parseParams(IniFile &iniFile)
for (i = paramList->begin(); i != paramList->end(); ++i) {
string string_value;
-
- if (iniFile.findDefault(instanceName, (*i)->name, string_value)) {
- (*i)->parse(string_value);
- }
- else if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
+ if (iniFile.find(iniSection, (*i)->name, string_value))
(*i)->parse(string_value);
- }
}
}
@@ -86,9 +76,8 @@ SimObjectBuilder::parseParams(IniFile &iniFile)
void
SimObjectBuilder::printErrorProlog(ostream &os)
{
- os << "Error creating object '" << getInstanceName()
- << "' of type '" << simObjClassName
- << "', section '" << iniSection << "':" << endl;
+ ccprintf(os, "Error creating object '%s' of type '%s':\n",
+ iniSection, configNode->getType());
}
@@ -111,11 +100,7 @@ SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc)
classMap = new map<string,SimObjectClass::CreateFunc>();
if ((*classMap)[className])
- {
- cerr << "Error: simulation object class " << className << " redefined"
- << endl;
- fatal("");
- }
+ panic("Error: simulation object class '%s' redefined\n", className);
// add className --> createFunc to class map
(*classMap)[className] = createFunc;
@@ -125,35 +110,20 @@ SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc)
//
//
SimObject *
-SimObjectClass::createObject(IniFile &configDB,
- const string &configClassName,
- const string &objName,
- ConfigNode *configNode)
+SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode)
{
- // find simulation object class name from configuration class
- // (specified by 'type=' parameter)
- string simObjClassName;
-
- if (!configNode->find("type", simObjClassName)) {
- cerr << "Configuration class '" << configClassName << "' not found."
- << endl;
- abort();
- }
+ const string &type = configNode->getType();
// look up className to get appropriate createFunc
- if (classMap->find(simObjClassName) == classMap->end()) {
- cerr << "Simulator object class '" << simObjClassName << "' not found."
- << endl;
- abort();
- }
+ if (classMap->find(type) == classMap->end())
+ panic("Simulator object type '%s' not found.\n", type);
+
- CreateFunc createFunc = (*classMap)[simObjClassName];
+ CreateFunc createFunc = (*classMap)[type];
// call createFunc with config hierarchy node to get object
// builder instance (context with parameters for object creation)
- SimObjectBuilder *objectBuilder = (*createFunc)(configClassName,
- objName, configNode,
- simObjClassName);
+ SimObjectBuilder *objectBuilder = (*createFunc)(configNode);
assert(objectBuilder != NULL);
@@ -167,10 +137,10 @@ SimObjectClass::createObject(IniFile &configDB,
// echo object parameters to stats file (for documenting the
// config used to generate the associated stats)
- *configStream << "[" << object->name() << "]" << endl;
- *configStream << "type=" << simObjClassName << endl;
+ ccprintf(*configStream, "[%s]\n", object->name());
+ ccprintf(*configStream, "type=%s\n", type);
objectBuilder->showParams(*configStream);
- *configStream << endl;
+ ccprintf(*configStream, "\n");
// done with the SimObjectBuilder now
delete objectBuilder;
@@ -194,7 +164,7 @@ SimObjectClass::describeAllClasses(ostream &os)
os << "[" << className << "]\n";
// create dummy object builder just to instantiate parameters
- SimObjectBuilder *objectBuilder = (*createFunc)("", "", NULL, "");
+ SimObjectBuilder *objectBuilder = (*createFunc)(NULL);
// now get the object builder to describe ite params
objectBuilder->describeParams(os);
diff --git a/sim/builder.hh b/sim/builder.hh
index 36e40c2a9..f6b7b1a1f 100644
--- a/sim/builder.hh
+++ b/sim/builder.hh
@@ -54,22 +54,13 @@ class SimObject;
class SimObjectBuilder : public ParamContext
{
private:
- // name of the instance we are creating
- std::string instanceName;
-
// The corresponding node in the configuration hierarchy.
// (optional: may be null if the created object is not in the
// hierarchy)
ConfigNode *configNode;
- // The external SimObject class name (for error messages)
- std::string simObjClassName;
-
public:
- SimObjectBuilder(const std::string &_configClass,
- const std::string &_instanceName,
- ConfigNode *_configNode,
- const std::string &_simObjClassName);
+ SimObjectBuilder(ConfigNode *_configNode);
virtual ~SimObjectBuilder();
@@ -82,7 +73,7 @@ class SimObjectBuilder : public ParamContext
// generate the name for this SimObject instance (derived from the
// configuration hierarchy node label and position)
- virtual const std::string &getInstanceName() { return instanceName; }
+ virtual const std::string &getInstanceName() { return iniSection; }
// return the configuration hierarchy node for this context.
virtual ConfigNode *getConfigNode() { return configNode; }
@@ -132,10 +123,7 @@ class SimObjectClass
// 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 &configClassName,
- const std::string &objName,
- ConfigNode *configNode,
- const std::string &simObjClassName);
+ typedef SimObjectBuilder *(*CreateFunc)(ConfigNode *configNode);
static std::map<std::string,CreateFunc> *classMap;
@@ -147,10 +135,7 @@ class SimObjectClass
// create SimObject given name of class and pointer to
// configuration hierarchy node
- static SimObject *createObject(IniFile &configDB,
- const std::string &configClassName,
- const std::string &objName,
- ConfigNode *configNode);
+ static SimObject *createObject(IniFile &configDB, ConfigNode *configNode);
// print descriptions of all parameters registered with all
// SimObject classes
@@ -169,22 +154,15 @@ class OBJ_CLASS##Builder : public SimObjectBuilder \
#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
\
- OBJ_CLASS##Builder(const std::string &configClass, \
- const std::string &instanceName, \
- ConfigNode *configNode, \
- const std::string &simObjClassName); \
+ OBJ_CLASS##Builder(ConfigNode *configNode); \
virtual ~OBJ_CLASS##Builder() {} \
\
OBJ_CLASS *create(); \
};
-#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
-OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &configClass, \
- const std::string &instanceName, \
- ConfigNode *configNode, \
- const std::string &simObjClassName) \
- : SimObjectBuilder(configClass, instanceName, \
- configNode, simObjClassName),
+#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+OBJ_CLASS##Builder::OBJ_CLASS##Builder(ConfigNode *configNode) \
+ : SimObjectBuilder(configNode),
#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
@@ -196,13 +174,9 @@ OBJ_CLASS *OBJ_CLASS##Builder::create()
#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \
SimObjectBuilder * \
-new##OBJ_CLASS##Builder(const std::string &configClass, \
- const std::string &instanceName, \
- ConfigNode *configNode, \
- const std::string &simObjClassName) \
+new##OBJ_CLASS##Builder(ConfigNode *configNode) \
{ \
- return new OBJ_CLASS##Builder(configClass, instanceName, \
- configNode, simObjClassName); \
+ return new OBJ_CLASS##Builder(configNode); \
} \
\
SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
diff --git a/sim/eventq.hh b/sim/eventq.hh
index 304e4b16a..d62e7df10 100644
--- a/sim/eventq.hh
+++ b/sim/eventq.hh
@@ -30,8 +30,8 @@
* EventQueue interfaces
*/
-#ifndef __EVENTQ_HH__
-#define __EVENTQ_HH__
+#ifndef __SIM_EVENTQ_HH__
+#define __SIM_EVENTQ_HH__
#include <assert.h>
@@ -43,11 +43,24 @@
#include "sim/host.hh" // for Tick
#include "base/fast_alloc.hh"
-#include "sim/serialize.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
@@ -228,7 +241,7 @@ DelayFunction(Tick when, T *object)
public:
DelayEvent(Tick when, T *o)
: Event(&mainEventQueue), object(o)
- { setFlags(AutoDestroy); schedule(when); }
+ { setFlags(this->AutoDestroy); schedule(when); }
void process() { (object->*F)(); }
const char *description() { return "delay"; }
};
@@ -386,16 +399,5 @@ EventQueue::reschedule(Event *event)
}
-//////////////////////
-//
-// 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;
-#endif // __EVENTQ_HH__
+#endif // __SIM_EVENTQ_HH__
diff --git a/sim/main.cc b/sim/main.cc
index e8ac58786..c15d24453 100644
--- a/sim/main.cc
+++ b/sim/main.cc
@@ -31,17 +31,23 @@
///
#include <sys/types.h>
#include <sys/stat.h>
+#include <errno.h>
+#include <libgen.h>
#include <stdlib.h>
#include <signal.h>
+#include <list>
#include <string>
#include <vector>
#include "base/copyright.hh"
+#include "base/embedfile.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_cpu.hh"
#include "cpu/full_cpu/smt.hh"
@@ -103,28 +109,35 @@ abortHandler(int sigtype)
}
/// Simulator executable name
-const char *myProgName = "";
+char *myProgName = "";
/// Show brief help message.
-static void
+void
showBriefHelp(ostream &out)
{
- out << "Usage: " << myProgName
- << " [-hnu] [-Dname[=def]] [-Uname] [-I[dir]] "
- << "<config-spec> [<config-spec> ...]\n"
- << "[] [<config file> ...]\n"
- << " -h: print long help (including parameter listing)\n"
- << " -u: don't quit on unreferenced parameters\n"
- << " -D,-U,-I: passed to cpp for preprocessing .ini files\n"
- << " <config-spec>: config file name (.ini or .py) or\n"
- << " single param (--<section>:<param>=<value>)"
- << endl;
+ char *prog = basename(myProgName);
+
+ ccprintf(out, "Usage:\n");
+ ccprintf(out,
+"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n"
+" [--<var>=<val>] <config file>\n"
+"\n"
+" -d set the output directory to <dir>\n"
+" -E set the environment variable <var> to <val> (or 'True')\n"
+" -I add the directory <dir> to python's path\n"
+" -P execute <python> directly in the configuration\n"
+" --var=val set the python variable <var> to '<val>'\n"
+" <configfile> config file name (.py or .mpy)\n",
+ prog);
+
+ ccprintf(out, "%s -X\n -X extract embedded files\n", prog);
+ ccprintf(out, "%s -h\n -h print long help\n", prog);
}
/// Show verbose help message. Includes parameter listing from
/// showBriefHelp(), plus an exhaustive list of ini-file parameters
/// and SimObjects (with their parameters).
-static void
+void
showLongHelp(ostream &out)
{
showBriefHelp(out);
@@ -149,7 +162,7 @@ showLongHelp(ostream &out)
}
/// Print welcome message.
-static void
+void
sayHello(ostream &out)
{
extern const char *compileDate; // from date.cc
@@ -173,7 +186,7 @@ sayHello(ostream &out)
/// Echo the command line for posterity in such a way that it can be
/// used to rerun the same simulation (given the same .ini files).
///
-static void
+void
echoCommandLine(int argc, char **argv, ostream &out)
{
out << "command line: " << argv[0];
@@ -205,16 +218,20 @@ echoCommandLine(int argc, char **argv, ostream &out)
out << endl << endl;
}
+char *
+getOptionString(int &index, int argc, char **argv)
+{
+ char *option = argv[index] + 2;
+ if (*option != '\0')
+ return option;
-///
-/// The simulator configuration database. This is the union of all
-/// specified .ini files. This shouldn't need to be visible outside
-/// this file, as it is passed as a parameter to all the param-parsing
-/// routines.
-///
-static IniFile simConfigDB;
+ // We didn't find an argument, it must be in the next variable.
+ if (++index >= argc)
+ panic("option string for option '%s' not found", argv[index - 1]);
+
+ return argv[index];
+}
-/// M5 entry point.
int
main(int argc, char **argv)
{
@@ -230,16 +247,9 @@ main(int argc, char **argv)
sayHello(cerr);
- // Initialize statistics database
- Stats::InitSimStats();
-
- vector<char *> cppArgs;
-
- // Should we quit if there are unreferenced parameters? By
- // default, yes... it's a good way of catching typos in
- // section/parameter names (which otherwise go by silently). Use
- // -u to override.
- bool quitOnUnreferenced = true;
+ bool configfile_found = false;
+ PythonConfig pyconfig;
+ string outdir;
// Parse command-line options.
// Since most of the complex options are handled through the
@@ -248,107 +258,126 @@ main(int argc, char **argv)
for (int i = 1; i < argc; ++i) {
char *arg_str = argv[i];
- // if arg starts with '-', parse as option,
- // else treat it as a configuration file name and load it
- if (arg_str[0] == '-') {
+ // if arg starts with '--', parse as a special python option
+ // of the format --<python var>=<string value>, if the arg
+ // starts with '-', it should be a simulator option with a
+ // format similar to getopt. In any other case, treat the
+ // option as a configuration file name and load it.
+ if (arg_str[0] == '-' && arg_str[1] == '-') {
+ string str = &arg_str[2];
+ string var, val;
+
+ if (!split_first(str, var, val, '='))
+ panic("Could not parse configuration argument '%s'\n"
+ "Expecting --<variable>=<value>\n", arg_str);
+
+ pyconfig.setVariable(var, val);
+ } else if (arg_str[0] == '-') {
+ char *option;
+ string var, val;
// switch on second char
switch (arg_str[1]) {
+ case 'd':
+ outdir = getOptionString(i, argc, argv);
+ break;
+
case 'h':
- // -h: show help
showLongHelp(cerr);
exit(1);
- case 'u':
- // -u: don't quit on unreferenced parameters
- quitOnUnreferenced = false;
+ case 'E':
+ option = getOptionString(i, argc, argv);
+ if (!split_first(option, var, val, '='))
+ val = "True";
+
+ if (setenv(var.c_str(), val.c_str(), true) == -1)
+ panic("setenv: %s\n", strerror(errno));
break;
- case 'D':
- case 'U':
case 'I':
- // cpp options: record & pass to cpp. Note that these
- // cannot have spaces, i.e., '-Dname=val' is OK, but
- // '-D name=val' is not. I don't consider this a
- // problem, since even though gnu cpp accepts the
- // latter, other cpp implementations do not (Tru64,
- // for one).
- cppArgs.push_back(arg_str);
+ option = getOptionString(i, argc, argv);
+ pyconfig.addPath(option);
break;
- case '-':
- // command-line configuration parameter:
- // '--<section>:<parameter>=<value>'
- if (!simConfigDB.add(arg_str + 2)) {
- // parse error
- ccprintf(cerr,
- "Could not parse configuration argument '%s'\n"
- "Expecting --<section>:<parameter>=<value>\n",
- arg_str);
- exit(0);
- }
+ case 'P':
+ option = getOptionString(i, argc, argv);
+ pyconfig.writeLine(option);
break;
+ case 'X': {
+ list<EmbedFile> lst;
+ EmbedMap::all(lst);
+ list<EmbedFile>::iterator i = lst.begin();
+ list<EmbedFile>::iterator end = lst.end();
+
+ while (i != end) {
+ cprintf("Embedded File: %s\n", i->name);
+ cout.write(i->data, i->length);
+ ++i;
+ }
+
+ return 0;
+ }
+
default:
showBriefHelp(cerr);
- ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str);
- exit(0);
- }
- }
- else {
- // no '-', treat as config file name
-
- // make STL string out of file name
- string filename(arg_str);
-
- int ext_loc = filename.rfind(".");
-
- string ext =
- (ext_loc != string::npos) ? filename.substr(ext_loc) : "";
-
- if (ext == ".ini") {
- if (!simConfigDB.loadCPP(filename, cppArgs)) {
- cprintf("Error processing file %s\n", filename);
- exit(1);
- }
- } else if (ext == ".py") {
- if (!loadPythonConfig(filename, &simConfigDB)) {
- cprintf("Error processing file %s\n", filename);
- exit(1);
- }
- }
- else {
- cprintf("Config file name '%s' must end in '.py' or '.ini'.\n",
- filename);
- exit(1);
+ panic("invalid argument '%s'\n", arg_str);
}
+ } else {
+ string file(arg_str);
+ string base, ext;
+
+ if (!split_last(file, base, ext, '.') ||
+ ext != "py" && ext != "mpy")
+ panic("Config file '%s' must end in '.py' or '.mpy'\n", file);
+
+ pyconfig.load(file);
+ configfile_found = true;
}
}
+ if (outdir.empty()) {
+ char *env = getenv("OUTPUT_DIR");
+ outdir = env ? env : ".";
+ }
+
+ simout.setDirectory(outdir);
+
+ char *env = getenv("CONFIG_OUTPUT");
+ if (!env)
+ env = "config.out";
+ configStream = simout.find(env);
+
+ if (!configfile_found)
+ panic("no configuration file specified!");
+
// The configuration database is now complete; start processing it.
+ IniFile inifile;
+ if (!pyconfig.output(inifile))
+ panic("Error processing python code");
+
+ // Initialize statistics database
+ Stats::InitSimStats();
+
+ // Now process the configuration hierarchy and create the SimObjects.
+ ConfigHierarchy configHierarchy(inifile);
+ configHierarchy.build();
+ configHierarchy.createSimObjects();
// Parse and check all non-config-hierarchy parameters.
- ParamContext::parseAllContexts(simConfigDB);
+ ParamContext::parseAllContexts(inifile);
ParamContext::checkAllContexts();
- // Print header info into stats file. Can't do this sooner since
- // the stat file name is set via a .ini param... thus it just got
- // opened above during ParamContext::checkAllContexts().
-
// Print hello message to stats file if it's actually a file. If
// it's not (i.e. it's cout or cerr) then we already did it above.
- if (outputStream != &cout && outputStream != &cerr)
+ if (simout.isFile(*outputStream))
sayHello(*outputStream);
// Echo command line and all parameter settings to stats file as well.
echoCommandLine(argc, argv, *outputStream);
ParamContext::showAllContexts(*configStream);
- // Now process the configuration hierarchy and create the SimObjects.
- ConfigHierarchy configHierarchy(simConfigDB);
- configHierarchy.build();
- configHierarchy.createSimObjects();
-
// Do a second pass to finish initializing the sim objects
SimObject::initAll();
@@ -357,13 +386,8 @@ main(int argc, char **argv)
// Done processing the configuration database.
// Check for unreferenced entries.
- if (simConfigDB.printUnreferenced() && quitOnUnreferenced) {
- cerr << "Fatal: unreferenced .ini sections/entries." << endl
- << "If this is not an error, add 'unref_section_ok=y' or "
- << "'unref_entries_ok=y' to the appropriate sections "
- << "to suppress this message." << endl;
- exit(1);
- }
+ if (inifile.printUnreferenced())
+ panic("unreferenced sections/entries in the intermediate ini file");
SimObject::regAllStats();
@@ -378,12 +402,6 @@ main(int argc, char **argv)
// Reset to put the stats in a consistent state.
Stats::reset();
- // Nothing to simulate if we don't have at least one CPU somewhere.
- if (BaseCPU::numSimulatedCPUs() == 0) {
- cerr << "Fatal: no CPUs to simulate." << endl;
- exit(1);
- }
-
warn("Entering event queue. Starting simulation...\n");
SimStartup();
while (!mainEventQueue.empty()) {
diff --git a/sim/param.cc b/sim/param.cc
index d20be8d33..ff023ce85 100644
--- a/sim/param.cc
+++ b/sim/param.cc
@@ -27,21 +27,21 @@
*/
#include <algorithm>
+#include <cassert>
+#include <cstdio>
#include <list>
#include <string>
#include <vector>
-#include <stdio.h> // for sscanf()
-#include <assert.h>
-
-#include "sim/param.hh"
-#include "sim/sim_object.hh"
#include "base/inifile.hh"
-#include "sim/configfile.hh"
-#include "sim/config_node.hh"
#include "base/misc.hh"
+#include "base/range.hh"
#include "base/str.hh"
#include "base/trace.hh"
+#include "sim/config_node.hh"
+#include "sim/configfile.hh"
+#include "sim/param.hh"
+#include "sim/sim_object.hh"
using namespace std;
@@ -180,6 +180,22 @@ parseParam(const string &s, string &value)
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()
@@ -310,6 +326,9 @@ 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
//
@@ -422,6 +441,11 @@ EnumVectorParam<Map>::parse(const string &s)
{
vector<string> tokens;
+ if (s.empty()) {
+ wasSet = true;
+ return;
+ }
+
tokenize(tokens, s, ' ');
value.resize(tokens.size());
@@ -474,11 +498,11 @@ EnumVectorParam<Map>::showType(ostream &os) const
showEnumType(os, map, num_values);
}
-template EnumParam<const char *>;
-template EnumVectorParam<const char *>;
+template class EnumParam<const char *>;
+template class EnumVectorParam<const char *>;
-template EnumParam<EnumParamMap>;
-template EnumVectorParam<EnumParamMap>;
+template class EnumParam<EnumParamMap>;
+template class EnumVectorParam<EnumParamMap>;
////////////////////////////////////////////////////////////////////////
//
@@ -602,9 +626,8 @@ ParamContext::parseParams(IniFile &iniFile)
for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
string string_value;
- if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
+ if (iniFile.find(iniSection, (*i)->name, string_value))
(*i)->parse(string_value);
- }
}
}
@@ -680,18 +703,8 @@ ParamContext::printErrorProlog(ostream &os)
// SimObjectBuilder objects, which return non-NULL for configNode()).
//
SimObject *
-ParamContext::resolveSimObject(const string &_name)
-{
- // look for a colon
- string::size_type i = _name.find(':');
- string name = _name;
- if (i != string::npos) {
- // colon found: local object
- // add as child to current node and create it
- name = _name.substr(0, i);
- string objConfigClassName = _name.substr(i + 1);
- getConfigNode()->addChild(name, objConfigClassName);
- }
+ParamContext::resolveSimObject(const string &name)
+{
ConfigNode *n = getConfigNode();
return n ? n->resolveSimObject(name) : NULL;
}
diff --git a/sim/param.hh b/sim/param.hh
index ac57afa31..f4b9d3450 100644
--- a/sim/param.hh
+++ b/sim/param.hh
@@ -26,9 +26,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __PARAM_HH__
-#define __PARAM_HH__
+#ifndef __SIM_PARAM_HH__
+#define __SIM_PARAM_HH__
+#include <iostream>
#include <list>
#include <string>
#include <vector>
@@ -524,7 +525,7 @@ class MappedEnumParam : public EnumParam<EnumParamMap>
{
if (!isValid())
die("not found");
- return (ENUM)value[n];
+ return (ENUM)value[this->n];
}
};
@@ -782,4 +783,4 @@ SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \
template <class T> bool parseParam(const std::string &str, T &data);
template <class T> void showParam(std::ostream &os, const T &data);
-#endif // _PARAM_HH
+#endif // _SIM_PARAM_HH_
diff --git a/sim/process.cc b/sim/process.cc
index bd1a2d8fd..7111e8733 100644
--- a/sim/process.cc
+++ b/sim/process.cc
@@ -65,14 +65,14 @@ using namespace std;
// current number of allocated processes
int num_processes = 0;
-Process::Process(const string &name,
+Process::Process(const string &nm,
int stdin_fd, // initial I/O descriptors
int stdout_fd,
int stderr_fd)
- : SimObject(name)
+ : SimObject(nm)
{
// allocate memory space
- memory = new MainMemory(name + ".MainMem");
+ memory = new MainMemory(nm + ".MainMem");
// allocate initial register file
init_regs = new RegFile;
@@ -88,8 +88,7 @@ Process::Process(const string &name,
fd_map[i] = -1;
}
- num_syscalls = 0;
-
+ mmap_start = mmap_end = 0;
// other parameters will be initialized when the program is loaded
}
@@ -145,21 +144,28 @@ Process::registerExecContext(ExecContext *xc)
execContexts.push_back(xc);
if (myIndex == 0) {
- // first exec context for this process... initialize & enable
-
// copy process's initial regs struct
xc->regs = *init_regs;
-
- // mark this context as active.
- // activate with zero delay so that we start ticking right
- // away on cycle 0
- xc->activate(0);
}
// return CPU number to caller and increment available CPU count
return myIndex;
}
+void
+Process::startup()
+{
+ if (execContexts.empty())
+ return;
+
+ // first exec context for this process... initialize & enable
+ ExecContext *xc = execContexts[0];
+
+ // mark this context as active.
+ // activate with zero delay so that we start ticking right
+ // away on cycle 0
+ xc->activate(0);
+}
void
Process::replaceExecContext(ExecContext *xc, int xcIndex)
@@ -247,10 +253,10 @@ copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
memory->access(Write, array_ptr, &data_ptr, sizeof(Addr));
}
-LiveProcess::LiveProcess(const string &name, ObjectFile *objFile,
+LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile,
int stdin_fd, int stdout_fd, int stderr_fd,
vector<string> &argv, vector<string> &envp)
- : Process(name, stdin_fd, stdout_fd, stderr_fd)
+ : Process(nm, stdin_fd, stdout_fd, stderr_fd)
{
prog_fname = argv[0];
@@ -282,7 +288,7 @@ LiveProcess::LiveProcess(const string &name, ObjectFile *objFile,
// Set up region for mmaps. Tru64 seems to start just above 0 and
// grow up from there.
- mmap_base = 0x10000;
+ mmap_start = mmap_end = 0x10000;
// Set pointer for next thread stack. Reserve 8M for main stack.
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
@@ -334,7 +340,7 @@ LiveProcess::LiveProcess(const string &name, ObjectFile *objFile,
LiveProcess *
-LiveProcess::create(const string &name,
+LiveProcess::create(const string &nm,
int stdin_fd, int stdout_fd, int stderr_fd,
vector<string> &argv, vector<string> &envp)
{
@@ -348,13 +354,13 @@ LiveProcess::create(const string &name,
if (objFile->getArch() == ObjectFile::Alpha) {
switch (objFile->getOpSys()) {
case ObjectFile::Tru64:
- process = new AlphaTru64Process(name, objFile,
+ process = new AlphaTru64Process(nm, objFile,
stdin_fd, stdout_fd, stderr_fd,
argv, envp);
break;
case ObjectFile::Linux:
- process = new AlphaLinuxProcess(name, objFile,
+ process = new AlphaLinuxProcess(nm, objFile,
stdin_fd, stdout_fd, stderr_fd,
argv, envp);
break;
@@ -397,19 +403,29 @@ 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 = input.isValid() ? Process::openInputFile(input) : 0;
- int stdout_fd = output.isValid() ? Process::openOutputFile(output) : 1;
- int stderr_fd = output.isValid() ? stdout_fd : 2;
+ int stdin_fd, stdout_fd, stderr_fd;
- // dummy for default env
- vector<string> null_vec;
+ 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(),
stdin_fd, stdout_fd, stderr_fd,
- cmd,
- env.isValid() ? env : null_vec);
+ cmd, env);
}
-
REGISTER_SIM_OBJECT("LiveProcess", LiveProcess)
diff --git a/sim/process.hh b/sim/process.hh
index bb4829875..1ab43cd62 100644
--- a/sim/process.hh
+++ b/sim/process.hh
@@ -42,6 +42,7 @@
#include "sim/sim_object.hh"
#include "sim/stats.hh"
#include "base/statistics.hh"
+#include "base/trace.hh"
class ExecContext;
class FunctionalMemory;
@@ -93,7 +94,8 @@ class Process : public SimObject
Addr next_thread_stack_base;
// Base of region for mmaps (when user doesn't specify an address).
- Addr mmap_base;
+ Addr mmap_start;
+ Addr mmap_end;
std::string prog_fname; // file name
Addr prog_entry; // entry point (initial PC)
@@ -103,11 +105,13 @@ class Process : public SimObject
protected:
// constructor
- Process(const std::string &name,
+ Process(const std::string &nm,
int stdin_fd, // initial I/O descriptors
int stdout_fd,
int stderr_fd);
+ // post initialization startup
+ virtual void startup();
protected:
FunctionalMemory *memory;
@@ -156,7 +160,8 @@ class Process : public SimObject
{
return ((data_base <= addr && addr < brk_point) ||
((stack_base - 16*1024*1024) <= addr && addr < stack_base) ||
- (text_base <= addr && addr < (text_base + text_size)));
+ (text_base <= addr && addr < (text_base + text_size)) ||
+ (mmap_start <= addr && addr < mmap_end));
}
virtual void syscall(ExecContext *xc) = 0;
@@ -171,7 +176,7 @@ class ObjectFile;
class LiveProcess : public Process
{
protected:
- LiveProcess(const std::string &name, ObjectFile *objFile,
+ LiveProcess(const std::string &nm, ObjectFile *objFile,
int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &argv,
std::vector<std::string> &envp);
@@ -180,7 +185,7 @@ class LiveProcess : public Process
// 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 &name,
+ static LiveProcess *create(const std::string &nm,
int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &argv,
std::vector<std::string> &envp);
diff --git a/sim/pyconfig/SConscript b/sim/pyconfig/SConscript
index 7661e7603..2799ef64f 100644
--- a/sim/pyconfig/SConscript
+++ b/sim/pyconfig/SConscript
@@ -1,6 +1,6 @@
# -*- mode:python -*-
-# Copyright (c) 2004 The Regents of The University of Michigan
+# Copyright (c) 2005 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -26,25 +26,190 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import os
+import os, os.path, re
-Import('env', 'obj_desc_files')
+def WriteEmbeddedPyFile(target, source, path, name, ext, filename):
+ if isinstance(source, str):
+ source = file(source, 'r')
-my_obj_desc_files = map(lambda x: '../../' + x, obj_desc_files)
+ if isinstance(target, str):
+ target = file(target, 'w')
-env.Command('m5odescs.py', my_obj_desc_files,
- '$TARGET.srcdir/load_odescs.py $_CPPDEFFLAGS $SOURCES $TARGET')
+ print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \
+ (`path`, `name`, `ext`, `filename`)
-# Python modules to encapsulate
-string_module_bases = Split('m5config m5configbase m5odescs')
-string_modules = map(lambda x: x + '_as_string.py', string_module_bases)
+ for line in source:
+ line = line
+ # escape existing backslashes
+ line = line.replace('\\', '\\\\')
+ # escape existing triple quotes
+ line = line.replace("'''", r"\'\'\'")
-for m in string_module_bases:
- env.Command(m + '_as_string.py', m + '.py',
- '$TARGET.srcdir/make_string_module.py $SOURCE $TARGET')
+ print >>target, line,
-embedded_py_files = Split('string_importer.py') + string_modules
+ print >>target, "''')"
+ print >>target
-env.Command('code.cc', embedded_py_files,
- '$TARGET.srcdir/make_c_file.py pyconfig_code $SOURCES $TARGET')
+def WriteCFile(target, source, name):
+ if isinstance(source, str):
+ source = file(source, 'r')
+ if isinstance(target, str):
+ target = file(target, 'w')
+
+ print >>target, 'const char %s_string[] = {' % name
+
+ count = 0
+ from array import array
+ try:
+ while True:
+ foo = array('B')
+ foo.fromfile(source, 10000)
+ l = [ str(i) for i in foo.tolist() ]
+ count += len(l)
+ for i in xrange(0,9999,20):
+ print >>target, ','.join(l[i:i+20]) + ','
+ except EOFError:
+ l = [ str(i) for i in foo.tolist() ]
+ count += len(l)
+ for i in xrange(0,len(l),20):
+ print >>target, ','.join(l[i:i+20]) + ','
+ print >>target, ','.join(l[i:]) + ','
+
+ print >>target, '};'
+ print >>target, 'const int %s_length = %d;' % (name, count)
+ print >>target
+
+def splitpath(path):
+ dir,file = os.path.split(path)
+ path = []
+ assert(file)
+ while dir:
+ dir,base = os.path.split(dir)
+ path.insert(0, base)
+ return path, file
+
+Import('env')
+def MakeEmbeddedPyFile(target, source, env):
+ target = file(str(target[0]), 'w')
+
+ tree = {}
+ for src in source:
+ src = str(src)
+ path,pyfile = splitpath(src)
+ node = tree
+ for dir in path:
+ if not node.has_key(dir):
+ node[dir] = { }
+ node = node[dir]
+
+ name,ext = pyfile.split('.')
+ if name == '__init__':
+ node['.hasinit'] = True
+ node[pyfile] = (src,name,ext,src)
+
+ done = False
+ while not done:
+ done = True
+ for name,entry in tree.items():
+ if not isinstance(entry, dict): continue
+ if entry.has_key('.hasinit'): continue
+
+ done = False
+ del tree[name]
+ for key,val in entry.iteritems():
+ if tree.has_key(key):
+ raise NameError, \
+ "dir already has %s can't add it again" % key
+ tree[key] = val
+
+ files = []
+ def populate(node, path = []):
+ names = node.keys()
+ names.sort()
+ for name in names:
+ if name == '.hasinit':
+ continue
+
+ entry = node[name]
+ if isinstance(entry, dict):
+ if not entry.has_key('.hasinit'):
+ raise NameError, 'package directory missing __init__.py'
+ populate(entry, path + [ name ])
+ else:
+ pyfile,name,ext,filename = entry
+ files.append((pyfile, path, name, ext, filename))
+ populate(tree)
+
+ for pyfile, path, name, ext, filename in files:
+ WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename)
+
+def MakeDefinesPyFile(target, source, env):
+ target = file(str(target[0]), 'w')
+
+ print >>target, "import os"
+ defines = env['CPPDEFINES']
+ if isinstance(defines, list):
+ for var in defines:
+ if isinstance(var, tuple):
+ key,val = var
+ else:
+ key,val = var,'True'
+
+ if not isinstance(key, basestring):
+ panic("invalid type for define: %s" % type(key))
+
+ print >>target, "os.environ['%s'] = '%s'" % (key, val)
+
+ elif isinstance(defines, dict):
+ for key,val in defines.iteritems():
+ print >>target, "os.environ['%s'] = '%s'" % (key, val)
+ else:
+ panic("invalid type for defines: %s" % type(defines))
+
+CFileCounter = 0
+def MakePythonCFile(target, source, env):
+ global CFileCounter
+ target = file(str(target[0]), 'w')
+
+ print >>target, '''\
+#include "base/embedfile.hh"
+
+namespace {
+'''
+ for src in source:
+ src = str(src)
+ fname = os.path.basename(src)
+ name = 'embedded_file%d' % CFileCounter
+ CFileCounter += 1
+ WriteCFile(target, src, name)
+ print >>target, '''\
+EmbedMap %(name)s("%(fname)s",
+ %(name)s_string, %(name)s_length);
+
+''' % locals()
+ print >>target, '''\
+
+/* namespace */ }
+'''
+
+embedded_py_files = ['m5config.py', 'importer.py', '../../util/pbs/jobfile.py']
+objpath = os.path.join(env['SRCDIR'], 'objects')
+for root, dirs, files in os.walk(objpath, topdown=True):
+ for i,dir in enumerate(dirs):
+ if dir == 'SCCS':
+ del dirs[i]
+ break
+
+ assert(root.startswith(objpath))
+ for f in files:
+ if f.endswith('.mpy') or f.endswith('.py'):
+ embedded_py_files.append(os.path.join(root, f))
+
+embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh')
+env.Command('defines.py', None, MakeDefinesPyFile)
+env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile)
+env.Depends('embedded_py.cc', embedfile_hh)
+env.Command('embedded_py.cc',
+ ['string_importer.py', 'defines.py', 'embedded_py.py'],
+ MakePythonCFile)
diff --git a/sim/pyconfig/m5config.py b/sim/pyconfig/m5config.py
new file mode 100644
index 000000000..e6201b3ad
--- /dev/null
+++ b/sim/pyconfig/m5config.py
@@ -0,0 +1,1303 @@
+# 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.
+
+from __future__ import generators
+import os, re, sys, types, inspect
+
+from importer import AddToPath, LoadMpyFile
+
+noDot = False
+try:
+ import pydot
+except:
+ noDot = True
+
+env = {}
+env.update(os.environ)
+
+def panic(string):
+ print >>sys.stderr, 'panic:', string
+ sys.exit(1)
+
+def issequence(value):
+ return isinstance(value, tuple) or isinstance(value, list)
+
+class Singleton(type):
+ def __call__(cls, *args, **kwargs):
+ if hasattr(cls, '_instance'):
+ return cls._instance
+
+ cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
+ return cls._instance
+
+#####################################################################
+#
+# M5 Python Configuration Utility
+#
+# The basic idea is to write simple Python programs that build Python
+# objects corresponding to M5 SimObjects for the deisred simulation
+# configuration. For now, the Python emits a .ini file that can be
+# parsed by M5. In the future, some tighter integration between M5
+# and the Python interpreter may allow bypassing the .ini file.
+#
+# Each SimObject class in M5 is represented by a Python class with the
+# same name. The Python inheritance tree mirrors the M5 C++ tree
+# (e.g., SimpleCPU derives from BaseCPU in both cases, and all
+# SimObjects inherit from a single SimObject base class). To specify
+# an instance of an M5 SimObject in a configuration, the user simply
+# instantiates the corresponding Python object. The parameters for
+# that SimObject are given by assigning to attributes of the Python
+# object, either using keyword assignment in the constructor or in
+# separate assignment statements. For example:
+#
+# cache = BaseCache('my_cache', root, size=64*K)
+# cache.hit_latency = 3
+# cache.assoc = 8
+#
+# (The first two constructor arguments specify the name of the created
+# cache and its parent node in the hierarchy.)
+#
+# The magic lies in the mapping of the Python attributes for SimObject
+# classes to the actual SimObject parameter specifications. This
+# allows parameter validity checking in the Python code. Continuing
+# the example above, the statements "cache.blurfl=3" or
+# "cache.assoc='hello'" would both result in runtime errors in Python,
+# since the BaseCache object has no 'blurfl' parameter and the 'assoc'
+# parameter requires an integer, respectively. This magic is done
+# primarily by overriding the special __setattr__ method that controls
+# assignment to object attributes.
+#
+# The Python module provides another class, ConfigNode, which is a
+# superclass of SimObject. ConfigNode implements the parent/child
+# relationship for building the configuration hierarchy tree.
+# Concrete instances of ConfigNode can be used to group objects in the
+# hierarchy, but do not correspond to SimObjects themselves (like a
+# .ini section with "children=" but no "type=".
+#
+# Once a set of Python objects have been instantiated in a hierarchy,
+# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
+# will generate a .ini file. See simple-4cpu.py for an example
+# (corresponding to m5-test/simple-4cpu.ini).
+#
+#####################################################################
+
+#####################################################################
+#
+# ConfigNode/SimObject classes
+#
+# The Python class hierarchy rooted by ConfigNode (which is the base
+# class of SimObject, which in turn is the base class of all other M5
+# SimObject classes) has special attribute behavior. In general, an
+# object in this hierarchy has three categories of attribute-like
+# things:
+#
+# 1. Regular Python methods and variables. These must start with an
+# underscore to be treated normally.
+#
+# 2. SimObject parameters. These values are stored as normal Python
+# attributes, but all assignments to these attributes are checked
+# against the pre-defined set of parameters stored in the class's
+# _params dictionary. Assignments to attributes that do not
+# correspond to predefined parameters, or that are not of the correct
+# type, incur runtime errors.
+#
+# 3. Hierarchy children. The child nodes of a ConfigNode are stored
+# in the node's _children dictionary, but can be accessed using the
+# Python attribute dot-notation (just as they are printed out by the
+# simulator). Children cannot be created using attribute assigment;
+# they must be added by specifying the parent node in the child's
+# constructor or using the '+=' operator.
+
+# The SimObject parameters are the most complex, for a few reasons.
+# First, both parameter descriptions and parameter values are
+# inherited. Thus parameter description lookup must go up the
+# inheritance chain like normal attribute lookup, but this behavior
+# must be explicitly coded since the lookup occurs in each class's
+# _params attribute. Second, because parameter values can be set
+# on SimObject classes (to implement default values), the parameter
+# checking behavior must be enforced on class attribute assignments as
+# well as instance attribute assignments. Finally, because we allow
+# class specialization via inheritance (e.g., see the L1Cache class in
+# the simple-4cpu.py example), we must do parameter checking even on
+# class instantiation. To provide all these features, we use a
+# metaclass to define most of the SimObject parameter behavior for
+# this class hierarchy.
+#
+#####################################################################
+
+class Proxy(object):
+ def __init__(self, path = ()):
+ self._object = None
+ self._path = path
+
+ def __getattr__(self, attr):
+ return Proxy(self._path + (attr, ))
+
+ def __setattr__(self, attr, value):
+ if not attr.startswith('_'):
+ raise AttributeError, 'cannot set attribute %s' % attr
+ super(Proxy, self).__setattr__(attr, value)
+
+ def _convert(self):
+ obj = self._object
+ for attr in self._path:
+ obj = obj.__getattribute__(attr)
+ return obj
+
+Super = Proxy()
+
+def isSubClass(value, cls):
+ try:
+ return issubclass(value, cls)
+ except:
+ return False
+
+def isConfigNode(value):
+ try:
+ return issubclass(value, ConfigNode)
+ except:
+ return False
+
+def isSimObject(value):
+ try:
+ return issubclass(value, SimObject)
+ except:
+ return False
+
+def isSimObjSequence(value):
+ if not issequence(value):
+ return False
+
+ for val in value:
+ if not isNullPointer(val) and not isConfigNode(val):
+ return False
+
+ return True
+
+def isParamContext(value):
+ try:
+ return issubclass(value, ParamContext)
+ except:
+ return False
+
+
+class_decorator = 'M5M5_SIMOBJECT_'
+expr_decorator = 'M5M5_EXPRESSION_'
+dot_decorator = '_M5M5_DOT_'
+
+# The metaclass for ConfigNode (and thus for everything that derives
+# from ConfigNode, including SimObject). This class controls how new
+# classes that derive from ConfigNode are instantiated, and provides
+# inherited class behavior (just like a class controls how instances
+# of that class are instantiated, and provides inherited instance
+# behavior).
+class MetaConfigNode(type):
+ # Attributes that can be set only at initialization time
+ init_keywords = {}
+ # Attributes that can be set any time
+ keywords = { 'check' : types.FunctionType,
+ 'children' : types.ListType }
+
+ # __new__ is called before __init__, and is where the statements
+ # in the body of the class definition get loaded into the class's
+ # __dict__. We intercept this to filter out parameter assignments
+ # and only allow "private" attributes to be passed to the base
+ # __new__ (starting with underscore).
+ def __new__(mcls, name, bases, dict):
+ # Copy "private" attributes (including special methods such as __new__)
+ # to the official dict. Everything else goes in _init_dict to be
+ # filtered in __init__.
+ cls_dict = {}
+ for key,val in dict.items():
+ if key.startswith('_'):
+ cls_dict[key] = val
+ del dict[key]
+ cls_dict['_init_dict'] = dict
+ return super(MetaConfigNode, mcls).__new__(mcls, name, bases, cls_dict)
+
+ # initialization
+ def __init__(cls, name, bases, dict):
+ super(MetaConfigNode, cls).__init__(name, bases, dict)
+
+ # initialize required attributes
+ cls._params = {}
+ cls._values = {}
+ cls._enums = {}
+ cls._bases = [c for c in cls.__mro__ if isConfigNode(c)]
+ cls._anon_subclass_counter = 0
+
+ # If your parent has a value in it that's a config node, clone
+ # it. Do this now so if we update any of the values'
+ # attributes we are updating the clone and not the original.
+ for base in cls._bases:
+ for key,val in base._values.iteritems():
+
+ # don't clone if (1) we're about to overwrite it with
+ # a local setting or (2) we've already cloned a copy
+ # from an earlier (more derived) base
+ if cls._init_dict.has_key(key) or cls._values.has_key(key):
+ continue
+
+ if isConfigNode(val):
+ cls._values[key] = val()
+ elif isSimObjSequence(val):
+ cls._values[key] = [ v() for v in val ]
+ elif isNullPointer(val):
+ cls._values[key] = val
+
+ # now process _init_dict items
+ for key,val in cls._init_dict.items():
+ if isinstance(val, _Param):
+ cls._params[key] = val
+
+ # init-time-only keywords
+ elif cls.init_keywords.has_key(key):
+ cls._set_keyword(key, val, cls.init_keywords[key])
+
+ # enums
+ elif isinstance(val, type) and issubclass(val, Enum):
+ cls._enums[key] = val
+
+ # See description of decorators in the importer.py file.
+ # We just strip off the expr_decorator now since we don't
+ # need from this point on.
+ elif key.startswith(expr_decorator):
+ key = key[len(expr_decorator):]
+ # because it had dots into a list so that we can find the
+ # proper variable to modify.
+ key = key.split(dot_decorator)
+ c = cls
+ for item in key[:-1]:
+ c = getattr(c, item)
+ setattr(c, key[-1], val)
+
+ # default: use normal path (ends up in __setattr__)
+ else:
+ setattr(cls, key, val)
+
+
+ def _isvalue(cls, name):
+ for c in cls._bases:
+ if c._params.has_key(name):
+ return True
+
+ for c in cls._bases:
+ if c._values.has_key(name):
+ return True
+
+ return False
+
+ # generator that iterates across all parameters for this class and
+ # all classes it inherits from
+ def _getparams(cls):
+ params = {}
+ for c in cls._bases:
+ for p,v in c._params.iteritems():
+ if not params.has_key(p):
+ params[p] = v
+ return params
+
+ # Lookup a parameter description by name in the given class.
+ def _getparam(cls, name, default = AttributeError):
+ for c in cls._bases:
+ if c._params.has_key(name):
+ return c._params[name]
+ if isSubClass(default, Exception):
+ raise default, \
+ "object '%s' has no attribute '%s'" % (cls.__name__, name)
+ else:
+ return default
+
+ def _hasvalue(cls, name):
+ for c in cls._bases:
+ if c._values.has_key(name):
+ return True
+
+ return False
+
+ def _getvalues(cls):
+ values = {}
+ for i,c in enumerate(cls._bases):
+ for p,v in c._values.iteritems():
+ if not values.has_key(p):
+ values[p] = v
+ for p,v in c._params.iteritems():
+ if not values.has_key(p) and hasattr(v, 'default'):
+ try:
+ v.valid(v.default)
+ except TypeError:
+ panic("Invalid default %s for param %s in node %s"
+ % (v.default,p,cls.__name__))
+ v = v.default
+ cls._setvalue(p, v)
+ values[p] = v
+
+ return values
+
+ def _getvalue(cls, name, default = AttributeError):
+ value = None
+ for c in cls._bases:
+ if c._values.has_key(name):
+ value = c._values[name]
+ break
+ if value is not None:
+ return value
+
+ param = cls._getparam(name, None)
+ if param is not None and hasattr(param, 'default'):
+ param.valid(param.default)
+ value = param.default
+ cls._setvalue(name, value)
+ return value
+
+ if isSubClass(default, Exception):
+ raise default, 'value for %s not found' % name
+ else:
+ return default
+
+ def _setvalue(cls, name, value):
+ cls._values[name] = value
+
+ def __getattr__(cls, attr):
+ if cls._isvalue(attr):
+ return Value(cls, attr)
+
+ if attr == '_cpp_param_decl' and hasattr(cls, 'type'):
+ return cls.type + '*'
+
+ raise AttributeError, \
+ "object '%s' has no attribute '%s'" % (cls.__name__, attr)
+
+ def _set_keyword(cls, keyword, val, kwtype):
+ if not isinstance(val, kwtype):
+ raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
+ (keyword, type(val), kwtype)
+ if isinstance(val, types.FunctionType):
+ val = classmethod(val)
+ type.__setattr__(cls, keyword, val)
+
+ # Set attribute (called on foo.attr = value when foo is an
+ # instance of class cls).
+ def __setattr__(cls, attr, value):
+ # normal processing for private attributes
+ if attr.startswith('_'):
+ type.__setattr__(cls, attr, value)
+ return
+
+ if cls.keywords.has_key(attr):
+ cls._set_keyword(attr, value, cls.keywords[attr])
+ return
+
+ # must be SimObject param
+ param = cls._getparam(attr, None)
+ if param:
+ # It's ok: set attribute by delegating to 'object' class.
+ # Note the use of param.make_value() to verify/canonicalize
+ # the assigned value
+ param.valid(value)
+ cls._setvalue(attr, value)
+ elif isConfigNode(value) or isSimObjSequence(value):
+ cls._setvalue(attr, value)
+ else:
+ raise AttributeError, \
+ "Class %s has no parameter %s" % (cls.__name__, attr)
+
+ def add_child(cls, instance, name, child):
+ if isNullPointer(child) or instance.top_child_names.has_key(name):
+ return
+
+ if issequence(child):
+ kid = []
+ for i,c in enumerate(child):
+ n = '%s%d' % (name, i)
+ k = c.instantiate(n, instance)
+
+ instance.children.append(k)
+ instance.child_names[n] = k
+ instance.child_objects[c] = k
+ kid.append(k)
+ else:
+ kid = child.instantiate(name, instance)
+ instance.children.append(kid)
+ instance.child_names[name] = kid
+ instance.child_objects[child] = kid
+
+ instance.top_child_names[name] = kid
+
+ # Print instance info to .ini file.
+ def instantiate(cls, name, parent = None):
+ instance = Node(name, cls, cls.type, parent, isParamContext(cls))
+
+ if hasattr(cls, 'check'):
+ cls.check()
+
+ for key,value in cls._getvalues().iteritems():
+ if isConfigNode(value):
+ cls.add_child(instance, key, value)
+ if issequence(value):
+ list = [ v for v in value if isConfigNode(v) ]
+ if len(list):
+ cls.add_child(instance, key, list)
+
+ for pname,param in cls._getparams().iteritems():
+ try:
+ value = cls._getvalue(pname)
+ except:
+ panic('Error getting %s' % pname)
+
+ try:
+ if isConfigNode(value):
+ value = instance.child_objects[value]
+ elif issequence(value):
+ v = []
+ for val in value:
+ if isConfigNode(val):
+ v.append(instance.child_objects[val])
+ else:
+ v.append(val)
+ value = v
+
+ p = NodeParam(pname, param, value)
+ instance.params.append(p)
+ instance.param_names[pname] = p
+ except:
+ print 'Exception while evaluating %s.%s' % \
+ (instance.path, pname)
+ raise
+
+ return instance
+
+ def _convert(cls, value):
+ realvalue = value
+ if isinstance(value, Node):
+ realvalue = value.realtype
+
+ if isinstance(realvalue, Proxy):
+ return value
+
+ if realvalue == None or isNullPointer(realvalue):
+ return value
+
+ if isSubClass(realvalue, cls):
+ return value
+
+ raise TypeError, 'object %s type %s wrong type, should be %s' % \
+ (repr(realvalue), realvalue, cls)
+
+ def _string(cls, value):
+ if isNullPointer(value):
+ return 'Null'
+ return Node._string(value)
+
+# The ConfigNode class is the root of the special hierarchy. Most of
+# the code in this class deals with the configuration hierarchy itself
+# (parent/child node relationships).
+class ConfigNode(object):
+ # Specify metaclass. Any class inheriting from ConfigNode will
+ # get this metaclass.
+ __metaclass__ = MetaConfigNode
+
+ def __new__(cls, **kwargs):
+ name = cls.__name__ + ("_%d" % cls._anon_subclass_counter)
+ cls._anon_subclass_counter += 1
+ return cls.__metaclass__(name, (cls, ), kwargs)
+
+class ParamContext(ConfigNode):
+ pass
+
+class MetaSimObject(MetaConfigNode):
+ # init_keywords and keywords are inherited from MetaConfigNode,
+ # with overrides/additions
+ init_keywords = MetaConfigNode.init_keywords
+ init_keywords.update({ 'abstract' : types.BooleanType,
+ 'type' : types.StringType })
+
+ keywords = MetaConfigNode.keywords
+ # no additional keywords
+
+ cpp_classes = []
+
+ # initialization
+ def __init__(cls, name, bases, dict):
+ super(MetaSimObject, cls).__init__(name, bases, dict)
+
+ if hasattr(cls, 'type'):
+ if name == 'SimObject':
+ cls._cpp_base = None
+ elif hasattr(cls._bases[1], 'type'):
+ cls._cpp_base = cls._bases[1].type
+ else:
+ panic("SimObject %s derives from a non-C++ SimObject %s "\
+ "(no 'type')" % (cls, cls_bases[1].__name__))
+
+ # This class corresponds to a C++ class: put it on the global
+ # list of C++ objects to generate param structs, etc.
+ MetaSimObject.cpp_classes.append(cls)
+
+ def _cpp_decl(cls):
+ name = cls.__name__
+ code = ""
+ code += "\n".join([e.cpp_declare() for e in cls._enums.values()])
+ code += "\n"
+ param_names = cls._params.keys()
+ param_names.sort()
+ code += "struct Params"
+ if cls._cpp_base:
+ code += " : public %s::Params" % cls._cpp_base
+ code += " {\n "
+ code += "\n ".join([cls._params[pname].cpp_decl(pname) \
+ for pname in param_names])
+ code += "\n};\n"
+ return code
+
+class NodeParam(object):
+ def __init__(self, name, param, value):
+ self.name = name
+ self.param = param
+ self.ptype = param.ptype
+ self.convert = param.convert
+ self.string = param.string
+ self.value = value
+
+class Node(object):
+ all = {}
+ def __init__(self, name, realtype, type, parent, paramcontext):
+ self.name = name
+ self.realtype = realtype
+ self.type = type
+ self.parent = parent
+ self.children = []
+ self.child_names = {}
+ self.child_objects = {}
+ self.top_child_names = {}
+ self.params = []
+ self.param_names = {}
+ self.paramcontext = paramcontext
+
+ path = [ self.name ]
+ node = self.parent
+ while node is not None:
+ if node.name != 'root':
+ path.insert(0, node.name)
+ else:
+ assert(node.parent is None)
+ node = node.parent
+ self.path = '.'.join(path)
+
+ def find(self, realtype, path):
+ if not path:
+ if issubclass(self.realtype, realtype):
+ return self, True
+
+ obj = None
+ for child in self.children:
+ if issubclass(child.realtype, realtype):
+ if obj is not None:
+ raise AttributeError, \
+ 'Super matched more than one: %s %s' % \
+ (obj.path, child.path)
+ obj = child
+ return obj, obj is not None
+
+ try:
+ obj = self
+ for node in path[:-1]:
+ obj = obj.child_names[node]
+
+ last = path[-1]
+ if obj.child_names.has_key(last):
+ value = obj.child_names[last]
+ if issubclass(value.realtype, realtype):
+ return value, True
+ elif obj.param_names.has_key(last):
+ value = obj.param_names[last]
+ realtype._convert(value.value)
+ return value.value, True
+ except KeyError:
+ pass
+
+ return None, False
+
+ def unproxy(self, ptype, value):
+ if not isinstance(value, Proxy):
+ return value
+
+ if value is None:
+ raise AttributeError, 'Error while fixing up %s' % self.path
+
+ obj = self
+ done = False
+ while not done:
+ if obj is None:
+ raise AttributeError, \
+ 'Parent of %s type %s not found at path %s' \
+ % (self.name, ptype, value._path)
+ found, done = obj.find(ptype, value._path)
+ if isinstance(found, Proxy):
+ done = False
+ obj = obj.parent
+
+ return found
+
+ def fixup(self):
+ self.all[self.path] = self
+
+ for param in self.params:
+ ptype = param.ptype
+ pval = param.value
+
+ try:
+ if issequence(pval):
+ param.value = [ self.unproxy(ptype, pv) for pv in pval ]
+ else:
+ param.value = self.unproxy(ptype, pval)
+ except:
+ print 'Error while fixing up %s:%s' % (self.path, param.name)
+ raise
+
+ for child in self.children:
+ assert(child != self)
+ child.fixup()
+
+ # print type and parameter values to .ini file
+ def display(self):
+ print '[' + self.path + ']' # .ini section header
+
+ if isSimObject(self.realtype):
+ print 'type = %s' % self.type
+
+ if self.children:
+ # instantiate children in same order they were added for
+ # backward compatibility (else we can end up with cpu1
+ # before cpu0). Changing ordering can also influence timing
+ # in the current memory system, as caches get added to a bus
+ # in different orders which affects their priority in the
+ # case of simulataneous requests. We should uncomment the
+ # following line once we take care of that issue.
+ # self.children.sort(lambda x,y: cmp(x.name, y.name))
+ children = [ c.name for c in self.children if not c.paramcontext]
+ print 'children =', ' '.join(children)
+
+ self.params.sort(lambda x,y: cmp(x.name, y.name))
+ for param in self.params:
+ try:
+ if param.value is None:
+ raise AttributeError, 'Parameter with no value'
+
+ value = param.convert(param.value)
+ string = param.string(value)
+ except:
+ print 'exception in %s:%s' % (self.path, param.name)
+ raise
+
+ print '%s = %s' % (param.name, string)
+
+ print
+
+ # recursively dump out children
+ for c in self.children:
+ c.display()
+
+ # print type and parameter values to .ini file
+ def outputDot(self, dot):
+
+
+ label = "{%s|" % self.path
+ if isSimObject(self.realtype):
+ label += '%s|' % self.type
+
+ if self.children:
+ # instantiate children in same order they were added for
+ # backward compatibility (else we can end up with cpu1
+ # before cpu0).
+ for c in self.children:
+ dot.add_edge(pydot.Edge(self.path,c.path, style="bold"))
+
+ simobjs = []
+ for param in self.params:
+ try:
+ if param.value is None:
+ raise AttributeError, 'Parameter with no value'
+
+ value = param.convert(param.value)
+ string = param.string(value)
+ except:
+ print 'exception in %s:%s' % (self.name, param.name)
+ raise
+ if isConfigNode(param.ptype) and string != "Null":
+ simobjs.append(string)
+ else:
+ label += '%s = %s\\n' % (param.name, string)
+
+ for so in simobjs:
+ label += "|<%s> %s" % (so, so)
+ dot.add_edge(pydot.Edge("%s:%s" % (self.path, so), so, tailport="w"))
+ label += '}'
+ dot.add_node(pydot.Node(self.path,shape="Mrecord",label=label))
+
+ # recursively dump out children
+ for c in self.children:
+ c.outputDot(dot)
+
+ def _string(cls, value):
+ if not isinstance(value, Node):
+ raise AttributeError, 'expecting %s got %s' % (Node, value)
+ return value.path
+ _string = classmethod(_string)
+
+#####################################################################
+#
+# Parameter description classes
+#
+# The _params dictionary in each class maps parameter names to
+# either a Param or a VectorParam object. These objects contain the
+# parameter description string, the parameter type, and the default
+# value (loaded from the PARAM section of the .odesc files). The
+# _convert() method on these objects is used to force whatever value
+# is assigned to the parameter to the appropriate type.
+#
+# Note that the default values are loaded into the class's attribute
+# space when the parameter dictionary is initialized (in
+# MetaConfigNode._setparams()); after that point they aren't used.
+#
+#####################################################################
+
+def isNullPointer(value):
+ return isinstance(value, NullSimObject)
+
+class Value(object):
+ def __init__(self, obj, attr):
+ super(Value, self).__setattr__('attr', attr)
+ super(Value, self).__setattr__('obj', obj)
+
+ def _getattr(self):
+ return self.obj._getvalue(self.attr)
+
+ def __setattr__(self, attr, value):
+ setattr(self._getattr(), attr, value)
+
+ def __getattr__(self, attr):
+ return getattr(self._getattr(), attr)
+
+ def __getitem__(self, index):
+ return self._getattr().__getitem__(index)
+
+ def __call__(self, *args, **kwargs):
+ return self._getattr().__call__(*args, **kwargs)
+
+ def __nonzero__(self):
+ return bool(self._getattr())
+
+ def __str__(self):
+ return str(self._getattr())
+
+# Regular parameter.
+class _Param(object):
+ def __init__(self, ptype, *args, **kwargs):
+ if isinstance(ptype, types.StringType):
+ self.ptype_string = ptype
+ elif isinstance(ptype, type):
+ self.ptype = ptype
+ else:
+ raise TypeError, "Param type is not a type (%s)" % ptype
+
+ if args:
+ if len(args) == 1:
+ self.desc = args[0]
+ elif len(args) == 2:
+ self.default = args[0]
+ self.desc = args[1]
+ else:
+ raise TypeError, 'too many arguments'
+
+ if kwargs.has_key('desc'):
+ assert(not hasattr(self, 'desc'))
+ self.desc = kwargs['desc']
+ del kwargs['desc']
+
+ if kwargs.has_key('default'):
+ assert(not hasattr(self, 'default'))
+ self.default = kwargs['default']
+ del kwargs['default']
+
+ if kwargs:
+ raise TypeError, 'extra unknown kwargs %s' % kwargs
+
+ if not hasattr(self, 'desc'):
+ raise TypeError, 'desc attribute missing'
+
+ def __getattr__(self, attr):
+ if attr == 'ptype':
+ try:
+ self.ptype = eval(self.ptype_string)
+ return self.ptype
+ except:
+ raise TypeError, 'Param.%s: undefined type' % self.ptype_string
+ else:
+ raise AttributeError, "'%s' object has no attribute '%s'" % \
+ (type(self).__name__, attr)
+
+ def valid(self, value):
+ if not isinstance(value, Proxy):
+ self.ptype._convert(value)
+
+ def convert(self, value):
+ return self.ptype._convert(value)
+
+ def string(self, value):
+ return self.ptype._string(value)
+
+ def set(self, name, instance, value):
+ instance.__dict__[name] = value
+
+ def cpp_decl(self, name):
+ return '%s %s;' % (self.ptype._cpp_param_decl, name)
+
+class _ParamProxy(object):
+ def __init__(self, type):
+ self.ptype = type
+
+ # E.g., Param.Int(5, "number of widgets")
+ def __call__(self, *args, **kwargs):
+ # Param type could be defined only in context of caller (e.g.,
+ # for locally defined Enum subclass). Need to go look up the
+ # type in that enclosing scope.
+ caller_frame = inspect.stack()[1][0]
+ ptype = caller_frame.f_locals.get(self.ptype, None)
+ if not ptype: ptype = caller_frame.f_globals.get(self.ptype, None)
+ if not ptype: ptype = globals().get(self.ptype, None)
+ # ptype could still be None due to circular references... we'll
+ # try one more time to evaluate lazily when ptype is first needed.
+ # In the meantime we'll save the type name as a string.
+ if not ptype: ptype = self.ptype
+ return _Param(ptype, *args, **kwargs)
+
+ def __getattr__(self, attr):
+ if attr == '__bases__':
+ raise AttributeError, ''
+ cls = type(self)
+ return cls(attr)
+
+ def __setattr__(self, attr, value):
+ if attr != 'ptype':
+ raise AttributeError, \
+ 'Attribute %s not available in %s' % (attr, self.__class__)
+ super(_ParamProxy, self).__setattr__(attr, value)
+
+
+Param = _ParamProxy(None)
+
+# Vector-valued parameter description. Just like Param, except that
+# the value is a vector (list) of the specified type instead of a
+# single value.
+class _VectorParam(_Param):
+ def __init__(self, type, *args, **kwargs):
+ _Param.__init__(self, type, *args, **kwargs)
+
+ def valid(self, value):
+ if value == None:
+ return True
+
+ if issequence(value):
+ for val in value:
+ if not isinstance(val, Proxy):
+ self.ptype._convert(val)
+ elif not isinstance(value, Proxy):
+ self.ptype._convert(value)
+
+ # Convert assigned value to appropriate type. If the RHS is not a
+ # list or tuple, it generates a single-element list.
+ def convert(self, value):
+ if value == None:
+ return []
+
+ if issequence(value):
+ # list: coerce each element into new list
+ return [ self.ptype._convert(v) for v in value ]
+ else:
+ # singleton: coerce & wrap in a list
+ return self.ptype._convert(value)
+
+ def string(self, value):
+ if issequence(value):
+ return ' '.join([ self.ptype._string(v) for v in value])
+ else:
+ return self.ptype._string(value)
+
+ def cpp_decl(self, name):
+ return 'std::vector<%s> %s;' % (self.ptype._cpp_param_decl, name)
+
+class _VectorParamProxy(_ParamProxy):
+ # E.g., VectorParam.Int(5, "number of widgets")
+ def __call__(self, *args, **kwargs):
+ return _VectorParam(self.ptype, *args, **kwargs)
+
+VectorParam = _VectorParamProxy(None)
+
+#####################################################################
+#
+# Parameter Types
+#
+# Though native Python types could be used to specify parameter types
+# (the 'ptype' field of the Param and VectorParam classes), it's more
+# flexible to define our own set of types. This gives us more control
+# over how Python expressions are converted to values (via the
+# __init__() constructor) and how these values are printed out (via
+# the __str__() conversion method). Eventually we'll need these types
+# to correspond to distinct C++ types as well.
+#
+#####################################################################
+# Integer parameter type.
+class _CheckedInt(object):
+ def _convert(cls, value):
+ t = type(value)
+ if t == bool:
+ return int(value)
+
+ if t != int and t != long and t != float and t != str:
+ raise TypeError, 'Integer parameter of invalid type %s' % t
+
+ if t == str or t == float:
+ value = long(value)
+
+ if not cls._min <= value <= cls._max:
+ raise TypeError, 'Integer parameter out of bounds %d < %d < %d' % \
+ (cls._min, value, cls._max)
+
+ return value
+ _convert = classmethod(_convert)
+
+ def _string(cls, value):
+ return str(value)
+ _string = classmethod(_string)
+
+class CheckedInt(type):
+ def __new__(cls, cppname, min, max):
+ # New class derives from _CheckedInt base with proper bounding
+ # parameters
+ dict = { '_cpp_param_decl' : cppname, '_min' : min, '_max' : max }
+ return type.__new__(cls, cppname, (_CheckedInt, ), dict)
+
+class CheckedIntType(CheckedInt):
+ def __new__(cls, cppname, size, unsigned):
+ dict = {}
+ if unsigned:
+ min = 0
+ max = 2 ** size - 1
+ else:
+ min = -(2 ** (size - 1))
+ max = (2 ** (size - 1)) - 1
+
+ return super(cls, CheckedIntType).__new__(cls, cppname, min, max)
+
+Int = CheckedIntType('int', 32, False)
+Unsigned = CheckedIntType('unsigned', 32, True)
+
+Int8 = CheckedIntType('int8_t', 8, False)
+UInt8 = CheckedIntType('uint8_t', 8, True)
+Int16 = CheckedIntType('int16_t', 16, False)
+UInt16 = CheckedIntType('uint16_t', 16, True)
+Int32 = CheckedIntType('int32_t', 32, False)
+UInt32 = CheckedIntType('uint32_t', 32, True)
+Int64 = CheckedIntType('int64_t', 64, False)
+UInt64 = CheckedIntType('uint64_t', 64, True)
+
+Counter = CheckedIntType('Counter', 64, True)
+Addr = CheckedIntType('Addr', 64, True)
+Tick = CheckedIntType('Tick', 64, True)
+
+Percent = CheckedInt('int', 0, 100)
+
+class Pair(object):
+ def __init__(self, first, second):
+ self.first = first
+ self.second = second
+
+class _Range(object):
+ def _convert(cls, value):
+ if not isinstance(value, Pair):
+ raise TypeError, 'value %s is not a Pair' % value
+ return Pair(cls._type._convert(value.first),
+ cls._type._convert(value.second))
+ _convert = classmethod(_convert)
+
+ def _string(cls, value):
+ return '%s:%s' % (cls._type._string(value.first),
+ cls._type._string(value.second))
+ _string = classmethod(_string)
+
+def RangeSize(start, size):
+ return Pair(start, start + size - 1)
+
+class Range(type):
+ def __new__(cls, type):
+ dict = { '_cpp_param_decl' : 'Range<%s>' % type._cpp_param_decl,
+ '_type' : type }
+ clsname = 'Range_' + type.__name__
+ return super(cls, Range).__new__(cls, clsname, (_Range, ), dict)
+
+AddrRange = Range(Addr)
+
+# Boolean parameter type.
+class Bool(object):
+ _cpp_param_decl = 'bool'
+ def _convert(value):
+ t = type(value)
+ if t == bool:
+ return value
+
+ if t == int or t == long:
+ return bool(value)
+
+ if t == str:
+ v = value.lower()
+ if v == "true" or v == "t" or v == "yes" or v == "y":
+ return True
+ elif v == "false" or v == "f" or v == "no" or v == "n":
+ return False
+
+ raise TypeError, 'Bool parameter (%s) of invalid type %s' % (v, t)
+ _convert = staticmethod(_convert)
+
+ def _string(value):
+ if value:
+ return "true"
+ else:
+ return "false"
+ _string = staticmethod(_string)
+
+# String-valued parameter.
+class String(object):
+ _cpp_param_decl = 'string'
+
+ # Constructor. Value must be Python string.
+ def _convert(cls,value):
+ if value is None:
+ return ''
+ if isinstance(value, str):
+ return value
+
+ raise TypeError, \
+ "String param got value %s %s" % (repr(value), type(value))
+ _convert = classmethod(_convert)
+
+ # Generate printable string version. Not too tricky.
+ def _string(cls, value):
+ return value
+ _string = classmethod(_string)
+
+
+def IncEthernetAddr(addr, val = 1):
+ bytes = map(lambda x: int(x, 16), addr.split(':'))
+ bytes[5] += val
+ for i in (5, 4, 3, 2, 1):
+ val,rem = divmod(bytes[i], 256)
+ bytes[i] = rem
+ if val == 0:
+ break
+ bytes[i - 1] += val
+ assert(bytes[0] <= 255)
+ return ':'.join(map(lambda x: '%02x' % x, bytes))
+
+class NextEthernetAddr(object):
+ __metaclass__ = Singleton
+ addr = "00:90:00:00:00:01"
+
+ def __init__(self, inc = 1):
+ self.value = self.addr
+ self.addr = IncEthernetAddr(self.addr, inc)
+
+class EthernetAddr(object):
+ _cpp_param_decl = 'EthAddr'
+
+ def _convert(cls, value):
+ if value == NextEthernetAddr:
+ return value
+
+ if not isinstance(value, str):
+ raise TypeError, "expected an ethernet address and didn't get one"
+
+ bytes = value.split(':')
+ if len(bytes) != 6:
+ raise TypeError, 'invalid ethernet address %s' % value
+
+ for byte in bytes:
+ if not 0 <= int(byte) <= 256:
+ raise TypeError, 'invalid ethernet address %s' % value
+
+ return value
+ _convert = classmethod(_convert)
+
+ def _string(cls, value):
+ if value == NextEthernetAddr:
+ value = value().value
+ return value
+ _string = classmethod(_string)
+
+# Special class for NULL pointers. Note the special check in
+# make_param_value() above that lets these be assigned where a
+# SimObject is required.
+# only one copy of a particular node
+class NullSimObject(object):
+ __metaclass__ = Singleton
+
+ def __call__(cls):
+ return cls
+
+ def _instantiate(self, parent = None, path = ''):
+ pass
+
+ def _convert(cls, value):
+ if value == Nxone:
+ return
+
+ if isinstance(value, cls):
+ return value
+
+ raise TypeError, 'object %s %s of the wrong type, should be %s' % \
+ (repr(value), type(value), cls)
+ _convert = classmethod(_convert)
+
+ def _string():
+ return 'NULL'
+ _string = staticmethod(_string)
+
+# The only instance you'll ever need...
+Null = NULL = NullSimObject()
+
+# Enumerated types are a little more complex. The user specifies the
+# type as Enum(foo) where foo is either a list or dictionary of
+# alternatives (typically strings, but not necessarily so). (In the
+# long run, the integer value of the parameter will be the list index
+# or the corresponding dictionary value. For now, since we only check
+# that the alternative is valid and then spit it into a .ini file,
+# there's not much point in using the dictionary.)
+
+# What Enum() must do is generate a new type encapsulating the
+# provided list/dictionary so that specific values of the parameter
+# can be instances of that type. We define two hidden internal
+# classes (_ListEnum and _DictEnum) to serve as base classes, then
+# derive the new type from the appropriate base class on the fly.
+
+
+# Metaclass for Enum types
+class MetaEnum(type):
+
+ def __init__(cls, name, bases, init_dict):
+ if init_dict.has_key('map'):
+ if not isinstance(cls.map, dict):
+ raise TypeError, "Enum-derived class attribute 'map' " \
+ "must be of type dict"
+ # build list of value strings from map
+ cls.vals = cls.map.keys()
+ cls.vals.sort()
+ elif init_dict.has_key('vals'):
+ if not isinstance(cls.vals, list):
+ raise TypeError, "Enum-derived class attribute 'vals' " \
+ "must be of type list"
+ # build string->value map from vals sequence
+ cls.map = {}
+ for idx,val in enumerate(cls.vals):
+ cls.map[val] = idx
+ else:
+ raise TypeError, "Enum-derived class must define "\
+ "attribute 'map' or 'vals'"
+
+ cls._cpp_param_decl = name
+
+ super(MetaEnum, cls).__init__(name, bases, init_dict)
+
+ def cpp_declare(cls):
+ s = 'enum %s {\n ' % cls.__name__
+ s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals])
+ s += '\n};\n'
+ return s
+
+# Base class for enum types.
+class Enum(object):
+ __metaclass__ = MetaEnum
+ vals = []
+
+ def _convert(self, value):
+ if value not in self.map:
+ raise TypeError, "Enum param got bad value '%s' (not in %s)" \
+ % (value, self.vals)
+ return value
+ _convert = classmethod(_convert)
+
+ # Generate printable string version of value.
+ def _string(self, value):
+ return str(value)
+ _string = classmethod(_string)
+#
+# "Constants"... handy aliases for various values.
+#
+
+# Some memory range specifications use this as a default upper bound.
+MAX_ADDR = Addr._max
+MaxTick = Tick._max
+
+# For power-of-two sizing, e.g. 64*K gives an integer value 65536.
+K = 1024
+M = K*K
+G = K*M
+
+#####################################################################
+
+# The final hook to generate .ini files. Called from configuration
+# script once config is built.
+def instantiate(root):
+ if not issubclass(root, Root):
+ raise AttributeError, 'Can only instantiate the Root of the tree'
+
+ instance = root.instantiate('root')
+ instance.fixup()
+ instance.display()
+ if not noDot:
+ dot = pydot.Dot()
+ instance.outputDot(dot)
+ dot.orientation = "portrait"
+ dot.size = "8.5,11"
+ dot.ranksep="equally"
+ dot.rank="samerank"
+ dot.write("config.dot")
+ dot.write_ps("config.ps")
+
+# SimObject is a minimal extension of ConfigNode, implementing a
+# hierarchy node that corresponds to an M5 SimObject. It prints out a
+# "type=" line to indicate its SimObject class, prints out the
+# assigned parameters corresponding to its class, and allows
+# parameters to be set by keyword in the constructor. Note that most
+# of the heavy lifting for the SimObject param handling is done in the
+# MetaConfigNode metaclass.
+class SimObject(ConfigNode):
+ __metaclass__ = MetaSimObject
+ type = 'SimObject'
+
+from objects import *
+
+cpp_classes = MetaSimObject.cpp_classes
+cpp_classes.sort()
diff --git a/sim/pyconfig/m5configbase.py b/sim/pyconfig/m5configbase.py
deleted file mode 100644
index 66660994e..000000000
--- a/sim/pyconfig/m5configbase.py
+++ /dev/null
@@ -1,723 +0,0 @@
-# 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.
-
-from __future__ import generators
-
-import os
-import re
-import sys
-
-#####################################################################
-#
-# M5 Python Configuration Utility
-#
-# The basic idea is to write simple Python programs that build Python
-# objects corresponding to M5 SimObjects for the deisred simulation
-# configuration. For now, the Python emits a .ini file that can be
-# parsed by M5. In the future, some tighter integration between M5
-# and the Python interpreter may allow bypassing the .ini file.
-#
-# Each SimObject class in M5 is represented by a Python class with the
-# same name. The Python inheritance tree mirrors the M5 C++ tree
-# (e.g., SimpleCPU derives from BaseCPU in both cases, and all
-# SimObjects inherit from a single SimObject base class). To specify
-# an instance of an M5 SimObject in a configuration, the user simply
-# instantiates the corresponding Python object. The parameters for
-# that SimObject are given by assigning to attributes of the Python
-# object, either using keyword assignment in the constructor or in
-# separate assignment statements. For example:
-#
-# cache = BaseCache('my_cache', root, size=64*K)
-# cache.hit_latency = 3
-# cache.assoc = 8
-#
-# (The first two constructor arguments specify the name of the created
-# cache and its parent node in the hierarchy.)
-#
-# The magic lies in the mapping of the Python attributes for SimObject
-# classes to the actual SimObject parameter specifications. This
-# allows parameter validity checking in the Python code. Continuing
-# the example above, the statements "cache.blurfl=3" or
-# "cache.assoc='hello'" would both result in runtime errors in Python,
-# since the BaseCache object has no 'blurfl' parameter and the 'assoc'
-# parameter requires an integer, respectively. This magic is done
-# primarily by overriding the special __setattr__ method that controls
-# assignment to object attributes.
-#
-# The Python module provides another class, ConfigNode, which is a
-# superclass of SimObject. ConfigNode implements the parent/child
-# relationship for building the configuration hierarchy tree.
-# Concrete instances of ConfigNode can be used to group objects in the
-# hierarchy, but do not correspond to SimObjects themselves (like a
-# .ini section with "children=" but no "type=".
-#
-# Once a set of Python objects have been instantiated in a hierarchy,
-# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
-# will generate a .ini file. See simple-4cpu.py for an example
-# (corresponding to m5-test/simple-4cpu.ini).
-#
-#####################################################################
-
-#####################################################################
-#
-# ConfigNode/SimObject classes
-#
-# The Python class hierarchy rooted by ConfigNode (which is the base
-# class of SimObject, which in turn is the base class of all other M5
-# SimObject classes) has special attribute behavior. In general, an
-# object in this hierarchy has three categories of attribute-like
-# things:
-#
-# 1. Regular Python methods and variables. These must start with an
-# underscore to be treated normally.
-#
-# 2. SimObject parameters. These values are stored as normal Python
-# attributes, but all assignments to these attributes are checked
-# against the pre-defined set of parameters stored in the class's
-# _param_dict dictionary. Assignments to attributes that do not
-# correspond to predefined parameters, or that are not of the correct
-# type, incur runtime errors.
-#
-# 3. Hierarchy children. The child nodes of a ConfigNode are stored
-# in the node's _children dictionary, but can be accessed using the
-# Python attribute dot-notation (just as they are printed out by the
-# simulator). Children cannot be created using attribute assigment;
-# they must be added by specifying the parent node in the child's
-# constructor or using the '+=' operator.
-
-# The SimObject parameters are the most complex, for a few reasons.
-# First, both parameter descriptions and parameter values are
-# inherited. Thus parameter description lookup must go up the
-# inheritance chain like normal attribute lookup, but this behavior
-# must be explicitly coded since the lookup occurs in each class's
-# _param_dict attribute. Second, because parameter values can be set
-# on SimObject classes (to implement default values), the parameter
-# checking behavior must be enforced on class attribute assignments as
-# well as instance attribute assignments. Finally, because we allow
-# class specialization via inheritance (e.g., see the L1Cache class in
-# the simple-4cpu.py example), we must do parameter checking even on
-# class instantiation. To provide all these features, we use a
-# metaclass to define most of the SimObject parameter behavior for
-# this class hierarchy.
-#
-#####################################################################
-
-# The metaclass for ConfigNode (and thus for everything that derives
-# from ConfigNode, including SimObject). This class controls how new
-# classes that derive from ConfigNode are instantiated, and provides
-# inherited class behavior (just like a class controls how instances
-# of that class are instantiated, and provides inherited instance
-# behavior).
-class MetaConfigNode(type):
-
- # __new__ is called before __init__, and is where the statements
- # in the body of the class definition get loaded into the class's
- # __dict__. We intercept this to filter out parameter assignments
- # and only allow "private" attributes to be passed to the base
- # __new__ (starting with underscore).
- def __new__(cls, name, bases, dict):
- priv_keys = [k for k in dict.iterkeys() if k.startswith('_')]
- priv_dict = {}
- for k in priv_keys: priv_dict[k] = dict[k]; del dict[k]
- # entries left in dict will get passed to __init__, where we'll
- # deal with them as params.
- return super(MetaConfigNode, cls).__new__(cls, name, bases, priv_dict)
-
- # initialization: start out with an empty param dict (makes life
- # simpler if we can assume _param_dict is always valid). Also
- # build inheritance list to simplify searching for inherited
- # params. Finally set parameters specified in class definition
- # (if any).
- def __init__(cls, name, bases, dict):
- super(MetaConfigNode, cls).__init__(cls, name, bases, {})
- # initialize _param_dict to empty
- cls._param_dict = {}
- # __mro__ is the ordered list of classes Python uses for
- # method resolution. We want to pick out the ones that have a
- # _param_dict attribute for doing parameter lookups.
- cls._param_bases = \
- [c for c in cls.__mro__ if hasattr(c, '_param_dict')]
- # initialize attributes with values from class definition
- for (pname, value) in dict.items():
- try:
- setattr(cls, pname, value)
- except Exception, exc:
- print "Error setting '%s' to '%s' on class '%s'\n" \
- % (pname, value, cls.__name__), exc
-
- # set the class's parameter dictionary (called when loading
- # class descriptions)
- def set_param_dict(cls, param_dict):
- # should only be called once (current one should be empty one
- # from __init__)
- assert not cls._param_dict
- cls._param_dict = param_dict
- # initialize attributes with default values
- for (pname, param) in param_dict.items():
- try:
- setattr(cls, pname, param.default)
- except Exception, exc:
- print "Error setting '%s' default on class '%s'\n" \
- % (pname, cls.__name__), exc
-
- # Set the class's parameter dictionary given a code string of
- # parameter initializers (as from an object description file).
- # Note that the caller must pass in the namespace in which to
- # execute the code (usually the caller's globals()), since if we
- # call globals() from inside this function all we get is this
- # module's internal scope.
- def init_params(cls, init_code, ctx):
- dict = {}
- try:
- exec fixPythonIndentation(init_code) in ctx, dict
- except Exception, exc:
- print "Error in %s.init_params:" % cls.__name__, exc
- raise
- cls.set_param_dict(dict)
-
- # Lookup a parameter description by name in the given class. Use
- # the _param_bases list defined in __init__ to go up the
- # inheritance hierarchy if necessary.
- def lookup_param(cls, param_name):
- for c in cls._param_bases:
- param = c._param_dict.get(param_name)
- if param: return param
- return None
-
- # Set attribute (called on foo.attr_name = value when foo is an
- # instance of class cls).
- def __setattr__(cls, attr_name, value):
- # normal processing for private attributes
- if attr_name.startswith('_'):
- type.__setattr__(cls, attr_name, value)
- return
- # no '_': must be SimObject param
- param = cls.lookup_param(attr_name)
- if not param:
- raise AttributeError, \
- "Class %s has no parameter %s" % (cls.__name__, attr_name)
- # It's ok: set attribute by delegating to 'object' class.
- # Note the use of param.make_value() to verify/canonicalize
- # the assigned value
- type.__setattr__(cls, attr_name, param.make_value(value))
-
- # generator that iterates across all parameters for this class and
- # all classes it inherits from
- def all_param_names(cls):
- for c in cls._param_bases:
- for p in c._param_dict.iterkeys():
- yield p
-
-# The ConfigNode class is the root of the special hierarchy. Most of
-# the code in this class deals with the configuration hierarchy itself
-# (parent/child node relationships).
-class ConfigNode(object):
- # Specify metaclass. Any class inheriting from ConfigNode will
- # get this metaclass.
- __metaclass__ = MetaConfigNode
-
- # Constructor. Since bare ConfigNodes don't have parameters, just
- # worry about the name and the parent/child stuff.
- def __init__(self, _name, _parent=None):
- # Type-check _name
- if type(_name) != str:
- if isinstance(_name, ConfigNode):
- # special case message for common error of trying to
- # coerce a SimObject to the wrong type
- raise TypeError, \
- "Attempt to coerce %s to %s" \
- % (_name.__class__.__name__, self.__class__.__name__)
- else:
- raise TypeError, \
- "%s name must be string (was %s, %s)" \
- % (self.__class__.__name__, _name, type(_name))
- # if specified, parent must be a subclass of ConfigNode
- if _parent != None and not isinstance(_parent, ConfigNode):
- raise TypeError, \
- "%s parent must be ConfigNode subclass (was %s, %s)" \
- % (self.__class__.__name__, _name, type(_name))
- self._name = _name
- self._parent = _parent
- if (_parent):
- _parent._add_child(self)
- self._children = {}
- # keep a list of children in addition to the dictionary keys
- # so we can remember the order they were added and print them
- # out in that order.
- self._child_list = []
-
- # When printing (e.g. to .ini file), just give the name.
- def __str__(self):
- return self._name
-
- # Catch attribute accesses that could be requesting children, and
- # satisfy them. Note that __getattr__ is called only if the
- # regular attribute lookup fails, so private and parameter lookups
- # will already be satisfied before we ever get here.
- def __getattr__(self, name):
- try:
- return self._children[name]
- except KeyError:
- raise AttributeError, \
- "Node '%s' has no attribute or child '%s'" \
- % (self._name, name)
-
- # Set attribute. All attribute assignments go through here. Must
- # be private attribute (starts with '_') or valid parameter entry.
- # Basically identical to MetaConfigClass.__setattr__(), except
- # this sets attributes on specific instances rather than on classes.
- def __setattr__(self, attr_name, value):
- if attr_name.startswith('_'):
- object.__setattr__(self, attr_name, value)
- return
- # not private; look up as param
- param = self.__class__.lookup_param(attr_name)
- if not param:
- raise AttributeError, \
- "Class %s has no parameter %s" \
- % (self.__class__.__name__, attr_name)
- # It's ok: set attribute by delegating to 'object' class.
- # Note the use of param.make_value() to verify/canonicalize
- # the assigned value.
- v = param.make_value(value)
- object.__setattr__(self, attr_name, v)
-
- # A little convenient magic: if the parameter is a ConfigNode
- # (or vector of ConfigNodes, or anything else with a
- # '_set_parent_if_none' function attribute) that does not have
- # a parent (and so is not part of the configuration
- # hierarchy), then make this node its parent.
- if hasattr(v, '_set_parent_if_none'):
- v._set_parent_if_none(self)
-
- def _path(self):
- # Return absolute path from root.
- if not self._parent and self._name != 'Universe':
- print >> sys.stderr, "Warning:", self._name, "has no parent"
- parent_path = self._parent and self._parent._path()
- if parent_path and parent_path != 'Universe':
- return parent_path + '.' + self._name
- else:
- return self._name
-
- # Add a child to this node.
- def _add_child(self, new_child):
- # set child's parent before calling this function
- assert new_child._parent == self
- if not isinstance(new_child, ConfigNode):
- raise TypeError, \
- "ConfigNode child must also be of class ConfigNode"
- if new_child._name in self._children:
- raise AttributeError, \
- "Node '%s' already has a child '%s'" \
- % (self._name, new_child._name)
- self._children[new_child._name] = new_child
- self._child_list += [new_child]
-
- # operator overload for '+='. You can say "node += child" to add
- # a child that was created with parent=None. An early attempt
- # at playing with syntax; turns out not to be that useful.
- def __iadd__(self, new_child):
- if new_child._parent != None:
- raise AttributeError, \
- "Node '%s' already has a parent" % new_child._name
- new_child._parent = self
- self._add_child(new_child)
- return self
-
- # Set this instance's parent to 'parent' if it doesn't already
- # have one. See ConfigNode.__setattr__().
- def _set_parent_if_none(self, parent):
- if self._parent == None:
- parent += self
-
- # Print instance info to .ini file.
- def _instantiate(self):
- print '[' + self._path() + ']' # .ini section header
- if self._child_list:
- # instantiate children in same order they were added for
- # backward compatibility (else we can end up with cpu1
- # before cpu0).
- print 'children =', ' '.join([c._name for c in self._child_list])
- self._instantiateParams()
- print
- # recursively dump out children
- for c in self._child_list:
- c._instantiate()
-
- # ConfigNodes have no parameters. Overridden by SimObject.
- def _instantiateParams(self):
- pass
-
-# SimObject is a minimal extension of ConfigNode, implementing a
-# hierarchy node that corresponds to an M5 SimObject. It prints out a
-# "type=" line to indicate its SimObject class, prints out the
-# assigned parameters corresponding to its class, and allows
-# parameters to be set by keyword in the constructor. Note that most
-# of the heavy lifting for the SimObject param handling is done in the
-# MetaConfigNode metaclass.
-
-class SimObject(ConfigNode):
- # initialization: like ConfigNode, but handle keyword-based
- # parameter initializers.
- def __init__(self, _name, _parent=None, **params):
- ConfigNode.__init__(self, _name, _parent)
- for param, value in params.items():
- setattr(self, param, value)
-
- # print type and parameter values to .ini file
- def _instantiateParams(self):
- print "type =", self.__class__._name
- for pname in self.__class__.all_param_names():
- value = getattr(self, pname)
- if value != None:
- print pname, '=', value
-
- def _sim_code(cls):
- name = cls.__name__
- param_names = cls._param_dict.keys()
- param_names.sort()
- code = "BEGIN_DECLARE_SIM_OBJECT_PARAMS(%s)\n" % name
- decls = [" " + cls._param_dict[pname].sim_decl(pname) \
- for pname in param_names]
- code += "\n".join(decls) + "\n"
- code += "END_DECLARE_SIM_OBJECT_PARAMS(%s)\n\n" % name
- code += "BEGIN_INIT_SIM_OBJECT_PARAMS(%s)\n" % name
- inits = [" " + cls._param_dict[pname].sim_init(pname) \
- for pname in param_names]
- code += ",\n".join(inits) + "\n"
- code += "END_INIT_SIM_OBJECT_PARAMS(%s)\n\n" % name
- return code
- _sim_code = classmethod(_sim_code)
-
-#####################################################################
-#
-# Parameter description classes
-#
-# The _param_dict dictionary in each class maps parameter names to
-# either a Param or a VectorParam object. These objects contain the
-# parameter description string, the parameter type, and the default
-# value (loaded from the PARAM section of the .odesc files). The
-# make_value() method on these objects is used to force whatever value
-# is assigned to the parameter to the appropriate type.
-#
-# Note that the default values are loaded into the class's attribute
-# space when the parameter dictionary is initialized (in
-# MetaConfigNode.set_param_dict()); after that point they aren't
-# used.
-#
-#####################################################################
-
-def isNullPointer(value):
- return isinstance(value, NullSimObject)
-
-# Regular parameter.
-class Param(object):
- # Constructor. E.g., Param(Int, "number of widgets", 5)
- def __init__(self, ptype, desc, default=None):
- self.ptype = ptype
- self.ptype_name = self.ptype.__name__
- self.desc = desc
- self.default = default
-
- # Convert assigned value to appropriate type. Force parameter
- # value (rhs of '=') to ptype (or None, which means not set).
- def make_value(self, value):
- # nothing to do if None or already correct type. Also allow NULL
- # pointer to be assigned where a SimObject is expected.
- if value == None or isinstance(value, self.ptype) or \
- isNullPointer(value) and issubclass(self.ptype, ConfigNode):
- return value
- # this type conversion will raise an exception if it's illegal
- return self.ptype(value)
-
- def sim_decl(self, name):
- return 'Param<%s> %s;' % (self.ptype_name, name)
-
- def sim_init(self, name):
- if self.default == None:
- return 'INIT_PARAM(%s, "%s")' % (name, self.desc)
- else:
- return 'INIT_PARAM_DFLT(%s, "%s", %s)' % \
- (name, self.desc, str(self.default))
-
-# The _VectorParamValue class is a wrapper for vector-valued
-# parameters. The leading underscore indicates that users shouldn't
-# see this class; it's magically generated by VectorParam. The
-# parameter values are stored in the 'value' field as a Python list of
-# whatever type the parameter is supposed to be. The only purpose of
-# storing these instead of a raw Python list is that we can override
-# the __str__() method to not print out '[' and ']' in the .ini file.
-class _VectorParamValue(object):
- def __init__(self, value):
- assert isinstance(value, list) or value == None
- self.value = value
-
- def __str__(self):
- return ' '.join(map(str, self.value))
-
- # Set member instance's parents to 'parent' if they don't already
- # have one. Extends "magic" parenting of ConfigNodes to vectors
- # of ConfigNodes as well. See ConfigNode.__setattr__().
- def _set_parent_if_none(self, parent):
- if self.value and hasattr(self.value[0], '_set_parent_if_none'):
- for v in self.value:
- v._set_parent_if_none(parent)
-
-# Vector-valued parameter description. Just like Param, except that
-# the value is a vector (list) of the specified type instead of a
-# single value.
-class VectorParam(Param):
-
- # Inherit Param constructor. However, the resulting parameter
- # will be a list of ptype rather than a single element of ptype.
- def __init__(self, ptype, desc, default=None):
- Param.__init__(self, ptype, desc, default)
-
- # Convert assigned value to appropriate type. If the RHS is not a
- # list or tuple, it generates a single-element list.
- def make_value(self, value):
- if value == None: return value
- if isinstance(value, list) or isinstance(value, tuple):
- # list: coerce each element into new list
- val_list = [Param.make_value(self, v) for v in iter(value)]
- else:
- # singleton: coerce & wrap in a list
- val_list = [Param.make_value(self, value)]
- # wrap list in _VectorParamValue (see above)
- return _VectorParamValue(val_list)
-
- def sim_decl(self, name):
- return 'VectorParam<%s> %s;' % (self.ptype_name, name)
-
- # sim_init inherited from Param
-
-#####################################################################
-#
-# Parameter Types
-#
-# Though native Python types could be used to specify parameter types
-# (the 'ptype' field of the Param and VectorParam classes), it's more
-# flexible to define our own set of types. This gives us more control
-# over how Python expressions are converted to values (via the
-# __init__() constructor) and how these values are printed out (via
-# the __str__() conversion method). Eventually we'll need these types
-# to correspond to distinct C++ types as well.
-#
-#####################################################################
-
-# Integer parameter type.
-class Int(object):
- # Constructor. Value must be Python int or long (long integer).
- def __init__(self, value):
- t = type(value)
- if t == int or t == long:
- self.value = value
- else:
- raise TypeError, "Int param got value %s %s" % (repr(value), t)
-
- # Use Python string conversion. Note that this puts an 'L' on the
- # end of long integers; we can strip that off here if it gives us
- # trouble.
- def __str__(self):
- return str(self.value)
-
-# Counter, Addr, and Tick are just aliases for Int for now.
-class Counter(Int):
- pass
-
-class Addr(Int):
- pass
-
-class Tick(Int):
- pass
-
-# Boolean parameter type.
-class Bool(object):
-
- # Constructor. Typically the value will be one of the Python bool
- # constants True or False (or the aliases true and false below).
- # Also need to take integer 0 or 1 values since bool was not a
- # distinct type in Python 2.2. Parse a bunch of boolean-sounding
- # strings too just for kicks.
- def __init__(self, value):
- t = type(value)
- if t == bool:
- self.value = value
- elif t == int or t == long:
- if value == 1:
- self.value = True
- elif value == 0:
- self.value = False
- elif t == str:
- v = value.lower()
- if v == "true" or v == "t" or v == "yes" or v == "y":
- self.value = True
- elif v == "false" or v == "f" or v == "no" or v == "n":
- self.value = False
- # if we didn't set it yet, it must not be something we understand
- if not hasattr(self, 'value'):
- raise TypeError, "Bool param got value %s %s" % (repr(value), t)
-
- # Generate printable string version.
- def __str__(self):
- if self.value: return "true"
- else: return "false"
-
-# String-valued parameter.
-class String(object):
- # Constructor. Value must be Python string.
- def __init__(self, value):
- t = type(value)
- if t == str:
- self.value = value
- else:
- raise TypeError, "String param got value %s %s" % (repr(value), t)
-
- # Generate printable string version. Not too tricky.
- def __str__(self):
- return self.value
-
-# Special class for NULL pointers. Note the special check in
-# make_param_value() above that lets these be assigned where a
-# SimObject is required.
-class NullSimObject(object):
- # Constructor. No parameters, nothing to do.
- def __init__(self):
- pass
-
- def __str__(self):
- return "NULL"
-
-# The only instance you'll ever need...
-NULL = NullSimObject()
-
-# Enumerated types are a little more complex. The user specifies the
-# type as Enum(foo) where foo is either a list or dictionary of
-# alternatives (typically strings, but not necessarily so). (In the
-# long run, the integer value of the parameter will be the list index
-# or the corresponding dictionary value. For now, since we only check
-# that the alternative is valid and then spit it into a .ini file,
-# there's not much point in using the dictionary.)
-
-# What Enum() must do is generate a new type encapsulating the
-# provided list/dictionary so that specific values of the parameter
-# can be instances of that type. We define two hidden internal
-# classes (_ListEnum and _DictEnum) to serve as base classes, then
-# derive the new type from the appropriate base class on the fly.
-
-
-# Base class for list-based Enum types.
-class _ListEnum(object):
- # Constructor. Value must be a member of the type's map list.
- def __init__(self, value):
- if value in self.map:
- self.value = value
- self.index = self.map.index(value)
- else:
- raise TypeError, "Enum param got bad value '%s' (not in %s)" \
- % (value, self.map)
-
- # Generate printable string version of value.
- def __str__(self):
- return str(self.value)
-
-class _DictEnum(object):
- # Constructor. Value must be a key in the type's map dictionary.
- def __init__(self, value):
- if value in self.map:
- self.value = value
- self.index = self.map[value]
- else:
- raise TypeError, "Enum param got bad value '%s' (not in %s)" \
- % (value, self.map.keys())
-
- # Generate printable string version of value.
- def __str__(self):
- return str(self.value)
-
-# Enum metaclass... calling Enum(foo) generates a new type (class)
-# that derives from _ListEnum or _DictEnum as appropriate.
-class Enum(type):
- # counter to generate unique names for generated classes
- counter = 1
-
- def __new__(cls, map):
- if isinstance(map, dict):
- base = _DictEnum
- keys = map.keys()
- elif isinstance(map, list):
- base = _ListEnum
- keys = map
- else:
- raise TypeError, "Enum map must be list or dict (got %s)" % map
- classname = "Enum%04d" % Enum.counter
- Enum.counter += 1
- # New class derives from selected base, and gets a 'map'
- # attribute containing the specified list or dict.
- return type.__new__(cls, classname, (base,), { 'map': map })
-
-
-#
-# "Constants"... handy aliases for various values.
-#
-
-# For compatibility with C++ bool constants.
-false = False
-true = True
-
-# Some memory range specifications use this as a default upper bound.
-MAX_ADDR = 2**64 - 1
-
-# For power-of-two sizing, e.g. 64*K gives an integer value 65536.
-K = 1024
-M = K*K
-G = K*M
-
-#####################################################################
-
-# Munge an arbitrary Python code string to get it to execute (mostly
-# dealing with indentation). Stolen from isa_parser.py... see
-# comments there for a more detailed description.
-def fixPythonIndentation(s):
- # get rid of blank lines first
- s = re.sub(r'(?m)^\s*\n', '', s);
- if (s != '' and re.match(r'[ \t]', s[0])):
- s = 'if 1:\n' + s
- return s
-
-# Hook to generate C++ parameter code.
-def gen_sim_code(file):
- for objname in sim_object_list:
- print >> file, eval("%s._sim_code()" % objname)
-
-# The final hook to generate .ini files. Called from configuration
-# script once config is built.
-def instantiate(*objs):
- for obj in objs:
- obj._instantiate()
-
-
diff --git a/sim/serialize.cc b/sim/serialize.cc
index 2a5e3d398..846d191e0 100644
--- a/sim/serialize.cc
+++ b/sim/serialize.cc
@@ -29,6 +29,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <errno.h>
#include <fstream>
#include <list>
@@ -37,6 +38,7 @@
#include "base/inifile.hh"
#include "base/misc.hh"
+#include "base/output.hh"
#include "base/str.hh"
#include "base/trace.hh"
#include "sim/config_node.hh"
@@ -332,11 +334,7 @@ SerializeParamContext::~SerializeParamContext()
void
SerializeParamContext::checkParams()
{
- if (serialize_dir.isValid()) {
- checkpointDirBase = serialize_dir;
- } else {
- checkpointDirBase = outputDirectory + "cpt.%012d";
- }
+ checkpointDirBase = simout.resolve(serialize_dir);
// guarantee that directory ends with a '/'
if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
diff --git a/sim/startup.cc b/sim/startup.cc
index ebb4c0bc0..7cc0ac8fb 100644
--- a/sim/startup.cc
+++ b/sim/startup.cc
@@ -29,20 +29,32 @@
#include <list>
#include "base/misc.hh"
-#include "sim/startup.hh"
#include "sim/debug.hh"
+#include "sim/startup.hh"
typedef std::list<StartupCallback *> startupq_t;
-startupq_t &startupq() { static startupq_t queue; return queue; }
-StartupCallback::StartupCallback() { startupq().push_back(this); }
-StartupCallback::~StartupCallback() { startupq().remove(this); }
+
+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();
+ startupq_t::iterator i = startupq->begin();
+ startupq_t::iterator end = startupq->end();
while (i != end) {
(*i)->startup();
diff --git a/sim/syscall_emul.cc b/sim/syscall_emul.cc
index a0cbdf414..22d62e4d1 100644
--- a/sim/syscall_emul.cc
+++ b/sim/syscall_emul.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * 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
@@ -47,17 +47,17 @@ SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc)
DPRINTFR(SyscallVerbose, "%s: syscall %s called\n",
xc->cpu->name(), name);
- int retval = (*funcPtr)(this, callnum, process, xc);
+ SyscallReturn retval = (*funcPtr)(this, callnum, process, xc);
DPRINTFR(SyscallVerbose, "%s: syscall %s returns %d\n",
- xc->cpu->name(), name, retval);
+ xc->cpu->name(), name, retval.value());
- if (!((flags & SyscallDesc::SuppressReturnValue) && retval == 0))
+ if (!(flags & SyscallDesc::SuppressReturnValue))
xc->setSyscallReturn(retval);
}
-int
+SyscallReturn
unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -70,7 +70,7 @@ unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
}
-int
+SyscallReturn
ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -83,7 +83,7 @@ ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
}
-int
+SyscallReturn
exitFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -93,25 +93,28 @@ exitFunc(SyscallDesc *desc, int callnum, Process *process,
}
-int
+SyscallReturn
getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
return VMPageSize;
}
-int
+SyscallReturn
obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
// change brk addr to first arg
Addr new_brk = xc->getSyscallArg(0);
if (new_brk != 0)
+ {
p->brk_point = xc->getSyscallArg(0);
+ }
+ DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
return p->brk_point;
}
-int
+SyscallReturn
closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
int fd = p->sim_fd(xc->getSyscallArg(0));
@@ -119,7 +122,7 @@ closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
}
-int
+SyscallReturn
readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
int fd = p->sim_fd(xc->getSyscallArg(0));
@@ -134,7 +137,7 @@ readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
return bytes_read;
}
-int
+SyscallReturn
writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
int fd = p->sim_fd(xc->getSyscallArg(0));
@@ -151,7 +154,7 @@ writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
}
-int
+SyscallReturn
lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
int fd = p->sim_fd(xc->getSyscallArg(0));
@@ -164,7 +167,7 @@ lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
}
-int
+SyscallReturn
munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
// given that we don't really implement mmap, munmap is really easy
@@ -174,7 +177,7 @@ munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
const char *hostname = "m5.eecs.umich.edu";
-int
+SyscallReturn
gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
int name_len = xc->getSyscallArg(1);
@@ -187,19 +190,19 @@ gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
return 0;
}
-int
+SyscallReturn
unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
std::string path;
if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
- return -EFAULT;
+ return (TheISA::IntReg)-EFAULT;
int result = unlink(path.c_str());
return (result == -1) ? -errno : result;
}
-int
+SyscallReturn
renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
std::string old_name;
@@ -212,7 +215,7 @@ renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
if (xc->mem->readString(new_name, xc->getSyscallArg(1)) != No_Fault)
return -EFAULT;
- int result = rename(old_name.c_str(),new_name.c_str());
+ int64_t result = rename(old_name.c_str(),new_name.c_str());
return (result == -1) ? -errno : result;
}
diff --git a/sim/syscall_emul.hh b/sim/syscall_emul.hh
index 77d104449..51a075a28 100644
--- a/sim/syscall_emul.hh
+++ b/sim/syscall_emul.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * 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
@@ -26,8 +26,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __SYSCALL_EMUL_HH__
-#define __SYSCALL_EMUL_HH__
+#ifndef __SIM_SYSCALL_EMUL_HH__
+#define __SIM_SYSCALL_EMUL_HH__
///
/// @file syscall_emul.hh
@@ -35,14 +35,16 @@
/// This file defines objects used to emulate syscalls from the target
/// application on the host machine.
+#include <errno.h>
#include <string>
#include "base/intmath.hh" // for RoundUp
-#include "targetarch/isa_traits.hh" // for Addr
#include "mem/functional_mem/functional_memory.hh"
+#include "targetarch/isa_traits.hh" // for Addr
-class Process;
-class ExecContext;
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "sim/process.hh"
///
/// System call descriptor.
@@ -52,7 +54,7 @@ class SyscallDesc {
public:
/// Typedef for target syscall handler functions.
- typedef int (*FuncPtr)(SyscallDesc *, int num,
+ typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
Process *, ExecContext *);
const char *name; //!< Syscall name (e.g., "open").
@@ -156,46 +158,76 @@ class TypedBufferArg : public BaseBufferArg
/// Handler for unimplemented syscalls that we haven't thought about.
-int unimplementedFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// 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.
-int ignoreFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn ignoreFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target exit() handler: terminate simulation.
-int exitFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn exitFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target getpagesize() handler.
-int getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target obreak() handler: set brk address.
-int obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target close() handler.
-int closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target read() handler.
-int readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target write() handler.
-int writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target lseek() handler.
-int lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target munmap() handler.
-int munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target gethostname() handler.
-int gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target unlink() handler.
-int unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// Target rename() handler.
-int renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// This struct is used to build an target-OS-dependent table that
+/// maps the target's open() flags to the host open() flags.
+struct OpenFlagTransTable {
+ int tgtFlag; //!< Target system flag value.
+ int hostFlag; //!< Corresponding host system flag value.
+};
+
+
+
+/// 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 cycles_per_usec = ticksPerSecond / one_million;
+
+ int elapsed_usecs = curTick / cycles_per_usec;
+ sec = elapsed_usecs / one_million;
+ usec = elapsed_usecs % one_million;
+}
//////////////////////////////////////////////////////////////////////
//
@@ -208,7 +240,7 @@ int renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
/// only to find out if their stdout is a tty, to determine whether to
/// do line or block buffering.
template <class OS>
-int
+SyscallReturn
ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -238,17 +270,9 @@ ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
}
}
-/// This struct is used to build an target-OS-dependent table that
-/// maps the target's open() flags to the host open() flags.
-struct OpenFlagTransTable {
- int tgtFlag; //!< Target system flag value.
- int hostFlag; //!< Corresponding host system flag value.
-};
-
-
/// Target open() handler.
template <class OS>
-int
+SyscallReturn
openFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -260,7 +284,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
if (path == "/dev/sysdev0") {
// This is a memory-mapped high-resolution timer device on Alpha.
// We don't support it, so just punt.
- DCOUT(SyscallWarnings) << "Ignoring open(" << path << ", ...)" << endl;
+ DCOUT(SyscallWarnings) << "Ignoring open(" << path << ", ...)" << std::endl;
return -ENOENT;
}
@@ -278,7 +302,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
// any target flags left?
if (tgtFlags != 0)
- cerr << "Syscall: open: cannot decode flags: " << tgtFlags << endl;
+ std::cerr << "Syscall: open: cannot decode flags: " << tgtFlags << std::endl;
#ifdef __CYGWIN32__
hostFlags |= O_BINARY;
@@ -293,7 +317,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target stat() handler.
template <class OS>
-int
+SyscallReturn
statFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -306,7 +330,7 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
int result = stat(path.c_str(), &hostBuf);
if (result < 0)
- return -errno;
+ return errno;
OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
@@ -316,7 +340,7 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target lstat() handler.
template <class OS>
-int
+SyscallReturn
lstatFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -338,7 +362,7 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target fstat() handler.
template <class OS>
-int
+SyscallReturn
fstatFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -374,7 +398,7 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process,
/// file descriptor, and fail (or implement!) a non-anonymous mmap to
/// anything else.
template <class OS>
-int
+SyscallReturn
mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
{
Addr start = xc->getSyscallArg(0);
@@ -386,8 +410,8 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
if (start == 0) {
// user didn't give an address... pick one from our "mmap region"
- start = p->mmap_base;
- p->mmap_base += RoundUp<Addr>(length, VMPageSize);
+ start = p->mmap_end;
+ p->mmap_end += RoundUp<Addr>(length, VMPageSize);
}
if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
@@ -400,7 +424,7 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
/// Target getrlimit() handler.
template <class OS>
-int
+SyscallReturn
getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -414,7 +438,7 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
break;
default:
- cerr << "getrlimitFunc: unimplemented resource " << resource << endl;
+ std::cerr << "getrlimitFunc: unimplemented resource " << resource << std::endl;
abort();
break;
}
@@ -423,31 +447,9 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
return 0;
}
-/// 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 cycles_per_usec = ticksPerSecond / one_million;
-
- int elapsed_usecs = curTick / cycles_per_usec;
- sec = elapsed_usecs / one_million;
- usec = elapsed_usecs % one_million;
-}
-
-
/// Target gettimeofday() handler.
template <class OS>
-int
+SyscallReturn
gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -464,7 +466,7 @@ gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target getrusage() function.
template <class OS>
-int
+SyscallReturn
getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
@@ -476,7 +478,7 @@ getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
// plow ahead
DCOUT(SyscallWarnings)
<< "Warning: getrusage() only supports RUSAGE_SELF."
- << " Parameter " << who << " ignored." << endl;
+ << " Parameter " << who << " ignored." << std::endl;
}
getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
@@ -502,6 +504,4 @@ getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
return 0;
}
-
-
-#endif // __SYSCALL_EMUL_HH__
+#endif // __SIM_SYSCALL_EMUL_HH__
diff --git a/sim/universe.cc b/sim/universe.cc
index 824b985fa..9137baaf0 100644
--- a/sim/universe.cc
+++ b/sim/universe.cc
@@ -26,9 +26,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-
#include <cstring>
#include <fstream>
#include <list>
@@ -36,9 +33,11 @@
#include <vector>
#include "base/misc.hh"
-#include "sim/universe.hh"
+#include "base/output.hh"
+#include "sim/builder.hh"
#include "sim/host.hh"
-#include "sim/param.hh"
+#include "sim/sim_object.hh"
+#include "sim/universe.hh"
using namespace std;
@@ -49,101 +48,61 @@ double __ticksPerUS;
double __ticksPerNS;
double __ticksPerPS;
-string outputDirectory;
+bool fullSystem;
ostream *outputStream;
ostream *configStream;
-class UniverseParamContext : public ParamContext
+// Dummy Object
+class Root : public SimObject
{
public:
- UniverseParamContext(const string &is)
- : ParamContext(is, OutputInitPhase) {}
- void checkParams();
+ Root(const std::string &name) : SimObject(name) {}
};
-UniverseParamContext universe("Universe");
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root)
+
+ Param<bool> full_system;
+ Param<Tick> frequency;
+ Param<string> output_file;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Root)
-Param<Tick> universe_freq(&universe, "frequency", "tick frequency",
- 200000000);
+BEGIN_INIT_SIM_OBJECT_PARAMS(Root)
-Param<string> universe_output_dir(&universe, "output_dir",
- "directory to output data to",
- ".");
-Param<string> universe_output_file(&universe, "output_file",
- "file to dump simulator output to",
- "cout");
-Param<string> universe_config_output_file(&universe, "config_output_file",
- "file to dump simulator config to",
- "m5config.out");
+ INIT_PARAM(full_system, "full system simulation"),
+ INIT_PARAM(frequency, "tick frequency"),
+ INIT_PARAM(output_file, "file to dump simulator output to")
-void
-UniverseParamContext::checkParams()
+END_INIT_SIM_OBJECT_PARAMS(Root)
+
+CREATE_SIM_OBJECT(Root)
{
- ticksPerSecond = universe_freq;
+ static bool created = false;
+ if (created)
+ panic("only one root object allowed!");
+
+ created = true;
+ fullSystem = full_system;
+
+#ifdef FULL_SYSTEM
+ if (!fullSystem)
+ panic("FULL_SYSTEM compiled and configuration not full_system");
+#else
+ if (fullSystem)
+ panic("FULL_SYSTEM not compiled but configuration is full_system");
+#endif
+
+ ticksPerSecond = frequency;
double freq = double(ticksPerSecond);
__ticksPerMS = freq / 1.0e3;
__ticksPerUS = freq / 1.0e6;
__ticksPerNS = freq / 1.0e9;
__ticksPerPS = freq / 1.0e12;
- if (universe_output_dir.isValid()) {
- outputDirectory = universe_output_dir;
-
- // guarantee that directory ends with a '/'
- if (outputDirectory[outputDirectory.size() - 1] != '/')
- outputDirectory += "/";
-
- if (mkdir(outputDirectory.c_str(), 0777) < 0) {
- if (errno != EEXIST) {
- panic("%s\ncould not make output directory: %s\n",
- strerror(errno), outputDirectory);
- }
- }
- }
-
- outputStream = makeOutputStream(universe_output_file);
- configStream = universe_config_output_file.isValid()
- ? makeOutputStream(universe_config_output_file)
- : outputStream;
-}
-
-
-std::ostream *
-makeOutputStream(std::string &name)
-{
- if (name == "cerr" || name == "stderr")
- return &std::cerr;
+ outputStream = simout.find(output_file);
- if (name == "cout" || name == "stdout")
- return &std::cout;
-
- string path = (name[0] != '/') ? outputDirectory + name : name;
-
- // have to dynamically allocate a stream since we're going to
- // return it... though the caller can't easily free it since it
- // may be cerr or cout. need GC!
- ofstream *s = new ofstream(path.c_str(), ios::trunc);
-
- if (!s->is_open())
- fatal("Cannot open file %s", path);
-
- return s;
+ return new Root(getInstanceName());
}
-
-void
-closeOutputStream(std::ostream *os)
-{
- // can't close cerr or cout
- if (os == &std::cerr || os == &std::cout)
- return;
-
- // can only close ofstreams, not generic ostreams, so try to
- // downcast and close only if the downcast succeeds
- std::ofstream *ofs = dynamic_cast<std::ofstream *>(os);
- if (ofs)
- ofs->close();
-}
-
-
+REGISTER_SIM_OBJECT("Root", Root)