systemc: Hook up sc_main.

sc_main is exported as a python method on the SystemC_Kernel class and
takes a series of string arguments. The internal c++ implementation
converts those arguments into the standard argc and argv and uses them
to call the standard SystemC version of that function.

A weak SystemC version of sc_main is provided so that systemc will
compile with or without a simulation provided version of that
function. The weak version just complains and dies.

Change-Id: Iad735536c37c8bc85d06cf24779f607ae4309b8b
Reviewed-on: https://gem5-review.googlesource.com/10824
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Gabe Black <gabeblack@google.com>
diff --git a/src/systemc/SConscript b/src/systemc/SConscript
index 3677a60..6e6742f 100644
--- a/src/systemc/SConscript
+++ b/src/systemc/SConscript
@@ -32,5 +32,6 @@
 
     Source('kernel.cc')
 
+    Source('sc_main.cc')
     Source('sc_module_name.cc')
     Source('sc_object.cc')
diff --git a/src/systemc/SystemC.py b/src/systemc/SystemC.py
index 8eb6c22..bc04ed6 100644
--- a/src/systemc/SystemC.py
+++ b/src/systemc/SystemC.py
@@ -36,6 +36,11 @@
     cxx_class = 'SystemC::Kernel'
     cxx_header = 'systemc/kernel.hh'
 
+    def sc_main(self, *args):
+        '''Call the systemc sc_main function with the given string args'''
+        from _m5.systemc import sc_main
+        sc_main(*args)
+
 # This class represents systemc sc_object instances in python config files. It
 # inherits from SimObject in python, but the c++ version, sc_core::sc_object,
 # doesn't inherit from gem5's c++ SimObject class.
diff --git a/src/systemc/sc_main.cc b/src/systemc/sc_main.cc
new file mode 100644
index 0000000..88d51ba
--- /dev/null
+++ b/src/systemc/sc_main.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2018 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "systemc/sc_main.hh"
+
+#include <cstring>
+
+#include "base/logging.hh"
+#include "python/pybind11/pybind.hh"
+#include "sim/init.hh"
+
+// A default version of this function in case one isn't otherwise defined.
+// This ensures everything will link properly whether or not the user defined
+// a custom sc_main function. If they didn't but still try to call it, throw
+// an error and die.
+[[gnu::weak]] int
+sc_main(int argc, char *argv[])
+{
+    // If python attempts to call sc_main but no sc_main was defined...
+    fatal("sc_main called but not defined.\n");
+}
+
+namespace sc_core
+{
+
+namespace
+{
+
+bool scMainCalled = false;
+
+int _argc = 0;
+char **_argv = NULL;
+
+// This wrapper adapts the python version of sc_main to the c++ version.
+void
+sc_main(pybind11::args args)
+{
+    panic_if(scMainCalled, "sc_main called more than once.");
+
+    _argc = args.size();
+    _argv = new char *[_argc];
+
+    // Initialize all the _argvs to NULL so we can delete [] them
+    // unconditionally.
+    for (int idx = 0; idx < _argc; idx++)
+        _argv[idx] = NULL;
+
+    // Attempt to convert all the arguments to strings. If that fails, clean
+    // up after ourselves. Also don't count this as a call to sc_main since
+    // we never got to the c++ version of that function.
+    try {
+        for (int idx = 0; idx < _argc; idx++) {
+            std::string arg = args[idx].cast<std::string>();
+            _argv[idx] = new char[arg.length() + 1];
+            strcpy(_argv[idx], arg.c_str());
+        }
+    } catch (...) {
+        // If that didn't work for some reason (probably a conversion error)
+        // blow away _argv and _argc and pass on the exception.
+        for (int idx = 0; idx < _argc; idx++)
+            delete [] _argv[idx];
+        delete [] _argv;
+        _argc = 0;
+        throw;
+    }
+
+    // At this point we're going to call the c++ sc_main, so we can't try
+    // again later.
+    scMainCalled = true;
+
+    //TODO Start a new fiber to call sc_main from.
+    ::sc_main(_argc, _argv);
+}
+
+// Make our sc_main wrapper available in the internal _m5 python module under
+// the systemc submodule.
+void
+systemc_pybind(pybind11::module &m_internal)
+{
+    pybind11::module m = m_internal.def_submodule("systemc");
+    m.def("sc_main", &sc_main);
+}
+EmbeddedPyBind embed_("systemc", &systemc_pybind);
+
+} // anonymous namespace
+
+int
+sc_argc()
+{
+    return _argc;
+}
+
+const char *const *
+sc_argv()
+{
+    return _argv;
+}
+
+} // namespace sc_core
diff --git a/src/systemc/sc_main.hh b/src/systemc/sc_main.hh
new file mode 100644
index 0000000..d9fd2b1
--- /dev/null
+++ b/src/systemc/sc_main.hh
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __SYSTEMC_SC_MAIN_HH__
+#define __SYSTEMC_SC_MAIN_HH__
+
+extern "C" int sc_main(int argc, char *argv[]);
+
+namespace sc_core
+{
+    extern "C" int sc_argc();
+
+    // The standard version of this function doesn't have these "const"
+    // qualifiers, but the canonical SystemC implementation does.
+    extern "C" const char *const *sc_argv();
+} // namespace sc_core
+
+#endif  //__SYSTEMC_SC_MAIN_HH__