sc_main.cc revision 13301:0ef9dd4e1154
12686Sksewell@umich.edu/* 22686Sksewell@umich.edu * Copyright 2018 Google, Inc. 32686Sksewell@umich.edu * 42686Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 52686Sksewell@umich.edu * modification, are permitted provided that the following conditions are 62686Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 72686Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 82686Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 92686Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 102686Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 112686Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 122686Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 132686Sksewell@umich.edu * this software without specific prior written permission. 142686Sksewell@umich.edu * 152686Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 162686Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 172686Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 182686Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 192686Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 202686Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 212686Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 222686Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 232686Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 242686Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 252686Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 262686Sksewell@umich.edu * 272706Sksewell@umich.edu * Authors: Gabe Black 282706Sksewell@umich.edu */ 292686Sksewell@umich.edu 302686Sksewell@umich.edu#include <cstring> 314661Sksewell@umich.edu#include <string> 322686Sksewell@umich.edu 334661Sksewell@umich.edu#include "base/fiber.hh" 344661Sksewell@umich.edu#include "base/logging.hh" 354661Sksewell@umich.edu#include "base/types.hh" 364661Sksewell@umich.edu#include "sim/core.hh" 374661Sksewell@umich.edu#include "sim/eventq.hh" 384661Sksewell@umich.edu#include "sim/init.hh" 392980Sgblack@eecs.umich.edu#include "systemc/core/kernel.hh" 402686Sksewell@umich.edu#include "systemc/core/python.hh" 412686Sksewell@umich.edu#include "systemc/core/scheduler.hh" 424661Sksewell@umich.edu#include "systemc/ext/core/sc_main.hh" 432686Sksewell@umich.edu#include "systemc/ext/utils/sc_report_handler.hh" 442686Sksewell@umich.edu 452686Sksewell@umich.edu// A weak symbol to detect if sc_main has been defined, and if so where it is. 462686Sksewell@umich.edu[[gnu::weak]] int sc_main(int argc, char *argv[]); 472686Sksewell@umich.edu 482686Sksewell@umich.edunamespace sc_core 492686Sksewell@umich.edu{ 502686Sksewell@umich.edu 512686Sksewell@umich.edunamespace 522686Sksewell@umich.edu{ 532686Sksewell@umich.edu 542686Sksewell@umich.edubool scMainCalled = false; 552686Sksewell@umich.edu 562686Sksewell@umich.eduint _argc = 0; 572686Sksewell@umich.educhar **_argv = NULL; 582686Sksewell@umich.edu 592686Sksewell@umich.educlass ScMainFiber : public Fiber 602686Sksewell@umich.edu{ 612686Sksewell@umich.edu public: 622686Sksewell@umich.edu std::string resultStr; 632686Sksewell@umich.edu int resultInt; 642686Sksewell@umich.edu 652686Sksewell@umich.edu ScMainFiber() : resultInt(1) {} 662686Sksewell@umich.edu 672686Sksewell@umich.edu void 682686Sksewell@umich.edu main() 692686Sksewell@umich.edu { 702686Sksewell@umich.edu if (::sc_main) { 712686Sksewell@umich.edu try { 722686Sksewell@umich.edu resultInt = ::sc_main(_argc, _argv); 732686Sksewell@umich.edu if (resultInt) 742686Sksewell@umich.edu resultStr = "sc_main returned non-zero"; 752686Sksewell@umich.edu else 762686Sksewell@umich.edu resultStr = "sc_main finished"; 772686Sksewell@umich.edu // Make sure no systemc events/notifications are scheduled 782686Sksewell@umich.edu // after sc_main returns. 792686Sksewell@umich.edu } catch (const sc_report &r) { 802686Sksewell@umich.edu // There was an exception nobody caught. 812686Sksewell@umich.edu resultStr = "uncaught sc_report"; 822686Sksewell@umich.edu sc_report_handler::get_handler()( 832686Sksewell@umich.edu r, sc_report_handler::get_catch_actions()); 842686Sksewell@umich.edu } catch (...) { 852686Sksewell@umich.edu // There was some other type of exception we need to wrap. 862686Sksewell@umich.edu resultStr = "uncaught exception"; 872686Sksewell@umich.edu sc_report_handler::get_handler()( 882686Sksewell@umich.edu ::sc_gem5::reportifyException(), 892686Sksewell@umich.edu sc_report_handler::get_catch_actions()); 902686Sksewell@umich.edu } 912686Sksewell@umich.edu ::sc_gem5::Kernel::scMainFinished(true); 922686Sksewell@umich.edu ::sc_gem5::scheduler.clear(); 932686Sksewell@umich.edu } else { 942686Sksewell@umich.edu // If python tries to call sc_main but no sc_main was defined... 952686Sksewell@umich.edu fatal("sc_main called but not defined.\n"); 962686Sksewell@umich.edu } 972686Sksewell@umich.edu } 982686Sksewell@umich.edu}; 992686Sksewell@umich.edu 1002686Sksewell@umich.eduScMainFiber scMainFiber; 1012686Sksewell@umich.edu 1022686Sksewell@umich.edu// This wrapper adapts the python version of sc_main to the c++ version. 1032686Sksewell@umich.eduvoid 1042686Sksewell@umich.edusc_main(pybind11::args args) 1052686Sksewell@umich.edu{ 1062686Sksewell@umich.edu panic_if(scMainCalled, "sc_main called more than once."); 1072686Sksewell@umich.edu 1082686Sksewell@umich.edu _argc = args.size(); 1092686Sksewell@umich.edu _argv = new char *[_argc]; 1102686Sksewell@umich.edu 1112686Sksewell@umich.edu // Initialize all the _argvs to NULL so we can delete [] them 1122686Sksewell@umich.edu // unconditionally. 1132686Sksewell@umich.edu for (int idx = 0; idx < _argc; idx++) 1142686Sksewell@umich.edu _argv[idx] = NULL; 1152686Sksewell@umich.edu 1162686Sksewell@umich.edu // Attempt to convert all the arguments to strings. If that fails, clean 1172686Sksewell@umich.edu // up after ourselves. Also don't count this as a call to sc_main since 1182686Sksewell@umich.edu // we never got to the c++ version of that function. 1192686Sksewell@umich.edu try { 1202686Sksewell@umich.edu for (int idx = 0; idx < _argc; idx++) { 1212686Sksewell@umich.edu std::string arg = args[idx].cast<std::string>(); 1222686Sksewell@umich.edu _argv[idx] = new char[arg.length() + 1]; 1232686Sksewell@umich.edu strcpy(_argv[idx], arg.c_str()); 1242686Sksewell@umich.edu } 1252686Sksewell@umich.edu } catch (...) { 1262686Sksewell@umich.edu // If that didn't work for some reason (probably a conversion error) 1272686Sksewell@umich.edu // blow away _argv and _argc and pass on the exception. 1282686Sksewell@umich.edu for (int idx = 0; idx < _argc; idx++) 1292686Sksewell@umich.edu delete [] _argv[idx]; 1302686Sksewell@umich.edu delete [] _argv; 1312686Sksewell@umich.edu _argc = 0; 1322686Sksewell@umich.edu throw; 1332686Sksewell@umich.edu } 1342686Sksewell@umich.edu 1352686Sksewell@umich.edu // At this point we're going to call the c++ sc_main, so we can't try 1362686Sksewell@umich.edu // again later. 1372686Sksewell@umich.edu scMainCalled = true; 1382686Sksewell@umich.edu 1392686Sksewell@umich.edu scMainFiber.run(); 1402686Sksewell@umich.edu} 1412686Sksewell@umich.edu 1422686Sksewell@umich.eduint 1432686Sksewell@umich.edusc_main_result_code() 1442686Sksewell@umich.edu{ 1452686Sksewell@umich.edu return scMainFiber.resultInt; 1462686Sksewell@umich.edu} 1472686Sksewell@umich.edu 1482686Sksewell@umich.edustd::string 1492686Sksewell@umich.edusc_main_result_str() 1502686Sksewell@umich.edu{ 1512686Sksewell@umich.edu return scMainFiber.resultStr; 1522686Sksewell@umich.edu} 1532686Sksewell@umich.edu 1542686Sksewell@umich.edu// Make our sc_main wrapper available in the internal _m5 python module under 1552686Sksewell@umich.edu// the systemc submodule. 1562686Sksewell@umich.edu 1572686Sksewell@umich.edustruct InstallScMain : public ::sc_gem5::PythonInitFunc 1582686Sksewell@umich.edu{ 1592686Sksewell@umich.edu void 1602686Sksewell@umich.edu run(pybind11::module &systemc) override 1612686Sksewell@umich.edu { 1622686Sksewell@umich.edu systemc.def("sc_main", &sc_main); 1632686Sksewell@umich.edu systemc.def("sc_main_result_code", &sc_main_result_code); 1642686Sksewell@umich.edu systemc.def("sc_main_result_str", &sc_main_result_str); 1652686Sksewell@umich.edu } 1662686Sksewell@umich.edu} installScMain; 1672686Sksewell@umich.edu 1682686Sksewell@umich.edusc_stop_mode _stop_mode = SC_STOP_FINISH_DELTA; 1692686Sksewell@umich.edu 1702686Sksewell@umich.edu} // anonymous namespace 1712686Sksewell@umich.edu 1722686Sksewell@umich.eduint 1732686Sksewell@umich.edusc_argc() 1742686Sksewell@umich.edu{ 1752686Sksewell@umich.edu return _argc; 1762686Sksewell@umich.edu} 1772686Sksewell@umich.edu 1782686Sksewell@umich.educonst char *const * 1792686Sksewell@umich.edusc_argv() 1802686Sksewell@umich.edu{ 1812686Sksewell@umich.edu return _argv; 1822686Sksewell@umich.edu} 1832686Sksewell@umich.edu 1842686Sksewell@umich.eduvoid 1852686Sksewell@umich.edusc_start() 1862686Sksewell@umich.edu{ 1872686Sksewell@umich.edu Tick now = ::sc_gem5::scheduler.getCurTick(); 1882686Sksewell@umich.edu sc_start(sc_time::from_value(MaxTick - now), SC_EXIT_ON_STARVATION); 1892686Sksewell@umich.edu} 1902686Sksewell@umich.edu 1912686Sksewell@umich.eduvoid 1922686Sksewell@umich.edusc_pause() 1932686Sksewell@umich.edu{ 1942686Sksewell@umich.edu if (::sc_gem5::Kernel::status() == SC_RUNNING) 1952686Sksewell@umich.edu ::sc_gem5::scheduler.schedulePause(); 1962686Sksewell@umich.edu} 1972686Sksewell@umich.edu 1982686Sksewell@umich.eduvoid 1992686Sksewell@umich.edusc_start(const sc_time &time, sc_starvation_policy p) 2002686Sksewell@umich.edu{ 2012686Sksewell@umich.edu if (time.value() == 0) { 2022686Sksewell@umich.edu ::sc_gem5::scheduler.oneCycle(); 2032686Sksewell@umich.edu } else { 2042686Sksewell@umich.edu Tick now = ::sc_gem5::scheduler.getCurTick(); 2052686Sksewell@umich.edu if (MaxTick - now < time.value()) { 2064661Sksewell@umich.edu SC_REPORT_ERROR("(E544) simulation time value overflow, " 2074661Sksewell@umich.edu "simulation aborted", ""); 2084661Sksewell@umich.edu } 2094661Sksewell@umich.edu ::sc_gem5::scheduler.start(now + time.value(), p == SC_RUN_TO_TIME); 2104661Sksewell@umich.edu } 2114661Sksewell@umich.edu} 212 213void 214sc_set_stop_mode(sc_stop_mode mode) 215{ 216 if (sc_is_running()) { 217 SC_REPORT_ERROR("attempt to set sc_stop mode " 218 "after start will be ignored", ""); 219 return; 220 } 221 _stop_mode = mode; 222} 223 224sc_stop_mode 225sc_get_stop_mode() 226{ 227 return _stop_mode; 228} 229 230void 231sc_stop() 232{ 233 static bool stop_called = false; 234 if (stop_called) { 235 static bool stop_warned = false; 236 if (!stop_warned) 237 SC_REPORT_WARNING("(W545) sc_stop has already been called", ""); 238 stop_warned = true; 239 return; 240 } 241 stop_called = true; 242 243 if (::sc_gem5::Kernel::status() == SC_STOPPED) 244 return; 245 246 if ((sc_get_status() & SC_RUNNING)) { 247 bool finish_delta = (_stop_mode == SC_STOP_FINISH_DELTA); 248 ::sc_gem5::scheduler.scheduleStop(finish_delta); 249 } else { 250 ::sc_gem5::Kernel::stop(); 251 } 252} 253 254const sc_time & 255sc_time_stamp() 256{ 257 static sc_time tstamp(1.0, SC_SEC); 258 tstamp = sc_time::from_value(::sc_gem5::scheduler.getCurTick()); 259 return tstamp; 260} 261 262sc_dt::uint64 263sc_delta_count() 264{ 265 return sc_gem5::scheduler.numCycles(); 266} 267 268bool 269sc_is_running() 270{ 271 return sc_get_status() & (SC_RUNNING | SC_PAUSED); 272} 273 274bool 275sc_pending_activity_at_current_time() 276{ 277 return ::sc_gem5::scheduler.pendingCurr(); 278} 279 280bool 281sc_pending_activity_at_future_time() 282{ 283 return ::sc_gem5::scheduler.pendingFuture(); 284} 285 286bool 287sc_pending_activity() 288{ 289 return sc_pending_activity_at_current_time() || 290 sc_pending_activity_at_future_time(); 291} 292 293sc_time 294sc_time_to_pending_activity() 295{ 296 return sc_time::from_value(::sc_gem5::scheduler.timeToPending()); 297} 298 299sc_status 300sc_get_status() 301{ 302 return ::sc_gem5::kernel ? ::sc_gem5::kernel->status() : SC_ELABORATION; 303} 304 305std::ostream & 306operator << (std::ostream &os, sc_status s) 307{ 308 switch (s) { 309 case SC_ELABORATION: 310 os << "SC_ELABORATION"; 311 break; 312 case SC_BEFORE_END_OF_ELABORATION: 313 os << "SC_BEFORE_END_OF_ELABORATION"; 314 break; 315 case SC_END_OF_ELABORATION: 316 os << "SC_END_OF_ELABORATION"; 317 break; 318 case SC_START_OF_SIMULATION: 319 os << "SC_START_OF_SIMULATION"; 320 break; 321 case SC_RUNNING: 322 os << "SC_RUNNING"; 323 break; 324 case SC_PAUSED: 325 os << "SC_PAUSED"; 326 break; 327 case SC_STOPPED: 328 os << "SC_STOPPED"; 329 break; 330 case SC_END_OF_SIMULATION: 331 os << "SC_END_OF_SIMULATION"; 332 break; 333 334 // Nonstandard 335 case SC_END_OF_INITIALIZATION: 336 os << "SC_END_OF_INITIALIZATION"; 337 break; 338 case SC_END_OF_UPDATE: 339 os << "SC_END_OF_UPDATE"; 340 break; 341 case SC_BEFORE_TIMESTEP: 342 os << "SC_BEFORE_TIMESTEP"; 343 break; 344 345 default: 346 if (s & SC_STATUS_ANY) { 347 const char *prefix = "("; 348 for (sc_status m = (sc_status)0x1; 349 m < SC_STATUS_ANY; m = (sc_status)(m << 1)) { 350 if (m & s) { 351 os << prefix; 352 prefix = "|"; 353 os << m; 354 } 355 } 356 os << ")"; 357 } else { 358 ccprintf(os, "%#x", s); 359 } 360 } 361 362 return os; 363} 364 365} // namespace sc_core 366