sc_main.cc revision 13255
11689SN/A/*
22329SN/A * Copyright 2018 Google, Inc.
31689SN/A *
41689SN/A * Redistribution and use in source and binary forms, with or without
51689SN/A * modification, are permitted provided that the following conditions are
61689SN/A * met: redistributions of source code must retain the above copyright
71689SN/A * notice, this list of conditions and the following disclaimer;
81689SN/A * redistributions in binary form must reproduce the above copyright
91689SN/A * notice, this list of conditions and the following disclaimer in the
101689SN/A * documentation and/or other materials provided with the distribution;
111689SN/A * neither the name of the copyright holders nor the names of its
121689SN/A * contributors may be used to endorse or promote products derived from
131689SN/A * this software without specific prior written permission.
141689SN/A *
151689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
181689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
191689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
201689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
211689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
221689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
231689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
241689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
251689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
261689SN/A *
272665Ssaidi@eecs.umich.edu * Authors: Gabe Black
282665Ssaidi@eecs.umich.edu */
291689SN/A
301060SN/A#include <cstring>
312292SN/A#include <string>
322292SN/A
331060SN/A#include "base/fiber.hh"
341060SN/A#include "base/logging.hh"
351060SN/A#include "base/types.hh"
361461SN/A#include "sim/core.hh"
371060SN/A#include "sim/eventq.hh"
381060SN/A#include "sim/init.hh"
392292SN/A#include "systemc/core/kernel.hh"
402329SN/A#include "systemc/core/python.hh"
412329SN/A#include "systemc/core/scheduler.hh"
422329SN/A#include "systemc/ext/core/sc_main.hh"
432329SN/A#include "systemc/ext/utils/sc_report_handler.hh"
442329SN/A
452292SN/A// A weak symbol to detect if sc_main has been defined, and if so where it is.
461060SN/A[[gnu::weak]] int sc_main(int argc, char *argv[]);
472292SN/A
481060SN/Anamespace sc_core
491060SN/A{
501060SN/A
512733Sktlim@umich.edunamespace
521061SN/A{
531060SN/A
541061SN/Abool scMainCalled = false;
551060SN/A
561061SN/Aint _argc = 0;
571061SN/Achar **_argv = NULL;
581061SN/A
591061SN/Aclass ScMainFiber : public Fiber
601060SN/A{
611060SN/A  public:
622292SN/A    std::string resultStr;
632292SN/A    int resultInt;
642292SN/A
652292SN/A    ScMainFiber() : resultInt(1) {}
662292SN/A
672292SN/A    void
682292SN/A    main()
692292SN/A    {
702292SN/A        if (::sc_main) {
712292SN/A            try {
721060SN/A                resultInt = ::sc_main(_argc, _argv);
731060SN/A                if (resultInt)
742292SN/A                    resultStr = "sc_main returned non-zero";
751060SN/A                else
761060SN/A                    resultStr = "sc_main finished";
771060SN/A                // Make sure no systemc events/notifications are scheduled
781060SN/A                // after sc_main returns.
791060SN/A            } catch (const sc_report &r) {
801060SN/A                // There was an exception nobody caught.
812292SN/A                resultStr = r.what();
822292SN/A            } catch (...) {
832292SN/A                // There was some other type of exception we need to wrap.
842292SN/A                const sc_report *r = ::sc_gem5::reportifyException();
852292SN/A                resultStr = r->what();
861060SN/A            }
871060SN/A            ::sc_gem5::Kernel::scMainFinished(true);
882292SN/A            ::sc_gem5::scheduler.clear();
892292SN/A        } else {
901060SN/A            // If python tries to call sc_main but no sc_main was defined...
912292SN/A            fatal("sc_main called but not defined.\n");
922292SN/A        }
932292SN/A    }
942292SN/A};
951062SN/A
961062SN/AScMainFiber scMainFiber;
972292SN/A
982733Sktlim@umich.edu// This wrapper adapts the python version of sc_main to the c++ version.
991060SN/Avoid
1002292SN/Asc_main(pybind11::args args)
1011060SN/A{
1021060SN/A    panic_if(scMainCalled, "sc_main called more than once.");
1032292SN/A
1041060SN/A    _argc = args.size();
1051060SN/A    _argv = new char *[_argc];
1062292SN/A
1071060SN/A    // Initialize all the _argvs to NULL so we can delete [] them
1081060SN/A    // unconditionally.
1092292SN/A    for (int idx = 0; idx < _argc; idx++)
1102292SN/A        _argv[idx] = NULL;
1112292SN/A
1122348SN/A    // Attempt to convert all the arguments to strings. If that fails, clean
1132307SN/A    // up after ourselves. Also don't count this as a call to sc_main since
1142307SN/A    // we never got to the c++ version of that function.
1152348SN/A    try {
1162307SN/A        for (int idx = 0; idx < _argc; idx++) {
1172348SN/A            std::string arg = args[idx].cast<std::string>();
1182292SN/A            _argv[idx] = new char[arg.length() + 1];
1192292SN/A            strcpy(_argv[idx], arg.c_str());
1202292SN/A        }
1211060SN/A    } catch (...) {
1221060SN/A        // If that didn't work for some reason (probably a conversion error)
1232292SN/A        // blow away _argv and _argc and pass on the exception.
1242292SN/A        for (int idx = 0; idx < _argc; idx++)
1252292SN/A            delete [] _argv[idx];
1262292SN/A        delete [] _argv;
1272292SN/A        _argc = 0;
1282292SN/A        throw;
1292292SN/A    }
1302292SN/A
1312292SN/A    // At this point we're going to call the c++ sc_main, so we can't try
1322292SN/A    // again later.
1332292SN/A    scMainCalled = true;
1342292SN/A
1352292SN/A    scMainFiber.run();
1361060SN/A}
1371060SN/A
1382292SN/Aint
1392292SN/Asc_main_result_code()
1402292SN/A{
1412292SN/A    return scMainFiber.resultInt;
1422292SN/A}
1432292SN/A
1442292SN/Astd::string
1452292SN/Asc_main_result_str()
1462292SN/A{
1472292SN/A    return scMainFiber.resultStr;
1482292SN/A}
1492292SN/A
1502292SN/A// Make our sc_main wrapper available in the internal _m5 python module under
1512292SN/A// the systemc submodule.
1522292SN/A
1532292SN/Astruct InstallScMain : public ::sc_gem5::PythonInitFunc
1542292SN/A{
1552292SN/A    void
1562292SN/A    run(pybind11::module &systemc) override
1572292SN/A    {
1582292SN/A        systemc.def("sc_main", &sc_main);
1592292SN/A        systemc.def("sc_main_result_code", &sc_main_result_code);
1602292SN/A        systemc.def("sc_main_result_str", &sc_main_result_str);
1612292SN/A    }
1622292SN/A} installScMain;
1632292SN/A
1641681SN/Asc_stop_mode _stop_mode = SC_STOP_FINISH_DELTA;
1651681SN/A
1662292SN/A} // anonymous namespace
1672292SN/A
1682292SN/Aint
1692292SN/Asc_argc()
1702292SN/A{
1711060SN/A    return _argc;
1722292SN/A}
1732292SN/A
1742292SN/Aconst char *const *
1752292SN/Asc_argv()
1762292SN/A{
1771060SN/A    return _argv;
1782292SN/A}
1792292SN/A
1802292SN/Avoid
1812292SN/Asc_start()
1821060SN/A{
1831684SN/A    Tick now = ::sc_gem5::scheduler.getCurTick();
1842292SN/A    sc_start(sc_time::from_value(MaxTick - now), SC_EXIT_ON_STARVATION);
1852292SN/A}
1862292SN/A
1872292SN/Avoid
1881681SN/Asc_pause()
1891684SN/A{
1901060SN/A    if (::sc_gem5::Kernel::status() == SC_RUNNING)
1911060SN/A        ::sc_gem5::scheduler.schedulePause();
1922733Sktlim@umich.edu}
1931060SN/A
1941060SN/Avoid
1951060SN/Asc_start(const sc_time &time, sc_starvation_policy p)
1961060SN/A{
1971060SN/A    if (time.value() == 0) {
1981060SN/A        ::sc_gem5::scheduler.oneCycle();
1991060SN/A    } else {
2001060SN/A        Tick now = ::sc_gem5::scheduler.getCurTick();
2011060SN/A        if (MaxTick - now < time.value()) {
2021060SN/A            SC_REPORT_ERROR("(E544) simulation time value overflow, "
2031060SN/A                    "simulation aborted", "");
2041060SN/A        }
2051060SN/A        ::sc_gem5::scheduler.start(now + time.value(), p == SC_RUN_TO_TIME);
2061060SN/A    }
2071060SN/A}
2081060SN/A
2091060SN/Avoid
2101060SN/Asc_set_stop_mode(sc_stop_mode mode)
2111060SN/A{
2121060SN/A    if (sc_is_running()) {
2131060SN/A        SC_REPORT_ERROR("attempt to set sc_stop mode "
2141060SN/A                        "after start will be ignored", "");
2151060SN/A        return;
2161060SN/A    }
2171060SN/A    _stop_mode = mode;
2181060SN/A}
2191060SN/A
2201060SN/Asc_stop_mode
2211060SN/Asc_get_stop_mode()
2222292SN/A{
2232292SN/A    return _stop_mode;
2242292SN/A}
2251060SN/A
2262292SN/Avoid
2271060SN/Asc_stop()
2282292SN/A{
2292292SN/A    static bool stop_called = false;
2302292SN/A    if (stop_called) {
2312292SN/A        static bool stop_warned = false;
2322292SN/A        if (!stop_warned)
2332292SN/A            SC_REPORT_WARNING("(W545) sc_stop has already been called", "");
2342292SN/A        stop_warned = true;
2352292SN/A        return;
2362292SN/A    }
2372292SN/A    stop_called = true;
2382292SN/A
2392292SN/A    if (::sc_gem5::Kernel::status() == SC_STOPPED)
2402292SN/A        return;
2412292SN/A
2422292SN/A    if ((sc_get_status() & SC_RUNNING)) {
2431060SN/A        bool finish_delta = (_stop_mode == SC_STOP_FINISH_DELTA);
2441060SN/A        ::sc_gem5::scheduler.scheduleStop(finish_delta);
2451060SN/A    } else {
2461060SN/A        ::sc_gem5::Kernel::stop();
2471060SN/A    }
2481060SN/A}
2491060SN/A
2501060SN/Aconst sc_time &
2511060SN/Asc_time_stamp()
2521060SN/A{
2531060SN/A    static sc_time tstamp(1.0, SC_SEC);
2541060SN/A    tstamp = sc_time::from_value(::sc_gem5::scheduler.getCurTick());
2551060SN/A    return tstamp;
2561060SN/A}
2571061SN/A
2582292SN/Asc_dt::uint64
2592292SN/Asc_delta_count()
2602292SN/A{
2612292SN/A    return sc_gem5::scheduler.numCycles();
2622292SN/A}
2632292SN/A
2642292SN/Abool
2652292SN/Asc_is_running()
2662292SN/A{
2672292SN/A    return sc_get_status() & (SC_RUNNING | SC_PAUSED);
2682292SN/A}
2692292SN/A
2702292SN/Abool
2712292SN/Asc_pending_activity_at_current_time()
2722292SN/A{
2732292SN/A    return ::sc_gem5::scheduler.pendingCurr();
2742292SN/A}
2752292SN/A
2762292SN/Abool
2772292SN/Asc_pending_activity_at_future_time()
2782292SN/A{
2792292SN/A    return ::sc_gem5::scheduler.pendingFuture();
2802292SN/A}
2812292SN/A
2822292SN/Abool
2832307SN/Asc_pending_activity()
2842307SN/A{
2852292SN/A    return sc_pending_activity_at_current_time() ||
2862292SN/A           sc_pending_activity_at_future_time();
2872292SN/A}
2882292SN/A
2891061SN/Asc_time
2901062SN/Asc_time_to_pending_activity()
2912292SN/A{
2921062SN/A    return sc_time::from_value(::sc_gem5::scheduler.timeToPending());
2932292SN/A}
2941062SN/A
2951060SN/Asc_status
2961060SN/Asc_get_status()
2972292SN/A{
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