/*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
///
#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"
+#include "cpu/base.hh"
+#include "cpu/smt.hh"
+#include "python/pyconfig.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
-#include "sim/sim_init.hh"
#include "sim/sim_object.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
-#include "sim/universe.hh"
+#include "sim/root.hh"
using namespace std;
}
/// Simulator executable name
-const char *myProgName = "";
+char *myProgName = "";
/// Show brief help message.
-static void
+void
showBriefHelp(ostream &out)
{
- out << "Usage: " << myProgName
- << " [-hn] [-Dname[=def]] [-Uname] [-I[dir]] "
- << "[--<section>:<param>=<value>] [<config file> ...]" << endl
- << " -h: print long help (including parameter listing)" << endl
- << " -n: don't load default.ini" << endl
- << " -u: don't quit on unreferenced parameters" << endl
- << " -D,-U,-I: passed to cpp for preprocessing .ini files" << endl;
-}
-
-/// Show verbose help message. Includes parameter listing from
-/// showBriefHelp(), plus an exhaustive list of ini-file parameters
-/// and SimObjects (with their parameters).
-static void
-showLongHelp(ostream &out)
-{
- showBriefHelp(out);
-
- out << endl
- << endl
- << "-----------------" << endl
- << "Global Parameters" << endl
- << "-----------------" << endl
- << endl;
-
- ParamContext::describeAllContexts(out);
-
- out << endl
- << endl
- << "-----------------" << endl
- << "Simulator Objects" << endl
- << "-----------------" << endl
- << endl;
-
- SimObjectClass::describeAllClasses(out);
+ 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 (ends in .py)\n\n",
+ prog);
+
+ ccprintf(out, "%s -X\n -X extract embedded files\n\n", prog);
+ ccprintf(out, "%s -h\n -h print short help\n\n", prog);
}
/// Print welcome message.
-static void
+void
sayHello(ostream &out)
{
extern const char *compileDate; // from date.cc
/// 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];
out << endl << endl;
}
-
-///
-/// 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;
-
-/// Check for a default.ini file and load it if necessary.
-static void
-handleDefaultIni(bool &loadIt, vector<char *> &cppArgs)
+char *
+getOptionString(int &index, int argc, char **argv)
{
- struct stat sb;
+ char *option = argv[index] + 2;
+ if (*option != '\0')
+ return option;
- if (loadIt) {
- if (stat("default.ini", &sb) == 0) {
- if (!simConfigDB.loadCPP("default.ini", cppArgs)) {
- cout << "Error processing file default.ini" << endl;
- exit(1);
- }
- }
+ // 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]);
- // set this whether it actually was found or not, so we don't
- // bother to check again next time
- loadIt = false;
- }
+ return argv[index];
}
-
-/// M5 entry point.
int
main(int argc, char **argv)
{
signal(SIGINT, exitNowHandler); // dump final stats and exit
signal(SIGABRT, abortHandler);
- sayHello(cerr);
-
- // Initialize statistics database
- Stats::InitSimStats();
-
- vector<char *> cppArgs;
+ bool configfile_found = false;
+ PythonConfig pyconfig;
+ string outdir;
- // Should we use default.ini if it exists? By default, yes. (Use
- // -n to override.)
- bool loadDefaultIni = true;
+ if (argc < 2) {
+ showBriefHelp(cerr);
+ exit(1);
+ }
- // 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;
+ sayHello(cerr);
- // Parse command-line options. The tricky part here is figuring
- // out whether to look for & load default.ini, and if needed,
- // doing so at the right time w.r.t. processing the other
- // parameters.
- //
+ // Parse command-line options.
// Since most of the complex options are handled through the
// config database, we don't mess with getopts, and just parse
// manually.
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);
+ showBriefHelp(cerr);
exit(1);
- case 'n':
- // -n: don't load default.ini
- if (!loadDefaultIni) {
- cerr << "Warning: -n option needs to precede any "
- << "explicit configuration file name " << endl
- << " or command-line configuration parameter."
- << endl;
- }
- loadDefaultIni = false;
- break;
+ case 'E':
+ option = getOptionString(i, argc, argv);
+ if (!split_first(option, var, val, '='))
+ val = "True";
- case 'u':
- // -u: don't quit on unreferenced parameters
- quitOnUnreferenced = false;
+ 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>'
-
- // Load default.ini if necessary -- see comment in
- // else clause below.
- handleDefaultIni(loadDefaultIni, cppArgs);
-
- 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);
+ panic("invalid argument '%s'\n", arg_str);
}
- }
- else {
- // no '-', treat as config file name
+ } else {
+ string file(arg_str);
+ string base, ext;
- // If we haven't loaded default.ini yet, and we want to,
- // now is the time. Can't do it sooner because we need to
- // look for '-n', can't do it later since we want
- // default.ini loaded first (so that any other settings
- // override it).
- handleDefaultIni(loadDefaultIni, cppArgs);
+ if (!split_last(file, base, ext, '.') || ext != "py")
+ panic("Config file '%s' must end in '.py'\n", file);
- if (!simConfigDB.loadCPP(arg_str, cppArgs)) {
- cprintf("Error processing file %s\n", arg_str);
- exit(1);
- }
+ pyconfig.load(file);
+ configfile_found = true;
}
}
- // Final check for default.ini, in case no config files or
- // command-line config parameters were given.
- handleDefaultIni(loadDefaultIni, cppArgs);
+ 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(builderStream());
+ 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();
// Restore checkpointed state, if any.
configHierarchy.unserializeSimObjects();
// 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();
// 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);
- }
-
- SimInit();
warn("Entering event queue. Starting simulation...\n");
-
+ SimStartup();
while (!mainEventQueue.empty()) {
assert(curTick <= mainEventQueue.nextTick() &&
"event scheduled in the past");