diff options
Diffstat (limited to 'sim/main.cc')
-rw-r--r-- | sim/main.cc | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/sim/main.cc b/sim/main.cc new file mode 100644 index 000000000..84f8e78cc --- /dev/null +++ b/sim/main.cc @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2003 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. + */ + +/// +/// @file sim/main.cc +/// +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <signal.h> + +#include <string> +#include <vector> + +#include "host.hh" +#include "misc.hh" +#include "stats.hh" + +#include "copyright.hh" +#include "inifile.hh" +#include "configfile.hh" +#include "pollevent.hh" +#include "statistics.hh" +#include "sim_events.hh" +#include "sim_exit.hh" +#include "sim_object.hh" +#include "sim_stats.hh" +#include "sim_time.hh" +#include "smt.hh" + +#include "base_cpu.hh" +#include "async.hh" + +using namespace std; + +// See async.h. +volatile bool async_event = false; +volatile bool async_dump = false; +volatile bool async_exit = false; +volatile bool async_io = false; +volatile bool async_alarm = false; + +/// Stats signal handler. +void +dumpStatsHandler(int sigtype) +{ + async_event = true; + async_dump = true; +} + +/// Exit signal handler. +void +exitNowHandler(int sigtype) +{ + async_event = true; + async_exit = true; +} + +/// Simulator executable name +const char *myProgName = ""; + +/// Show brief help message. +static 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); +} + +/// Print welcome message. +static void +sayHello(ostream &out) +{ + extern const char *compileDate; // from date.cc + + ccprintf(out, "M5 Simulator System\n"); + // display copyright + ccprintf(out, "%s\n", briefCopyright); + ccprintf(out, "M5 compiled on %d\n", compileDate); + + char *host = getenv("HOSTNAME"); + if (!host) + host = getenv("HOST"); + + if (host) + ccprintf(out, "M5 executing on %s\n", host); + + ccprintf(out, "M5 simulation started %s\n", Time::start); +} + +/// +/// 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 +echoCommandLine(int argc, char **argv, ostream &out) +{ + out << "command line: " << argv[0]; + for (int i = 1; i < argc; i++) { + string arg(argv[i]); + + out << ' '; + + // If the arg contains spaces, we need to quote it. + // The rest of this is overkill to make it look purty. + + // print dashes first outside quotes + int non_dash_pos = arg.find_first_not_of("-"); + out << arg.substr(0, non_dash_pos); // print dashes + string body = arg.substr(non_dash_pos); // the rest + + // if it's an assignment, handle the lhs & rhs separately + int eq_pos = body.find("="); + if (eq_pos == string::npos) { + out << quote(body); + } + else { + string lhs(body.substr(0, eq_pos)); + string rhs(body.substr(eq_pos + 1)); + + out << quote(lhs) << "=" << quote(rhs); + } + } + 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) +{ + struct stat sb; + + if (loadIt) { + if (stat("default.ini", &sb) == 0) { + if (!simConfigDB.loadCPP("default.ini", cppArgs)) { + cout << "Error processing file default.ini" << endl; + exit(1); + } + } + + // set this whether it actually was found or not, so we don't + // bother to check again next time + loadIt = false; + } +} + + +/// M5 entry point. +int +main(int argc, char **argv) +{ + // Save off program name + myProgName = argv[0]; + + signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths + signal(SIGPIPE, SIG_IGN); + signal(SIGTRAP, SIG_IGN); + signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats + signal(SIGINT, exitNowHandler); // dump final stats and exit + + sayHello(cerr); + + // Initialize statistics database + init_old_stats(); + initBaseStats(); + + vector<char *> cppArgs; + + // Should we use default.ini if it exists? By default, yes. (Use + // -n to override.) + bool loadDefaultIni = true; + + // 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; + + // 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. + // + // 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] == '-') { + + // switch on second char + switch (arg_str[1]) { + case 'h': + // -h: show help + showLongHelp(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 'u': + // -u: don't quit on unreferenced parameters + quitOnUnreferenced = false; + 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); + 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); + } + break; + + default: + showBriefHelp(cerr); + ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str); + exit(0); + } + } + else { + // no '-', treat as config file name + + // 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 (!simConfigDB.loadCPP(arg_str, cppArgs)) { + cprintf("Error processing file %s\n", arg_str); + exit(1); + } + } + } + + // Final check for default.ini, in case no config files or + // command-line config parameters were given. + handleDefaultIni(loadDefaultIni, cppArgs); + + // The configuration database is now complete; start processing it. + + // Parse and check all non-config-hierarchy parameters. + ParamContext::parseAllContexts(simConfigDB); + 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 (statStreamIsFile) + sayHello(*statStream); + + // Echo command line and all parameter settings to stats file as well. + echoCommandLine(argc, argv, *statStream); + ParamContext::showAllContexts(*statStream); + + // Now process the configuration hierarchy and create the SimObjects. + ConfigHierarchy configHierarchy(simConfigDB); + configHierarchy.build(); + configHierarchy.createSimObjects(); + + // 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); + } + + SimObject::regAllStats(); + + // uncomment the following to get PC-based execution-time profile +#ifdef DO_PROFILE + init_profile((char *)&_init, (char *)&_fini); +#endif + + // Check to make sure that the stats package is properly initialized + Statistics::check(); + + // 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); + } + + while (!mainEventQueue.empty()) { + assert(curTick <= mainEventQueue.nextTick() && + "event scheduled in the past"); + + // forward current cycle to the time of the first event on the + // queue + curTick = mainEventQueue.nextTick(); + mainEventQueue.serviceOne(); + + if (async_event) { + async_event = false; + if (async_dump) { + async_dump = false; + new DumpStatsEvent(); + } + + if (async_exit) { + async_exit = false; + new SimExitEvent("User requested STOP"); + } + + if (async_io || async_alarm) { + async_io = false; + async_alarm = false; + pollQueue.service(); + } + } + } + + // This should never happen... every conceivable way for the + // simulation to terminate (hit max cycles/insts, signal, + // simulated system halts/exits) generates an exit event, so we + // should never run out of events on the queue. + exitNow("improperly exited event loop!", 1); + + return 0; +} |