sc_main.cc revision 13301
1/* 2 * Copyright 2018 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Authors: Gabe Black 28 */ 29 30#include <cstring> 31#include <string> 32 33#include "base/fiber.hh" 34#include "base/logging.hh" 35#include "base/types.hh" 36#include "sim/core.hh" 37#include "sim/eventq.hh" 38#include "sim/init.hh" 39#include "systemc/core/kernel.hh" 40#include "systemc/core/python.hh" 41#include "systemc/core/scheduler.hh" 42#include "systemc/ext/core/sc_main.hh" 43#include "systemc/ext/utils/sc_report_handler.hh" 44 45// A weak symbol to detect if sc_main has been defined, and if so where it is. 46[[gnu::weak]] int sc_main(int argc, char *argv[]); 47 48namespace sc_core 49{ 50 51namespace 52{ 53 54bool scMainCalled = false; 55 56int _argc = 0; 57char **_argv = NULL; 58 59class ScMainFiber : public Fiber 60{ 61 public: 62 std::string resultStr; 63 int resultInt; 64 65 ScMainFiber() : resultInt(1) {} 66 67 void 68 main() 69 { 70 if (::sc_main) { 71 try { 72 resultInt = ::sc_main(_argc, _argv); 73 if (resultInt) 74 resultStr = "sc_main returned non-zero"; 75 else 76 resultStr = "sc_main finished"; 77 // Make sure no systemc events/notifications are scheduled 78 // after sc_main returns. 79 } catch (const sc_report &r) { 80 // There was an exception nobody caught. 81 resultStr = "uncaught sc_report"; 82 sc_report_handler::get_handler()( 83 r, sc_report_handler::get_catch_actions()); 84 } catch (...) { 85 // There was some other type of exception we need to wrap. 86 resultStr = "uncaught exception"; 87 sc_report_handler::get_handler()( 88 ::sc_gem5::reportifyException(), 89 sc_report_handler::get_catch_actions()); 90 } 91 ::sc_gem5::Kernel::scMainFinished(true); 92 ::sc_gem5::scheduler.clear(); 93 } else { 94 // If python tries to call sc_main but no sc_main was defined... 95 fatal("sc_main called but not defined.\n"); 96 } 97 } 98}; 99 100ScMainFiber scMainFiber; 101 102// This wrapper adapts the python version of sc_main to the c++ version. 103void 104sc_main(pybind11::args args) 105{ 106 panic_if(scMainCalled, "sc_main called more than once."); 107 108 _argc = args.size(); 109 _argv = new char *[_argc]; 110 111 // Initialize all the _argvs to NULL so we can delete [] them 112 // unconditionally. 113 for (int idx = 0; idx < _argc; idx++) 114 _argv[idx] = NULL; 115 116 // Attempt to convert all the arguments to strings. If that fails, clean 117 // up after ourselves. Also don't count this as a call to sc_main since 118 // we never got to the c++ version of that function. 119 try { 120 for (int idx = 0; idx < _argc; idx++) { 121 std::string arg = args[idx].cast<std::string>(); 122 _argv[idx] = new char[arg.length() + 1]; 123 strcpy(_argv[idx], arg.c_str()); 124 } 125 } catch (...) { 126 // If that didn't work for some reason (probably a conversion error) 127 // blow away _argv and _argc and pass on the exception. 128 for (int idx = 0; idx < _argc; idx++) 129 delete [] _argv[idx]; 130 delete [] _argv; 131 _argc = 0; 132 throw; 133 } 134 135 // At this point we're going to call the c++ sc_main, so we can't try 136 // again later. 137 scMainCalled = true; 138 139 scMainFiber.run(); 140} 141 142int 143sc_main_result_code() 144{ 145 return scMainFiber.resultInt; 146} 147 148std::string 149sc_main_result_str() 150{ 151 return scMainFiber.resultStr; 152} 153 154// Make our sc_main wrapper available in the internal _m5 python module under 155// the systemc submodule. 156 157struct InstallScMain : public ::sc_gem5::PythonInitFunc 158{ 159 void 160 run(pybind11::module &systemc) override 161 { 162 systemc.def("sc_main", &sc_main); 163 systemc.def("sc_main_result_code", &sc_main_result_code); 164 systemc.def("sc_main_result_str", &sc_main_result_str); 165 } 166} installScMain; 167 168sc_stop_mode _stop_mode = SC_STOP_FINISH_DELTA; 169 170} // anonymous namespace 171 172int 173sc_argc() 174{ 175 return _argc; 176} 177 178const char *const * 179sc_argv() 180{ 181 return _argv; 182} 183 184void 185sc_start() 186{ 187 Tick now = ::sc_gem5::scheduler.getCurTick(); 188 sc_start(sc_time::from_value(MaxTick - now), SC_EXIT_ON_STARVATION); 189} 190 191void 192sc_pause() 193{ 194 if (::sc_gem5::Kernel::status() == SC_RUNNING) 195 ::sc_gem5::scheduler.schedulePause(); 196} 197 198void 199sc_start(const sc_time &time, sc_starvation_policy p) 200{ 201 if (time.value() == 0) { 202 ::sc_gem5::scheduler.oneCycle(); 203 } else { 204 Tick now = ::sc_gem5::scheduler.getCurTick(); 205 if (MaxTick - now < time.value()) { 206 SC_REPORT_ERROR("(E544) simulation time value overflow, " 207 "simulation aborted", ""); 208 } 209 ::sc_gem5::scheduler.start(now + time.value(), p == SC_RUN_TO_TIME); 210 } 211} 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