2 * Copyright 2018 Google, Inc.
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.
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.
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"
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
[]);
54 bool scMainCalled
= false;
59 class ScMainFiber
: public Fiber
62 std::string resultStr
;
65 ScMainFiber() : resultInt(1) {}
72 resultInt
= ::sc_main(_argc
, _argv
);
74 resultStr
= "sc_main returned non-zero";
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.
83 ::sc_gem5::Kernel::scMainFinished(true);
84 ::sc_gem5::scheduler
.clear();
86 // If python tries to call sc_main but no sc_main was defined...
87 fatal("sc_main called but not defined.\n");
92 ScMainFiber scMainFiber
;
94 // This wrapper adapts the python version of sc_main to the c++ version.
96 sc_main(pybind11::args args
)
98 panic_if(scMainCalled
, "sc_main called more than once.");
101 _argv
= new char *[_argc
];
103 // Initialize all the _argvs to NULL so we can delete [] them
105 for (int idx
= 0; idx
< _argc
; idx
++)
108 // Attempt to convert all the arguments to strings. If that fails, clean
109 // up after ourselves. Also don't count this as a call to sc_main since
110 // we never got to the c++ version of that function.
112 for (int idx
= 0; idx
< _argc
; idx
++) {
113 std::string arg
= args
[idx
].cast
<std::string
>();
114 _argv
[idx
] = new char[arg
.length() + 1];
115 strcpy(_argv
[idx
], arg
.c_str());
118 // If that didn't work for some reason (probably a conversion error)
119 // blow away _argv and _argc and pass on the exception.
120 for (int idx
= 0; idx
< _argc
; idx
++)
121 delete [] _argv
[idx
];
127 // At this point we're going to call the c++ sc_main, so we can't try
135 sc_main_result_code()
137 return scMainFiber
.resultInt
;
143 return scMainFiber
.resultStr
;
146 // Make our sc_main wrapper available in the internal _m5 python module under
147 // the systemc submodule.
149 struct InstallScMain
: public ::sc_gem5::PythonInitFunc
152 run(pybind11::module
&systemc
) override
154 systemc
.def("sc_main", &sc_main
);
155 systemc
.def("sc_main_result_code", &sc_main_result_code
);
156 systemc
.def("sc_main_result_str", &sc_main_result_str
);
160 sc_stop_mode _stop_mode
= SC_STOP_FINISH_DELTA
;
162 } // anonymous namespace
179 Tick now
= ::sc_gem5::scheduler
.getCurTick();
180 sc_start(sc_time::from_value(MaxTick
- now
), SC_EXIT_ON_STARVATION
);
186 if (::sc_gem5::Kernel::status() == SC_RUNNING
)
187 ::sc_gem5::scheduler
.schedulePause();
191 sc_start(const sc_time
&time
, sc_starvation_policy p
)
193 if (time
.value() == 0) {
194 ::sc_gem5::scheduler
.oneCycle();
196 Tick now
= ::sc_gem5::scheduler
.getCurTick();
197 if (MaxTick
- now
< time
.value()) {
198 SC_REPORT_ERROR("(E544) simulation time value overflow, "
199 "simulation aborted", "");
201 ::sc_gem5::scheduler
.start(now
+ time
.value(), p
== SC_RUN_TO_TIME
);
206 sc_set_stop_mode(sc_stop_mode mode
)
208 if (sc_is_running()) {
209 SC_REPORT_ERROR("attempt to set sc_stop mode "
210 "after start will be ignored", "");
225 if (::sc_gem5::Kernel::status() == SC_STOPPED
)
228 if (sc_is_running()) {
229 bool finish_delta
= (_stop_mode
== SC_STOP_FINISH_DELTA
);
230 ::sc_gem5::scheduler
.scheduleStop(finish_delta
);
232 ::sc_gem5::Kernel::stop();
239 static sc_time tstamp
;
240 Tick tick
= ::sc_gem5::scheduler
.getCurTick();
241 //XXX We're assuming the systemc time resolution is in ps.
242 // If tick is zero, the time scale may not be fixed yet, and
243 // SimClock::Int::ps may be zero.
244 tstamp
= sc_time::from_value(tick
? tick
/ SimClock::Int::ps
: 0);
251 return sc_gem5::scheduler
.numCycles();
257 return sc_get_status() & (SC_RUNNING
| SC_PAUSED
);
261 sc_pending_activity_at_current_time()
263 return ::sc_gem5::scheduler
.pendingCurr();
267 sc_pending_activity_at_future_time()
269 return ::sc_gem5::scheduler
.pendingFuture();
273 sc_pending_activity()
275 return sc_pending_activity_at_current_time() ||
276 sc_pending_activity_at_future_time();
280 sc_time_to_pending_activity()
282 return sc_time::from_value(::sc_gem5::scheduler
.timeToPending());
288 return ::sc_gem5::kernel
? ::sc_gem5::kernel
->status() : SC_ELABORATION
;
292 operator << (std::ostream
&os
, sc_status s
)
296 os
<< "SC_ELABORATION";
298 case SC_BEFORE_END_OF_ELABORATION
:
299 os
<< "SC_BEFORE_END_OF_ELABORATION";
301 case SC_END_OF_ELABORATION
:
302 os
<< "SC_END_OF_ELABORATION";
304 case SC_START_OF_SIMULATION
:
305 os
<< "SC_START_OF_SIMULATION";
316 case SC_END_OF_SIMULATION
:
317 os
<< "SC_END_OF_SIMULATION";
321 case SC_END_OF_INITIALIZATION
:
322 os
<< "SC_END_OF_INITIALIZATION";
324 case SC_END_OF_UPDATE
:
325 os
<< "SC_END_OF_UPDATE";
327 case SC_BEFORE_TIMESTEP
:
328 os
<< "SC_BEFORE_TIMESTEP";
332 if (s
& SC_STATUS_ANY
) {
333 const char *prefix
= "(";
334 for (sc_status m
= (sc_status
)0x1;
335 m
< SC_STATUS_ANY
; m
= (sc_status
)(m
<< 1)) {
344 ccprintf(os
, "%#x", s
);
351 } // namespace sc_core