sc_main.cc revision 13255:570e2d799f70
113772Sjavier.bueno@metempsy.com/*
213772Sjavier.bueno@metempsy.com * Copyright 2018 Google, Inc.
313772Sjavier.bueno@metempsy.com *
413772Sjavier.bueno@metempsy.com * Redistribution and use in source and binary forms, with or without
513772Sjavier.bueno@metempsy.com * modification, are permitted provided that the following conditions are
613772Sjavier.bueno@metempsy.com * met: redistributions of source code must retain the above copyright
713772Sjavier.bueno@metempsy.com * notice, this list of conditions and the following disclaimer;
813772Sjavier.bueno@metempsy.com * redistributions in binary form must reproduce the above copyright
913772Sjavier.bueno@metempsy.com * notice, this list of conditions and the following disclaimer in the
1013772Sjavier.bueno@metempsy.com * documentation and/or other materials provided with the distribution;
1113772Sjavier.bueno@metempsy.com * neither the name of the copyright holders nor the names of its
1213772Sjavier.bueno@metempsy.com * contributors may be used to endorse or promote products derived from
1313772Sjavier.bueno@metempsy.com * this software without specific prior written permission.
1413772Sjavier.bueno@metempsy.com *
1513772Sjavier.bueno@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1613772Sjavier.bueno@metempsy.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1713772Sjavier.bueno@metempsy.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1813772Sjavier.bueno@metempsy.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1913772Sjavier.bueno@metempsy.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2013772Sjavier.bueno@metempsy.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2113772Sjavier.bueno@metempsy.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2213772Sjavier.bueno@metempsy.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2313772Sjavier.bueno@metempsy.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2413772Sjavier.bueno@metempsy.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2513772Sjavier.bueno@metempsy.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2613772Sjavier.bueno@metempsy.com *
2713772Sjavier.bueno@metempsy.com * Authors: Gabe Black
2813772Sjavier.bueno@metempsy.com */
2913772Sjavier.bueno@metempsy.com
3013772Sjavier.bueno@metempsy.com#include <cstring>
3113772Sjavier.bueno@metempsy.com#include <string>
3213772Sjavier.bueno@metempsy.com
3313772Sjavier.bueno@metempsy.com#include "base/fiber.hh"
3413772Sjavier.bueno@metempsy.com#include "base/logging.hh"
3513772Sjavier.bueno@metempsy.com#include "base/types.hh"
3613772Sjavier.bueno@metempsy.com#include "sim/core.hh"
3713772Sjavier.bueno@metempsy.com#include "sim/eventq.hh"
3813772Sjavier.bueno@metempsy.com#include "sim/init.hh"
3913772Sjavier.bueno@metempsy.com#include "systemc/core/kernel.hh"
4013772Sjavier.bueno@metempsy.com#include "systemc/core/python.hh"
4113772Sjavier.bueno@metempsy.com#include "systemc/core/scheduler.hh"
4213772Sjavier.bueno@metempsy.com#include "systemc/ext/core/sc_main.hh"
4313772Sjavier.bueno@metempsy.com#include "systemc/ext/utils/sc_report_handler.hh"
4413772Sjavier.bueno@metempsy.com
4513772Sjavier.bueno@metempsy.com// A weak symbol to detect if sc_main has been defined, and if so where it is.
4613772Sjavier.bueno@metempsy.com[[gnu::weak]] int sc_main(int argc, char *argv[]);
4713772Sjavier.bueno@metempsy.com
4813772Sjavier.bueno@metempsy.comnamespace sc_core
4913772Sjavier.bueno@metempsy.com{
5013772Sjavier.bueno@metempsy.com
5113772Sjavier.bueno@metempsy.comnamespace
5213772Sjavier.bueno@metempsy.com{
5313772Sjavier.bueno@metempsy.com
5413772Sjavier.bueno@metempsy.combool scMainCalled = false;
5513772Sjavier.bueno@metempsy.com
5613772Sjavier.bueno@metempsy.comint _argc = 0;
5713772Sjavier.bueno@metempsy.comchar **_argv = NULL;
5813772Sjavier.bueno@metempsy.com
5913772Sjavier.bueno@metempsy.comclass ScMainFiber : public Fiber
6013772Sjavier.bueno@metempsy.com{
6113772Sjavier.bueno@metempsy.com  public:
6213772Sjavier.bueno@metempsy.com    std::string resultStr;
6313772Sjavier.bueno@metempsy.com    int resultInt;
6413772Sjavier.bueno@metempsy.com
6513772Sjavier.bueno@metempsy.com    ScMainFiber() : resultInt(1) {}
6613772Sjavier.bueno@metempsy.com
6713772Sjavier.bueno@metempsy.com    void
6813772Sjavier.bueno@metempsy.com    main()
6913772Sjavier.bueno@metempsy.com    {
7013772Sjavier.bueno@metempsy.com        if (::sc_main) {
7113772Sjavier.bueno@metempsy.com            try {
7213772Sjavier.bueno@metempsy.com                resultInt = ::sc_main(_argc, _argv);
7313772Sjavier.bueno@metempsy.com                if (resultInt)
7413772Sjavier.bueno@metempsy.com                    resultStr = "sc_main returned non-zero";
7513772Sjavier.bueno@metempsy.com                else
7613772Sjavier.bueno@metempsy.com                    resultStr = "sc_main finished";
7713772Sjavier.bueno@metempsy.com                // Make sure no systemc events/notifications are scheduled
7813772Sjavier.bueno@metempsy.com                // after sc_main returns.
7913772Sjavier.bueno@metempsy.com            } catch (const sc_report &r) {
8013772Sjavier.bueno@metempsy.com                // There was an exception nobody caught.
8113772Sjavier.bueno@metempsy.com                resultStr = r.what();
8213772Sjavier.bueno@metempsy.com            } catch (...) {
8313772Sjavier.bueno@metempsy.com                // There was some other type of exception we need to wrap.
8413772Sjavier.bueno@metempsy.com                const sc_report *r = ::sc_gem5::reportifyException();
8513772Sjavier.bueno@metempsy.com                resultStr = r->what();
8613772Sjavier.bueno@metempsy.com            }
8713772Sjavier.bueno@metempsy.com            ::sc_gem5::Kernel::scMainFinished(true);
8813772Sjavier.bueno@metempsy.com            ::sc_gem5::scheduler.clear();
8913772Sjavier.bueno@metempsy.com        } else {
9013772Sjavier.bueno@metempsy.com            // If python tries to call sc_main but no sc_main was defined...
9113772Sjavier.bueno@metempsy.com            fatal("sc_main called but not defined.\n");
9213772Sjavier.bueno@metempsy.com        }
9313772Sjavier.bueno@metempsy.com    }
9413772Sjavier.bueno@metempsy.com};
9513772Sjavier.bueno@metempsy.com
9613772Sjavier.bueno@metempsy.comScMainFiber scMainFiber;
9713772Sjavier.bueno@metempsy.com
9813772Sjavier.bueno@metempsy.com// This wrapper adapts the python version of sc_main to the c++ version.
9913772Sjavier.bueno@metempsy.comvoid
10013772Sjavier.bueno@metempsy.comsc_main(pybind11::args args)
10113772Sjavier.bueno@metempsy.com{
10213772Sjavier.bueno@metempsy.com    panic_if(scMainCalled, "sc_main called more than once.");
10313772Sjavier.bueno@metempsy.com
10413772Sjavier.bueno@metempsy.com    _argc = args.size();
10513772Sjavier.bueno@metempsy.com    _argv = new char *[_argc];
10613772Sjavier.bueno@metempsy.com
10713772Sjavier.bueno@metempsy.com    // Initialize all the _argvs to NULL so we can delete [] them
10813772Sjavier.bueno@metempsy.com    // unconditionally.
10913772Sjavier.bueno@metempsy.com    for (int idx = 0; idx < _argc; idx++)
11013772Sjavier.bueno@metempsy.com        _argv[idx] = NULL;
11113772Sjavier.bueno@metempsy.com
11213772Sjavier.bueno@metempsy.com    // Attempt to convert all the arguments to strings. If that fails, clean
11313772Sjavier.bueno@metempsy.com    // up after ourselves. Also don't count this as a call to sc_main since
11413772Sjavier.bueno@metempsy.com    // we never got to the c++ version of that function.
11513772Sjavier.bueno@metempsy.com    try {
11613772Sjavier.bueno@metempsy.com        for (int idx = 0; idx < _argc; idx++) {
11713772Sjavier.bueno@metempsy.com            std::string arg = args[idx].cast<std::string>();
11813772Sjavier.bueno@metempsy.com            _argv[idx] = new char[arg.length() + 1];
11913772Sjavier.bueno@metempsy.com            strcpy(_argv[idx], arg.c_str());
12013772Sjavier.bueno@metempsy.com        }
12113772Sjavier.bueno@metempsy.com    } catch (...) {
12213772Sjavier.bueno@metempsy.com        // If that didn't work for some reason (probably a conversion error)
12313772Sjavier.bueno@metempsy.com        // blow away _argv and _argc and pass on the exception.
12413772Sjavier.bueno@metempsy.com        for (int idx = 0; idx < _argc; idx++)
12513772Sjavier.bueno@metempsy.com            delete [] _argv[idx];
12613772Sjavier.bueno@metempsy.com        delete [] _argv;
12713772Sjavier.bueno@metempsy.com        _argc = 0;
12813772Sjavier.bueno@metempsy.com        throw;
12913772Sjavier.bueno@metempsy.com    }
13013772Sjavier.bueno@metempsy.com
13113772Sjavier.bueno@metempsy.com    // At this point we're going to call the c++ sc_main, so we can't try
13213772Sjavier.bueno@metempsy.com    // again later.
13313772Sjavier.bueno@metempsy.com    scMainCalled = true;
13413772Sjavier.bueno@metempsy.com
13513772Sjavier.bueno@metempsy.com    scMainFiber.run();
13613772Sjavier.bueno@metempsy.com}
13713772Sjavier.bueno@metempsy.com
13813772Sjavier.bueno@metempsy.comint
13913772Sjavier.bueno@metempsy.comsc_main_result_code()
14013772Sjavier.bueno@metempsy.com{
14113772Sjavier.bueno@metempsy.com    return scMainFiber.resultInt;
14213772Sjavier.bueno@metempsy.com}
14313772Sjavier.bueno@metempsy.com
14413772Sjavier.bueno@metempsy.comstd::string
14513772Sjavier.bueno@metempsy.comsc_main_result_str()
14613772Sjavier.bueno@metempsy.com{
14713772Sjavier.bueno@metempsy.com    return scMainFiber.resultStr;
14813772Sjavier.bueno@metempsy.com}
14913772Sjavier.bueno@metempsy.com
15013772Sjavier.bueno@metempsy.com// Make our sc_main wrapper available in the internal _m5 python module under
15113772Sjavier.bueno@metempsy.com// the systemc submodule.
15213772Sjavier.bueno@metempsy.com
15313772Sjavier.bueno@metempsy.comstruct InstallScMain : public ::sc_gem5::PythonInitFunc
15413772Sjavier.bueno@metempsy.com{
15513772Sjavier.bueno@metempsy.com    void
15613772Sjavier.bueno@metempsy.com    run(pybind11::module &systemc) override
15713772Sjavier.bueno@metempsy.com    {
15813772Sjavier.bueno@metempsy.com        systemc.def("sc_main", &sc_main);
15913772Sjavier.bueno@metempsy.com        systemc.def("sc_main_result_code", &sc_main_result_code);
16013772Sjavier.bueno@metempsy.com        systemc.def("sc_main_result_str", &sc_main_result_str);
16113772Sjavier.bueno@metempsy.com    }
16213772Sjavier.bueno@metempsy.com} installScMain;
16313772Sjavier.bueno@metempsy.com
16413772Sjavier.bueno@metempsy.comsc_stop_mode _stop_mode = SC_STOP_FINISH_DELTA;
16513772Sjavier.bueno@metempsy.com
16613772Sjavier.bueno@metempsy.com} // anonymous namespace
16713772Sjavier.bueno@metempsy.com
16813772Sjavier.bueno@metempsy.comint
16913772Sjavier.bueno@metempsy.comsc_argc()
17013772Sjavier.bueno@metempsy.com{
17113772Sjavier.bueno@metempsy.com    return _argc;
17213772Sjavier.bueno@metempsy.com}
17313772Sjavier.bueno@metempsy.com
17413772Sjavier.bueno@metempsy.comconst char *const *
17513772Sjavier.bueno@metempsy.comsc_argv()
17613772Sjavier.bueno@metempsy.com{
17713772Sjavier.bueno@metempsy.com    return _argv;
17813772Sjavier.bueno@metempsy.com}
17913772Sjavier.bueno@metempsy.com
18013772Sjavier.bueno@metempsy.comvoid
18113772Sjavier.bueno@metempsy.comsc_start()
18213772Sjavier.bueno@metempsy.com{
18313772Sjavier.bueno@metempsy.com    Tick now = ::sc_gem5::scheduler.getCurTick();
18413772Sjavier.bueno@metempsy.com    sc_start(sc_time::from_value(MaxTick - now), SC_EXIT_ON_STARVATION);
18513772Sjavier.bueno@metempsy.com}
18613772Sjavier.bueno@metempsy.com
18713772Sjavier.bueno@metempsy.comvoid
18813772Sjavier.bueno@metempsy.comsc_pause()
18913772Sjavier.bueno@metempsy.com{
19013772Sjavier.bueno@metempsy.com    if (::sc_gem5::Kernel::status() == SC_RUNNING)
19113772Sjavier.bueno@metempsy.com        ::sc_gem5::scheduler.schedulePause();
19213772Sjavier.bueno@metempsy.com}
19313772Sjavier.bueno@metempsy.com
19413772Sjavier.bueno@metempsy.comvoid
19513772Sjavier.bueno@metempsy.comsc_start(const sc_time &time, sc_starvation_policy p)
19613772Sjavier.bueno@metempsy.com{
19713772Sjavier.bueno@metempsy.com    if (time.value() == 0) {
19813772Sjavier.bueno@metempsy.com        ::sc_gem5::scheduler.oneCycle();
19913772Sjavier.bueno@metempsy.com    } else {
20013772Sjavier.bueno@metempsy.com        Tick now = ::sc_gem5::scheduler.getCurTick();
20113772Sjavier.bueno@metempsy.com        if (MaxTick - now < time.value()) {
20213772Sjavier.bueno@metempsy.com            SC_REPORT_ERROR("(E544) simulation time value overflow, "
20313772Sjavier.bueno@metempsy.com                    "simulation aborted", "");
20413772Sjavier.bueno@metempsy.com        }
20513772Sjavier.bueno@metempsy.com        ::sc_gem5::scheduler.start(now + time.value(), p == SC_RUN_TO_TIME);
20613772Sjavier.bueno@metempsy.com    }
20713772Sjavier.bueno@metempsy.com}
20813772Sjavier.bueno@metempsy.com
20913772Sjavier.bueno@metempsy.comvoid
21013772Sjavier.bueno@metempsy.comsc_set_stop_mode(sc_stop_mode mode)
21113772Sjavier.bueno@metempsy.com{
21213772Sjavier.bueno@metempsy.com    if (sc_is_running()) {
21313772Sjavier.bueno@metempsy.com        SC_REPORT_ERROR("attempt to set sc_stop mode "
21413772Sjavier.bueno@metempsy.com                        "after start will be ignored", "");
21513772Sjavier.bueno@metempsy.com        return;
21613772Sjavier.bueno@metempsy.com    }
21713772Sjavier.bueno@metempsy.com    _stop_mode = mode;
21813772Sjavier.bueno@metempsy.com}
21913772Sjavier.bueno@metempsy.com
22013772Sjavier.bueno@metempsy.comsc_stop_mode
22113772Sjavier.bueno@metempsy.comsc_get_stop_mode()
22213772Sjavier.bueno@metempsy.com{
22313772Sjavier.bueno@metempsy.com    return _stop_mode;
22413772Sjavier.bueno@metempsy.com}
22513772Sjavier.bueno@metempsy.com
22613772Sjavier.bueno@metempsy.comvoid
22713772Sjavier.bueno@metempsy.comsc_stop()
22813772Sjavier.bueno@metempsy.com{
22913772Sjavier.bueno@metempsy.com    static bool stop_called = false;
23013772Sjavier.bueno@metempsy.com    if (stop_called) {
23113772Sjavier.bueno@metempsy.com        static bool stop_warned = false;
23213772Sjavier.bueno@metempsy.com        if (!stop_warned)
23313772Sjavier.bueno@metempsy.com            SC_REPORT_WARNING("(W545) sc_stop has already been called", "");
23413772Sjavier.bueno@metempsy.com        stop_warned = true;
23513772Sjavier.bueno@metempsy.com        return;
23613772Sjavier.bueno@metempsy.com    }
23713772Sjavier.bueno@metempsy.com    stop_called = true;
23813772Sjavier.bueno@metempsy.com
23913772Sjavier.bueno@metempsy.com    if (::sc_gem5::Kernel::status() == SC_STOPPED)
24013772Sjavier.bueno@metempsy.com        return;
24113772Sjavier.bueno@metempsy.com
24213772Sjavier.bueno@metempsy.com    if ((sc_get_status() & SC_RUNNING)) {
24313772Sjavier.bueno@metempsy.com        bool finish_delta = (_stop_mode == SC_STOP_FINISH_DELTA);
24413772Sjavier.bueno@metempsy.com        ::sc_gem5::scheduler.scheduleStop(finish_delta);
24513772Sjavier.bueno@metempsy.com    } else {
24613772Sjavier.bueno@metempsy.com        ::sc_gem5::Kernel::stop();
24713772Sjavier.bueno@metempsy.com    }
24813772Sjavier.bueno@metempsy.com}
24913772Sjavier.bueno@metempsy.com
25013772Sjavier.bueno@metempsy.comconst sc_time &
25113772Sjavier.bueno@metempsy.comsc_time_stamp()
25213772Sjavier.bueno@metempsy.com{
25313772Sjavier.bueno@metempsy.com    static sc_time tstamp(1.0, SC_SEC);
25413772Sjavier.bueno@metempsy.com    tstamp = sc_time::from_value(::sc_gem5::scheduler.getCurTick());
25513772Sjavier.bueno@metempsy.com    return tstamp;
25613772Sjavier.bueno@metempsy.com}
25713772Sjavier.bueno@metempsy.com
25813772Sjavier.bueno@metempsy.comsc_dt::uint64
25913772Sjavier.bueno@metempsy.comsc_delta_count()
26013772Sjavier.bueno@metempsy.com{
26113772Sjavier.bueno@metempsy.com    return sc_gem5::scheduler.numCycles();
26213772Sjavier.bueno@metempsy.com}
26313772Sjavier.bueno@metempsy.com
26413772Sjavier.bueno@metempsy.combool
26513772Sjavier.bueno@metempsy.comsc_is_running()
26613772Sjavier.bueno@metempsy.com{
26713772Sjavier.bueno@metempsy.com    return sc_get_status() & (SC_RUNNING | SC_PAUSED);
26813772Sjavier.bueno@metempsy.com}
26913772Sjavier.bueno@metempsy.com
270bool
271sc_pending_activity_at_current_time()
272{
273    return ::sc_gem5::scheduler.pendingCurr();
274}
275
276bool
277sc_pending_activity_at_future_time()
278{
279    return ::sc_gem5::scheduler.pendingFuture();
280}
281
282bool
283sc_pending_activity()
284{
285    return sc_pending_activity_at_current_time() ||
286           sc_pending_activity_at_future_time();
287}
288
289sc_time
290sc_time_to_pending_activity()
291{
292    return sc_time::from_value(::sc_gem5::scheduler.timeToPending());
293}
294
295sc_status
296sc_get_status()
297{
298    return ::sc_gem5::kernel ? ::sc_gem5::kernel->status() : SC_ELABORATION;
299}
300
301std::ostream &
302operator << (std::ostream &os, sc_status s)
303{
304    switch (s) {
305      case SC_ELABORATION:
306        os << "SC_ELABORATION";
307        break;
308      case SC_BEFORE_END_OF_ELABORATION:
309        os << "SC_BEFORE_END_OF_ELABORATION";
310        break;
311      case SC_END_OF_ELABORATION:
312        os << "SC_END_OF_ELABORATION";
313        break;
314      case SC_START_OF_SIMULATION:
315        os << "SC_START_OF_SIMULATION";
316        break;
317      case SC_RUNNING:
318        os << "SC_RUNNING";
319        break;
320      case SC_PAUSED:
321        os << "SC_PAUSED";
322        break;
323      case SC_STOPPED:
324        os << "SC_STOPPED";
325        break;
326      case SC_END_OF_SIMULATION:
327        os << "SC_END_OF_SIMULATION";
328        break;
329
330        // Nonstandard
331      case SC_END_OF_INITIALIZATION:
332        os << "SC_END_OF_INITIALIZATION";
333        break;
334      case SC_END_OF_UPDATE:
335        os << "SC_END_OF_UPDATE";
336        break;
337      case SC_BEFORE_TIMESTEP:
338        os << "SC_BEFORE_TIMESTEP";
339        break;
340
341      default:
342        if (s & SC_STATUS_ANY) {
343            const char *prefix = "(";
344            for (sc_status m = (sc_status)0x1;
345                    m < SC_STATUS_ANY; m = (sc_status)(m << 1)) {
346                if (m & s) {
347                    os << prefix;
348                    prefix = "|";
349                    os << m;
350                }
351            }
352            os << ")";
353        } else {
354            ccprintf(os, "%#x", s);
355        }
356    }
357
358    return os;
359}
360
361} // namespace sc_core
362