1/* 2 * Copyright (c) 2000-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Raasch 29 * Nathan Binkert 30 * Steve Reinhardt 31 */ 32 33/// 34/// @file sim/main.cc 35/// 36#include <Python.h> // must be before system headers... see Python docs 37 38#include <sys/types.h> 39#include <sys/stat.h> 40#include <errno.h> 41#include <libgen.h> 42#include <stdlib.h> 43#include <signal.h> 44#include <getopt.h> 45 46#include <list> 47#include <string> 48#include <vector> 49 50#include "base/callback.hh" 51#include "base/inifile.hh" 52#include "base/misc.hh" 53#include "base/output.hh" 54#include "base/pollevent.hh" 55#include "base/statistics.hh" 56#include "base/str.hh" 57#include "base/time.hh"
| 1/* 2 * Copyright (c) 2000-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Raasch 29 * Nathan Binkert 30 * Steve Reinhardt 31 */ 32 33/// 34/// @file sim/main.cc 35/// 36#include <Python.h> // must be before system headers... see Python docs 37 38#include <sys/types.h> 39#include <sys/stat.h> 40#include <errno.h> 41#include <libgen.h> 42#include <stdlib.h> 43#include <signal.h> 44#include <getopt.h> 45 46#include <list> 47#include <string> 48#include <vector> 49 50#include "base/callback.hh" 51#include "base/inifile.hh" 52#include "base/misc.hh" 53#include "base/output.hh" 54#include "base/pollevent.hh" 55#include "base/statistics.hh" 56#include "base/str.hh" 57#include "base/time.hh"
|
| 58#include "config/pythonhome.hh"
|
58#include "cpu/base.hh" 59#include "cpu/smt.hh" 60#include "mem/mem_object.hh" 61#include "mem/port.hh" 62#include "sim/async.hh" 63#include "sim/builder.hh" 64#include "sim/host.hh" 65#include "sim/serialize.hh" 66#include "sim/sim_events.hh" 67#include "sim/sim_exit.hh" 68#include "sim/sim_object.hh" 69#include "sim/system.hh" 70#include "sim/stat_control.hh" 71#include "sim/stats.hh" 72#include "sim/root.hh" 73 74using namespace std; 75 76// See async.h. 77volatile bool async_event = false; 78volatile bool async_dump = false; 79volatile bool async_dumpreset = false; 80volatile bool async_exit = false; 81volatile bool async_io = false; 82volatile bool async_alarm = false; 83 84/// Stats signal handler. 85void 86dumpStatsHandler(int sigtype) 87{ 88 async_event = true; 89 async_dump = true; 90} 91 92void 93dumprstStatsHandler(int sigtype) 94{ 95 async_event = true; 96 async_dumpreset = true; 97} 98 99/// Exit signal handler. 100void 101exitNowHandler(int sigtype) 102{ 103 async_event = true; 104 async_exit = true; 105} 106 107/// Abort signal handler. 108void 109abortHandler(int sigtype) 110{ 111 cerr << "Program aborted at cycle " << curTick << endl; 112 113#if TRACING_ON 114 // dump trace buffer, if there is one 115 Trace::theLog.dump(cerr); 116#endif 117} 118 119extern "C" { void init_cc_main(); } 120 121int 122main(int argc, char **argv) 123{ 124 signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths 125 signal(SIGTRAP, SIG_IGN); 126 signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats 127 signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats 128 signal(SIGINT, exitNowHandler); // dump final stats and exit 129 signal(SIGABRT, abortHandler); 130 131 Py_SetProgramName(argv[0]); 132 133 // default path to m5 python code is the currently executing 134 // file... Python ZipImporter will find embedded zip archive. 135 // The M5_ARCHIVE environment variable can be used to override this. 136 char *m5_archive = getenv("M5_ARCHIVE"); 137 string pythonpath = m5_archive ? m5_archive : argv[0]; 138 139 char *oldpath = getenv("PYTHONPATH"); 140 if (oldpath != NULL) { 141 pythonpath += ":"; 142 pythonpath += oldpath; 143 } 144 145 if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1) 146 fatal("setenv: %s\n", strerror(errno)); 147
| 59#include "cpu/base.hh" 60#include "cpu/smt.hh" 61#include "mem/mem_object.hh" 62#include "mem/port.hh" 63#include "sim/async.hh" 64#include "sim/builder.hh" 65#include "sim/host.hh" 66#include "sim/serialize.hh" 67#include "sim/sim_events.hh" 68#include "sim/sim_exit.hh" 69#include "sim/sim_object.hh" 70#include "sim/system.hh" 71#include "sim/stat_control.hh" 72#include "sim/stats.hh" 73#include "sim/root.hh" 74 75using namespace std; 76 77// See async.h. 78volatile bool async_event = false; 79volatile bool async_dump = false; 80volatile bool async_dumpreset = false; 81volatile bool async_exit = false; 82volatile bool async_io = false; 83volatile bool async_alarm = false; 84 85/// Stats signal handler. 86void 87dumpStatsHandler(int sigtype) 88{ 89 async_event = true; 90 async_dump = true; 91} 92 93void 94dumprstStatsHandler(int sigtype) 95{ 96 async_event = true; 97 async_dumpreset = true; 98} 99 100/// Exit signal handler. 101void 102exitNowHandler(int sigtype) 103{ 104 async_event = true; 105 async_exit = true; 106} 107 108/// Abort signal handler. 109void 110abortHandler(int sigtype) 111{ 112 cerr << "Program aborted at cycle " << curTick << endl; 113 114#if TRACING_ON 115 // dump trace buffer, if there is one 116 Trace::theLog.dump(cerr); 117#endif 118} 119 120extern "C" { void init_cc_main(); } 121 122int 123main(int argc, char **argv) 124{ 125 signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths 126 signal(SIGTRAP, SIG_IGN); 127 signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats 128 signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats 129 signal(SIGINT, exitNowHandler); // dump final stats and exit 130 signal(SIGABRT, abortHandler); 131 132 Py_SetProgramName(argv[0]); 133 134 // default path to m5 python code is the currently executing 135 // file... Python ZipImporter will find embedded zip archive. 136 // The M5_ARCHIVE environment variable can be used to override this. 137 char *m5_archive = getenv("M5_ARCHIVE"); 138 string pythonpath = m5_archive ? m5_archive : argv[0]; 139 140 char *oldpath = getenv("PYTHONPATH"); 141 if (oldpath != NULL) { 142 pythonpath += ":"; 143 pythonpath += oldpath; 144 } 145 146 if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1) 147 fatal("setenv: %s\n", strerror(errno)); 148
|
| 149 char *python_home = getenv("PYTHONHOME"); 150 if (!python_home) 151 python_home = PYTHONHOME; 152 Py_SetPythonHome(python_home); 153
|
148 // initialize embedded Python interpreter 149 Py_Initialize(); 150 PySys_SetArgv(argc, argv); 151 152 // initialize SWIG 'cc_main' module 153 init_cc_main(); 154 155 PyRun_SimpleString("import m5.main"); 156 PyRun_SimpleString("m5.main.main()"); 157 158 // clean up Python intepreter. 159 Py_Finalize(); 160} 161 162 163void 164setOutputDir(const string &dir) 165{ 166 simout.setDirectory(dir); 167} 168 169 170IniFile inifile; 171 172SimObject * 173createSimObject(const string &name) 174{ 175 return SimObjectClass::createObject(inifile, name); 176} 177 178 179/** 180 * Pointer to the Python function that maps names to SimObjects. 181 */ 182PyObject *resolveFunc = NULL; 183 184/** 185 * Convert a pointer to the Python object that SWIG wraps around a C++ 186 * SimObject pointer back to the actual C++ pointer. See main.i. 187 */ 188extern "C" SimObject *convertSwigSimObjectPtr(PyObject *); 189 190 191SimObject * 192resolveSimObject(const string &name) 193{ 194 PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str()); 195 if (pyPtr == NULL) { 196 PyErr_Print(); 197 panic("resolveSimObject: failure on call to Python for %s", name); 198 } 199 200 SimObject *simObj = convertSwigSimObjectPtr(pyPtr); 201 if (simObj == NULL) 202 panic("resolveSimObject: failure on pointer conversion for %s", name); 203 204 return simObj; 205} 206 207 208/** 209 * Load config.ini into C++ database. Exported to Python via SWIG; 210 * invoked from m5.instantiate(). 211 */ 212void 213loadIniFile(PyObject *_resolveFunc) 214{ 215 resolveFunc = _resolveFunc; 216 configStream = simout.find("config.out"); 217 218 // The configuration database is now complete; start processing it. 219 inifile.load(simout.resolve("config.ini")); 220 221 // Initialize statistics database 222 Stats::InitSimStats(); 223} 224 225 226/** 227 * Look up a MemObject port. Helper function for connectPorts(). 228 */ 229Port * 230lookupPort(SimObject *so, const std::string &name, int i) 231{ 232 MemObject *mo = dynamic_cast<MemObject *>(so); 233 if (mo == NULL) { 234 warn("error casting SimObject %s to MemObject", so->name()); 235 return NULL; 236 } 237 238 Port *p = mo->getPort(name, i); 239 if (p == NULL) 240 warn("error looking up port %s on object %s", name, so->name()); 241 return p; 242} 243 244 245/** 246 * Connect the described MemObject ports. Called from Python via SWIG. 247 */ 248int 249connectPorts(SimObject *o1, const std::string &name1, int i1, 250 SimObject *o2, const std::string &name2, int i2) 251{ 252 Port *p1 = lookupPort(o1, name1, i1); 253 Port *p2 = lookupPort(o2, name2, i2); 254 255 if (p1 == NULL || p2 == NULL) { 256 warn("connectPorts: port lookup error"); 257 return 0; 258 } 259 260 p1->setPeer(p2); 261 p2->setPeer(p1); 262 263 return 1; 264} 265 266/** 267 * Do final initialization steps after object construction but before 268 * start of simulation. 269 */ 270void 271finalInit() 272{ 273 // Parse and check all non-config-hierarchy parameters. 274 ParamContext::parseAllContexts(inifile); 275 ParamContext::checkAllContexts(); 276 277 // Echo all parameter settings to stats file as well. 278 ParamContext::showAllContexts(*configStream); 279 280 // Do a second pass to finish initializing the sim objects 281 SimObject::initAll(); 282 283 // Restore checkpointed state, if any. 284#if 0 285 configHierarchy.unserializeSimObjects(); 286#endif 287 288 SimObject::regAllStats(); 289 290 // Check to make sure that the stats package is properly initialized 291 Stats::check(); 292 293 // Reset to put the stats in a consistent state. 294 Stats::reset(); 295 296 SimStartup(); 297} 298 299 300/** Simulate for num_cycles additional cycles. If num_cycles is -1 301 * (the default), do not limit simulation; some other event must 302 * terminate the loop. Exported to Python via SWIG. 303 * @return The SimLoopExitEvent that caused the loop to exit. 304 */ 305SimLoopExitEvent * 306simulate(Tick num_cycles = -1) 307{ 308 warn("Entering event queue @ %d. Starting simulation...\n", curTick); 309 310 // Fix up num_cycles. Special default value -1 means simulate 311 // "forever"... schedule event at MaxTick just to be safe. 312 // Otherwise it's a delta for additional cycles to simulate past 313 // curTick, and thus must be non-negative. 314 if (num_cycles == -1) 315 num_cycles = MaxTick; 316 else if (num_cycles < 0) 317 fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); 318 else 319 num_cycles = curTick + num_cycles; 320 321 Event *limit_event = schedExitSimLoop("simulate() limit reached", 322 num_cycles); 323 324 while (1) { 325 // there should always be at least one event (the SimLoopExitEvent 326 // we just scheduled) in the queue 327 assert(!mainEventQueue.empty()); 328 assert(curTick <= mainEventQueue.nextTick() && 329 "event scheduled in the past"); 330 331 // forward current cycle to the time of the first event on the 332 // queue 333 curTick = mainEventQueue.nextTick(); 334 Event *exit_event = mainEventQueue.serviceOne(); 335 if (exit_event != NULL) { 336 // hit some kind of exit event; return to Python 337 // event must be subclass of SimLoopExitEvent... 338 SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); 339 if (se_event == NULL) 340 panic("Bogus exit event class!"); 341 342 // if we didn't hit limit_event, delete it 343 if (se_event != limit_event) { 344 assert(limit_event->scheduled()); 345 limit_event->deschedule(); 346 delete limit_event; 347 } 348 349 return se_event; 350 } 351 352 if (async_event) { 353 async_event = false; 354 if (async_dump) { 355 async_dump = false; 356 357 using namespace Stats; 358 SetupEvent(Dump, curTick); 359 } 360 361 if (async_dumpreset) { 362 async_dumpreset = false; 363 364 using namespace Stats; 365 SetupEvent(Dump | Reset, curTick); 366 } 367 368 if (async_exit) { 369 async_exit = false; 370 exitSimLoop("user interrupt received"); 371 } 372 373 if (async_io || async_alarm) { 374 async_io = false; 375 async_alarm = false; 376 pollQueue.service(); 377 } 378 } 379 } 380 381 // not reached... only exit is return on SimLoopExitEvent 382} 383 384Event * 385createCountedDrain() 386{ 387 return new CountedDrainEvent(); 388} 389 390void 391cleanupCountedDrain(Event *counted_drain) 392{ 393 CountedDrainEvent *event = 394 dynamic_cast<CountedDrainEvent *>(counted_drain); 395 if (event == NULL) { 396 fatal("Called cleanupCountedDrain() on an event that was not " 397 "a CountedDrainEvent."); 398 } 399 assert(event->getCount() == 0); 400 delete event; 401} 402 403void 404serializeAll(const std::string &cpt_dir) 405{ 406 Serializable::serializeAll(cpt_dir); 407} 408 409void 410unserializeAll(const std::string &cpt_dir) 411{ 412 Serializable::unserializeAll(cpt_dir); 413} 414 415/** 416 * Queue of C++ callbacks to invoke on simulator exit. 417 */ 418CallbackQueue& 419exitCallbacks() 420{ 421 static CallbackQueue theQueue; 422 return theQueue; 423} 424 425/** 426 * Register an exit callback. 427 */ 428void 429registerExitCallback(Callback *callback) 430{ 431 exitCallbacks().add(callback); 432} 433 434BaseCPU * 435convertToBaseCPUPtr(SimObject *obj) 436{ 437 BaseCPU *ptr = dynamic_cast<BaseCPU *>(obj); 438 439 if (ptr == NULL) 440 warn("Casting to BaseCPU pointer failed"); 441 return ptr; 442} 443 444System * 445convertToSystemPtr(SimObject *obj) 446{ 447 System *ptr = dynamic_cast<System *>(obj); 448 449 if (ptr == NULL) 450 warn("Casting to System pointer failed"); 451 return ptr; 452} 453 454 455/** 456 * Do C++ simulator exit processing. Exported to SWIG to be invoked 457 * when simulator terminates via Python's atexit mechanism. 458 */ 459void 460doExitCleanup() 461{ 462 exitCallbacks().process(); 463 exitCallbacks().clear(); 464 465 cout.flush(); 466 467 ParamContext::cleanupAllContexts(); 468 469 // print simulation stats 470 Stats::DumpNow(); 471}
| 154 // initialize embedded Python interpreter 155 Py_Initialize(); 156 PySys_SetArgv(argc, argv); 157 158 // initialize SWIG 'cc_main' module 159 init_cc_main(); 160 161 PyRun_SimpleString("import m5.main"); 162 PyRun_SimpleString("m5.main.main()"); 163 164 // clean up Python intepreter. 165 Py_Finalize(); 166} 167 168 169void 170setOutputDir(const string &dir) 171{ 172 simout.setDirectory(dir); 173} 174 175 176IniFile inifile; 177 178SimObject * 179createSimObject(const string &name) 180{ 181 return SimObjectClass::createObject(inifile, name); 182} 183 184 185/** 186 * Pointer to the Python function that maps names to SimObjects. 187 */ 188PyObject *resolveFunc = NULL; 189 190/** 191 * Convert a pointer to the Python object that SWIG wraps around a C++ 192 * SimObject pointer back to the actual C++ pointer. See main.i. 193 */ 194extern "C" SimObject *convertSwigSimObjectPtr(PyObject *); 195 196 197SimObject * 198resolveSimObject(const string &name) 199{ 200 PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str()); 201 if (pyPtr == NULL) { 202 PyErr_Print(); 203 panic("resolveSimObject: failure on call to Python for %s", name); 204 } 205 206 SimObject *simObj = convertSwigSimObjectPtr(pyPtr); 207 if (simObj == NULL) 208 panic("resolveSimObject: failure on pointer conversion for %s", name); 209 210 return simObj; 211} 212 213 214/** 215 * Load config.ini into C++ database. Exported to Python via SWIG; 216 * invoked from m5.instantiate(). 217 */ 218void 219loadIniFile(PyObject *_resolveFunc) 220{ 221 resolveFunc = _resolveFunc; 222 configStream = simout.find("config.out"); 223 224 // The configuration database is now complete; start processing it. 225 inifile.load(simout.resolve("config.ini")); 226 227 // Initialize statistics database 228 Stats::InitSimStats(); 229} 230 231 232/** 233 * Look up a MemObject port. Helper function for connectPorts(). 234 */ 235Port * 236lookupPort(SimObject *so, const std::string &name, int i) 237{ 238 MemObject *mo = dynamic_cast<MemObject *>(so); 239 if (mo == NULL) { 240 warn("error casting SimObject %s to MemObject", so->name()); 241 return NULL; 242 } 243 244 Port *p = mo->getPort(name, i); 245 if (p == NULL) 246 warn("error looking up port %s on object %s", name, so->name()); 247 return p; 248} 249 250 251/** 252 * Connect the described MemObject ports. Called from Python via SWIG. 253 */ 254int 255connectPorts(SimObject *o1, const std::string &name1, int i1, 256 SimObject *o2, const std::string &name2, int i2) 257{ 258 Port *p1 = lookupPort(o1, name1, i1); 259 Port *p2 = lookupPort(o2, name2, i2); 260 261 if (p1 == NULL || p2 == NULL) { 262 warn("connectPorts: port lookup error"); 263 return 0; 264 } 265 266 p1->setPeer(p2); 267 p2->setPeer(p1); 268 269 return 1; 270} 271 272/** 273 * Do final initialization steps after object construction but before 274 * start of simulation. 275 */ 276void 277finalInit() 278{ 279 // Parse and check all non-config-hierarchy parameters. 280 ParamContext::parseAllContexts(inifile); 281 ParamContext::checkAllContexts(); 282 283 // Echo all parameter settings to stats file as well. 284 ParamContext::showAllContexts(*configStream); 285 286 // Do a second pass to finish initializing the sim objects 287 SimObject::initAll(); 288 289 // Restore checkpointed state, if any. 290#if 0 291 configHierarchy.unserializeSimObjects(); 292#endif 293 294 SimObject::regAllStats(); 295 296 // Check to make sure that the stats package is properly initialized 297 Stats::check(); 298 299 // Reset to put the stats in a consistent state. 300 Stats::reset(); 301 302 SimStartup(); 303} 304 305 306/** Simulate for num_cycles additional cycles. If num_cycles is -1 307 * (the default), do not limit simulation; some other event must 308 * terminate the loop. Exported to Python via SWIG. 309 * @return The SimLoopExitEvent that caused the loop to exit. 310 */ 311SimLoopExitEvent * 312simulate(Tick num_cycles = -1) 313{ 314 warn("Entering event queue @ %d. Starting simulation...\n", curTick); 315 316 // Fix up num_cycles. Special default value -1 means simulate 317 // "forever"... schedule event at MaxTick just to be safe. 318 // Otherwise it's a delta for additional cycles to simulate past 319 // curTick, and thus must be non-negative. 320 if (num_cycles == -1) 321 num_cycles = MaxTick; 322 else if (num_cycles < 0) 323 fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); 324 else 325 num_cycles = curTick + num_cycles; 326 327 Event *limit_event = schedExitSimLoop("simulate() limit reached", 328 num_cycles); 329 330 while (1) { 331 // there should always be at least one event (the SimLoopExitEvent 332 // we just scheduled) in the queue 333 assert(!mainEventQueue.empty()); 334 assert(curTick <= mainEventQueue.nextTick() && 335 "event scheduled in the past"); 336 337 // forward current cycle to the time of the first event on the 338 // queue 339 curTick = mainEventQueue.nextTick(); 340 Event *exit_event = mainEventQueue.serviceOne(); 341 if (exit_event != NULL) { 342 // hit some kind of exit event; return to Python 343 // event must be subclass of SimLoopExitEvent... 344 SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); 345 if (se_event == NULL) 346 panic("Bogus exit event class!"); 347 348 // if we didn't hit limit_event, delete it 349 if (se_event != limit_event) { 350 assert(limit_event->scheduled()); 351 limit_event->deschedule(); 352 delete limit_event; 353 } 354 355 return se_event; 356 } 357 358 if (async_event) { 359 async_event = false; 360 if (async_dump) { 361 async_dump = false; 362 363 using namespace Stats; 364 SetupEvent(Dump, curTick); 365 } 366 367 if (async_dumpreset) { 368 async_dumpreset = false; 369 370 using namespace Stats; 371 SetupEvent(Dump | Reset, curTick); 372 } 373 374 if (async_exit) { 375 async_exit = false; 376 exitSimLoop("user interrupt received"); 377 } 378 379 if (async_io || async_alarm) { 380 async_io = false; 381 async_alarm = false; 382 pollQueue.service(); 383 } 384 } 385 } 386 387 // not reached... only exit is return on SimLoopExitEvent 388} 389 390Event * 391createCountedDrain() 392{ 393 return new CountedDrainEvent(); 394} 395 396void 397cleanupCountedDrain(Event *counted_drain) 398{ 399 CountedDrainEvent *event = 400 dynamic_cast<CountedDrainEvent *>(counted_drain); 401 if (event == NULL) { 402 fatal("Called cleanupCountedDrain() on an event that was not " 403 "a CountedDrainEvent."); 404 } 405 assert(event->getCount() == 0); 406 delete event; 407} 408 409void 410serializeAll(const std::string &cpt_dir) 411{ 412 Serializable::serializeAll(cpt_dir); 413} 414 415void 416unserializeAll(const std::string &cpt_dir) 417{ 418 Serializable::unserializeAll(cpt_dir); 419} 420 421/** 422 * Queue of C++ callbacks to invoke on simulator exit. 423 */ 424CallbackQueue& 425exitCallbacks() 426{ 427 static CallbackQueue theQueue; 428 return theQueue; 429} 430 431/** 432 * Register an exit callback. 433 */ 434void 435registerExitCallback(Callback *callback) 436{ 437 exitCallbacks().add(callback); 438} 439 440BaseCPU * 441convertToBaseCPUPtr(SimObject *obj) 442{ 443 BaseCPU *ptr = dynamic_cast<BaseCPU *>(obj); 444 445 if (ptr == NULL) 446 warn("Casting to BaseCPU pointer failed"); 447 return ptr; 448} 449 450System * 451convertToSystemPtr(SimObject *obj) 452{ 453 System *ptr = dynamic_cast<System *>(obj); 454 455 if (ptr == NULL) 456 warn("Casting to System pointer failed"); 457 return ptr; 458} 459 460 461/** 462 * Do C++ simulator exit processing. Exported to SWIG to be invoked 463 * when simulator terminates via Python's atexit mechanism. 464 */ 465void 466doExitCleanup() 467{ 468 exitCallbacks().process(); 469 exitCallbacks().clear(); 470 471 cout.flush(); 472 473 ParamContext::cleanupAllContexts(); 474 475 // print simulation stats 476 Stats::DumpNow(); 477}
|