diff options
Diffstat (limited to 'src/sim/main.cc')
-rw-r--r-- | src/sim/main.cc | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/src/sim/main.cc b/src/sim/main.cc new file mode 100644 index 000000000..741926056 --- /dev/null +++ b/src/sim/main.cc @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2000-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Raasch + * Nathan Binkert + * Steve Reinhardt + */ + +/// +/// @file sim/main.cc +/// +#include <Python.h> // must be before system headers... see Python docs + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <libgen.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> + +#include <list> +#include <string> +#include <vector> + +#include "base/callback.hh" +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/pollevent.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "cpu/base.hh" +#include "cpu/smt.hh" +#include "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_object.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" +#include "sim/root.hh" + +using namespace std; + +// See async.h. +volatile bool async_event = false; +volatile bool async_dump = false; +volatile bool async_dumpreset = false; +volatile bool async_exit = false; +volatile bool async_io = false; +volatile bool async_alarm = false; + +/// Stats signal handler. +void +dumpStatsHandler(int sigtype) +{ + async_event = true; + async_dump = true; +} + +void +dumprstStatsHandler(int sigtype) +{ + async_event = true; + async_dumpreset = true; +} + +/// Exit signal handler. +void +exitNowHandler(int sigtype) +{ + async_event = true; + async_exit = true; +} + +/// Abort signal handler. +void +abortHandler(int sigtype) +{ + cerr << "Program aborted at cycle " << curTick << endl; + +#if TRACING_ON + // dump trace buffer, if there is one + Trace::theLog.dump(cerr); +#endif +} + + +const char *briefCopyright = +"Copyright (c) 2001-2006\n" +"The Regents of The University of Michigan\n" +"All Rights Reserved\n"; + +/// Print welcome message. +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 %d\n", compileDate); + ccprintf(out, "M5 started %s\n", Time::start); + + char *host = getenv("HOSTNAME"); + if (!host) + host = getenv("HOST"); + + if (host) + ccprintf(out, "M5 executing on %s\n", host); +} + + +extern "C" { void init_main(); } + +int +main(int argc, char **argv) +{ + sayHello(cerr); + + signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths + signal(SIGTRAP, SIG_IGN); + signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats + signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats + signal(SIGINT, exitNowHandler); // dump final stats and exit + signal(SIGABRT, abortHandler); + + Py_SetProgramName(argv[0]); + + // default path to m5 python code is the currently executing + // file... Python ZipImporter will find embedded zip archive + char *pythonpath = argv[0]; + + bool interactive = false; + bool getopt_done = false; + do { + switch (getopt(argc, argv, "+p:i")) { + // -p <path> prepends <path> to PYTHONPATH instead of + // using built-in zip archive. Useful when + // developing/debugging changes to built-in Python + // libraries, as the new Python can be tested without + // building a new m5 binary. + case 'p': + pythonpath = optarg; + break; + + // -i forces entry into interactive mode after the + // supplied script is executed (just like the -i option to + // the Python interpreter). + case 'i': + interactive = true; + break; + + case -1: + getopt_done = true; + break; + + default: + fatal("Unrecognized option %c\n", optopt); + } + } while (!getopt_done); + + // Fix up argc & argv to hide arguments we just processed. + // getopt() sets optind to the index of the first non-processed + // argv element. + argc -= optind; + argv += optind; + + // Set up PYTHONPATH to make sure the m5 module is found + string newpath(pythonpath); + + char *oldpath = getenv("PYTHONPATH"); + if (oldpath != NULL) { + newpath += ":"; + newpath += oldpath; + } + + if (setenv("PYTHONPATH", newpath.c_str(), true) == -1) + fatal("setenv: %s\n", strerror(errno)); + + // initialize embedded Python interpreter + Py_Initialize(); + PySys_SetArgv(argc, argv); + + // initialize SWIG 'main' module + init_main(); + + if (argc > 0) { + // extra arg(s): first is script file, remaining ones are args + // to script file + char *filename = argv[0]; + FILE *fp = fopen(filename, "r"); + if (!fp) { + fatal("cannot open file '%s'\n", filename); + } + + PyRun_AnyFile(fp, filename); + } else { + // no script file argument... force interactive prompt + interactive = true; + } + + if (interactive) { + // The following code to import readline was copied from Python + // 2.4.3's Modules/main.c. + // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 + // Python Software Foundation; All Rights Reserved + // We should only enable this if we're actually using an + // interactive prompt. + PyObject *v; + v = PyImport_ImportModule("readline"); + if (v == NULL) + PyErr_Clear(); + else + Py_DECREF(v); + + PyRun_InteractiveLoop(stdin, "stdin"); + } + + // clean up Python intepreter. + Py_Finalize(); +} + + +/// Initialize C++ configuration. Exported to Python via SWIG; invoked +/// from m5.instantiate(). +void +initialize() +{ + configStream = simout.find("config.out"); + + // The configuration database is now complete; start processing it. + IniFile inifile; + inifile.load("config.ini"); + + // 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(inifile); + ParamContext::checkAllContexts(); + + // Echo all parameter settings to stats file as well. + ParamContext::showAllContexts(*configStream); + + // Any objects that can't connect themselves until after construction should + // do so now + SimObject::connectAll(); + + // 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 (inifile.printUnreferenced()) + panic("unreferenced sections/entries in the intermediate ini file"); + + 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 + Stats::check(); + + // Reset to put the stats in a consistent state. + Stats::reset(); + + SimStartup(); +} + + +/** Simulate for num_cycles additional cycles. If num_cycles is -1 + * (the default), do not limit simulation; some other event must + * terminate the loop. Exported to Python via SWIG. + * @return The SimLoopExitEvent that caused the loop to exit. + */ +SimLoopExitEvent * +simulate(Tick num_cycles = -1) +{ + warn("Entering event queue @ %d. Starting simulation...\n", curTick); + + // Fix up num_cycles. Special default value -1 means simulate + // "forever"... schedule event at MaxTick just to be safe. + // Otherwise it's a delta for additional cycles to simulate past + // curTick, and thus must be non-negative. + if (num_cycles == -1) + num_cycles = MaxTick; + else if (num_cycles < 0) + fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); + else + num_cycles = curTick + num_cycles; + + Event *limit_event = new SimLoopExitEvent(num_cycles, + "simulate() limit reached"); + + while (1) { + // there should always be at least one event (the SimLoopExitEvent + // we just scheduled) in the queue + assert(!mainEventQueue.empty()); + assert(curTick <= mainEventQueue.nextTick() && + "event scheduled in the past"); + + // forward current cycle to the time of the first event on the + // queue + curTick = mainEventQueue.nextTick(); + Event *exit_event = mainEventQueue.serviceOne(); + if (exit_event != NULL) { + // hit some kind of exit event; return to Python + // event must be subclass of SimLoopExitEvent... + SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); + if (se_event == NULL) + panic("Bogus exit event class!"); + + // if we didn't hit limit_event, delete it + if (se_event != limit_event) { + assert(limit_event->scheduled()); + limit_event->deschedule(); + delete limit_event; + } + + return se_event; + } + + if (async_event) { + async_event = false; + if (async_dump) { + async_dump = false; + + using namespace Stats; + SetupEvent(Dump, curTick); + } + + if (async_dumpreset) { + async_dumpreset = false; + + using namespace Stats; + SetupEvent(Dump | Reset, curTick); + } + + if (async_exit) { + async_exit = false; + exitSimLoop("user interrupt received"); + } + + if (async_io || async_alarm) { + async_io = false; + async_alarm = false; + pollQueue.service(); + } + } + } + + // not reached... only exit is return on SimLoopExitEvent +} + +/** + * Queue of C++ callbacks to invoke on simulator exit. + */ +CallbackQueue exitCallbacks; + +/** + * Register an exit callback. + */ +void +registerExitCallback(Callback *callback) +{ + exitCallbacks.add(callback); +} + +/** + * Do C++ simulator exit processing. Exported to SWIG to be invoked + * when simulator terminates via Python's atexit mechanism. + */ +void +doExitCleanup() +{ + exitCallbacks.process(); + exitCallbacks.clear(); + + cout.flush(); + + ParamContext::cleanupAllContexts(); + + // print simulation stats + Stats::DumpNow(); +} |