init.cc revision 11990
17860SN/A/*
27860SN/A * Copyright (c) 2012, 2017 ARM Limited
37860SN/A * All rights reserved
49988Snilay@cs.wisc.edu *
58825Snilay@cs.wisc.edu * The license below extends only to copyright in the software and shall
69988Snilay@cs.wisc.edu * not be construed as granting a license to any other intellectual
77935SN/A * property including but not limited to intellectual property relating
87935SN/A * to a hardware implementation of the functionality of the software
97935SN/A * licensed hereunder.  You may use the software subject to the license
107860SN/A * terms below provided that you ensure that this notice is replicated
117860SN/A * unmodified and in its entirety in all distributions of the software,
127860SN/A * modified or unmodified, in source code or in binary form.
1310315Snilay@cs.wisc.edu *
148825Snilay@cs.wisc.edu * Copyright (c) 2000-2005 The Regents of The University of Michigan
159885Sstever@gmail.com * Copyright (c) 2008 The Hewlett-Packard Development Company
169885Sstever@gmail.com * All rights reserved.
179988Snilay@cs.wisc.edu *
188825Snilay@cs.wisc.edu * Redistribution and use in source and binary forms, with or without
198825Snilay@cs.wisc.edu * modification, are permitted provided that the following conditions are
2010315Snilay@cs.wisc.edu * met: redistributions of source code must retain the above copyright
218825Snilay@cs.wisc.edu * notice, this list of conditions and the following disclaimer;
2210038SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
239449SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
249449SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
258464SN/A * neither the name of the copyright holders nor the names of its
2610798Ssteve.reinhardt@amd.com * contributors may be used to endorse or promote products derived from
278721SN/A * this software without specific prior written permission.
288825Snilay@cs.wisc.edu *
298825Snilay@cs.wisc.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
307935SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
317935SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
327935SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
337935SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
347935SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
357935SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
367935SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
378893Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
387860SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
399885Sstever@gmail.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
409885Sstever@gmail.com *
419885Sstever@gmail.com * Authors: Nathan Binkert
4210315Snilay@cs.wisc.edu */
439988Snilay@cs.wisc.edu
4410315Snilay@cs.wisc.edu#include <Python.h>
459885Sstever@gmail.com
469885Sstever@gmail.com#include "sim/init.hh"
477860SN/A
487860SN/A#include <marshal.h>
4910038SAli.Saidi@ARM.com#include <zlib.h>
507860SN/A
5110451Snilay@cs.wisc.edu#include <iostream>
528210SN/A#include <list>
5310451Snilay@cs.wisc.edu#include <string>
5410451Snilay@cs.wisc.edu
557860SN/A#include "base/cprintf.hh"
567860SN/A#include "base/misc.hh"
577860SN/A#include "base/types.hh"
589481Snilay@cs.wisc.edu#include "config/have_protobuf.hh"
597860SN/A#include "python/pybind11/pybind.hh"
607860SN/A#include "sim/async.hh"
619885Sstever@gmail.com#include "sim/core.hh"
627860SN/A
637860SN/A#if HAVE_PROTOBUF
647860SN/A#include <google/protobuf/stubs/common.h>
657860SN/A
667860SN/A#endif
677860SN/A
687860SN/Ausing namespace std;
6910451Snilay@cs.wisc.edunamespace py = pybind11;
7010451Snilay@cs.wisc.edu
7110451Snilay@cs.wisc.edu// The python library is totally messed up with respect to constness,
727860SN/A// so make a simple macro to make life a little easier
738825Snilay@cs.wisc.edu#define PyCC(x) (const_cast<char *>(x))
747860SN/A
7510038SAli.Saidi@ARM.comEmbeddedPython *EmbeddedPython::importer = NULL;
767860SN/APyObject *EmbeddedPython::importerModule = NULL;
779988Snilay@cs.wisc.eduEmbeddedPython::EmbeddedPython(const char *filename, const char *abspath,
7810451Snilay@cs.wisc.edu    const char *modpath, const unsigned char *code, int zlen, int len)
7910451Snilay@cs.wisc.edu    : filename(filename), abspath(abspath), modpath(modpath), code(code),
8010451Snilay@cs.wisc.edu      zlen(zlen), len(len)
817860SN/A{
8210451Snilay@cs.wisc.edu    // if we've added the importer keep track of it because we need it
837860SN/A    // to bootstrap.
847860SN/A    if (string(modpath) == string("importer"))
857860SN/A        importer = this;
867860SN/A    else
877860SN/A        getList().push_back(this);
887860SN/A}
897860SN/A
907860SN/Alist<EmbeddedPython *> &
918825Snilay@cs.wisc.eduEmbeddedPython::getList()
929449SAli.Saidi@ARM.com{
937860SN/A    static list<EmbeddedPython *> the_list;
947860SN/A    return the_list;
9510038SAli.Saidi@ARM.com}
967860SN/A
977860SN/A/*
987860SN/A * Uncompress and unmarshal the code object stored in the
997860SN/A * EmbeddedPython
1007860SN/A */
1018825Snilay@cs.wisc.eduPyObject *
10210451Snilay@cs.wisc.eduEmbeddedPython::getCode() const
10310451Snilay@cs.wisc.edu{
10410451Snilay@cs.wisc.edu    Bytef marshalled[len];
10510451Snilay@cs.wisc.edu    uLongf unzlen = len;
10610451Snilay@cs.wisc.edu    int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen);
1077860SN/A    if (ret != Z_OK)
1087860SN/A        panic("Could not uncompress code: %s\n", zError(ret));
1098825Snilay@cs.wisc.edu    assert(unzlen == (uLongf)len);
1107860SN/A
1117860SN/A    return PyMarshal_ReadObjectFromString((char *)marshalled, len);
1127860SN/A}
11310451Snilay@cs.wisc.edu
1147860SN/Abool
11510451Snilay@cs.wisc.eduEmbeddedPython::addModule() const
1169885Sstever@gmail.com{
1177860SN/A    PyObject *code = getCode();
1187860SN/A    PyObject *result = PyObject_CallMethod(importerModule, PyCC("add_module"),
1197860SN/A        PyCC("sssO"), filename, abspath, modpath, code);
1207860SN/A    if (!result) {
1217860SN/A        PyErr_Print();
1227860SN/A        return false;
1237860SN/A    }
1247860SN/A
1257860SN/A    Py_DECREF(result);
12610242Ssteve.reinhardt@amd.com    return true;
1277860SN/A}
1288521SN/A
1299449SAli.Saidi@ARM.com/*
1307860SN/A * Load and initialize all of the python parts of M5.
1317860SN/A */
1327860SN/Aint
1337860SN/AEmbeddedPython::initAll()
1347860SN/A{
1357860SN/A    // Load the importer module
1367860SN/A    PyObject *code = importer->getCode();
1377860SN/A    importerModule = PyImport_ExecCodeModule(PyCC("importer"), code);
1389481Snilay@cs.wisc.edu    if (!importerModule) {
13910798Ssteve.reinhardt@amd.com        PyErr_Print();
14010451Snilay@cs.wisc.edu        return 1;
14110451Snilay@cs.wisc.edu    }
1429481Snilay@cs.wisc.edu
1439481Snilay@cs.wisc.edu    // Load the rest of the embedded python files into the embedded
1449481Snilay@cs.wisc.edu    // python importer
1459988Snilay@cs.wisc.edu    list<EmbeddedPython *>::iterator i = getList().begin();
1469481Snilay@cs.wisc.edu    list<EmbeddedPython *>::iterator end = getList().end();
1479481Snilay@cs.wisc.edu    for (; i != end; ++i)
1489481Snilay@cs.wisc.edu        if (!(*i)->addModule())
1499481Snilay@cs.wisc.edu            return 1;
1509481Snilay@cs.wisc.edu
1517860SN/A    return 0;
1527860SN/A}
1539885Sstever@gmail.com
1548893Ssaidi@eecs.umich.eduEmbeddedPyBind::EmbeddedPyBind(const char *_name,
1557860SN/A                               void (*init_func)(py::module &),
1569885Sstever@gmail.com                               const char *_base)
15710636Snilay@cs.wisc.edu    : initFunc(init_func), registered(false), name(_name), base(_base)
1589988Snilay@cs.wisc.edu{
1597860SN/A    getMap()[_name] = this;
1609348SAli.Saidi@ARM.com}
1618150SN/A
1627860SN/AEmbeddedPyBind::EmbeddedPyBind(const char *_name,
16310451Snilay@cs.wisc.edu                               void (*init_func)(py::module &))
1647860SN/A    : initFunc(init_func), registered(false), name(_name), base("")
1658835SAli.Saidi@ARM.com{
1669348SAli.Saidi@ARM.com    getMap()[_name] = this;
16710036SAli.Saidi@ARM.com}
16810451Snilay@cs.wisc.edu
1698835SAli.Saidi@ARM.comvoid
1709885Sstever@gmail.comEmbeddedPyBind::init(py::module &m)
17110451Snilay@cs.wisc.edu{
1727860SN/A    if (!registered) {
17310451Snilay@cs.wisc.edu        initFunc(m);
1747860SN/A        registered = true;
1758893Ssaidi@eecs.umich.edu    } else {
1767860SN/A        cprintf("Warning: %s already registered.\n", name);
1779885Sstever@gmail.com    }
1789885Sstever@gmail.com}
1799885Sstever@gmail.com
1809885Sstever@gmail.combool
1819885Sstever@gmail.comEmbeddedPyBind::depsReady() const
1829988Snilay@cs.wisc.edu{
1839885Sstever@gmail.com    return base.empty() || getMap()[base]->registered;
18410036SAli.Saidi@ARM.com}
18510451Snilay@cs.wisc.edu
1869885Sstever@gmail.comstd::map<std::string, EmbeddedPyBind *> &
18710038SAli.Saidi@ARM.comEmbeddedPyBind::getMap()
18810038SAli.Saidi@ARM.com{
18910038SAli.Saidi@ARM.com    static std::map<std::string, EmbeddedPyBind *> objs;
19010038SAli.Saidi@ARM.com    return objs;
19110038SAli.Saidi@ARM.com}
19210798Ssteve.reinhardt@amd.com
19310038SAli.Saidi@ARM.comvoid
19410038SAli.Saidi@ARM.comEmbeddedPyBind::initAll()
19510038SAli.Saidi@ARM.com{
19610038SAli.Saidi@ARM.com    std::list<EmbeddedPyBind *> pending;
19710038SAli.Saidi@ARM.com
19810038SAli.Saidi@ARM.com    py::module m_m5 = py::module("_m5");
19910038SAli.Saidi@ARM.com    m_m5.attr("__package__") = py::cast("_m5");
20010038SAli.Saidi@ARM.com
20110038SAli.Saidi@ARM.com    pybind_init_core(m_m5);
20210038SAli.Saidi@ARM.com    pybind_init_debug(m_m5);
20310038SAli.Saidi@ARM.com
20410038SAli.Saidi@ARM.com    pybind_init_event(m_m5);
20510038SAli.Saidi@ARM.com    pybind_init_pyobject(m_m5);
20610038SAli.Saidi@ARM.com    pybind_init_stats(m_m5);
20710038SAli.Saidi@ARM.com
20810038SAli.Saidi@ARM.com    for (auto &kv : getMap()) {
20910038SAli.Saidi@ARM.com        auto &obj = kv.second;
21010038SAli.Saidi@ARM.com        if (obj->base.empty()) {
2117860SN/A            obj->init(m_m5);
2127860SN/A        } else {
2138825Snilay@cs.wisc.edu            pending.push_back(obj);
2149988Snilay@cs.wisc.edu        }
21510038SAli.Saidi@ARM.com    }
2167860SN/A
2178825Snilay@cs.wisc.edu    while (!pending.empty()) {
2188825Snilay@cs.wisc.edu        for (auto it = pending.begin(); it != pending.end(); ) {
2198825Snilay@cs.wisc.edu            EmbeddedPyBind &obj = **it;
2208825Snilay@cs.wisc.edu            if (obj.depsReady()) {
2219885Sstever@gmail.com                obj.init(m_m5);
2229988Snilay@cs.wisc.edu                it = pending.erase(it);
22310038SAli.Saidi@ARM.com            } else {
2249265SAli.Saidi@ARM.com                ++it;
2258825Snilay@cs.wisc.edu            }
2268893Ssaidi@eecs.umich.edu        }
2277860SN/A    }
2287860SN/A}
2297860SN/A
23010451Snilay@cs.wisc.eduint
23110451Snilay@cs.wisc.eduinitM5Python()
2329988Snilay@cs.wisc.edu{
2337860SN/A    EmbeddedPyBind::initAll();
2347860SN/A    return EmbeddedPython::initAll();
2357860SN/A}
2367860SN/A
23710451Snilay@cs.wisc.edu/*
2389988Snilay@cs.wisc.edu * Make the commands array weak so that they can be overridden (used
2397860SN/A * by unit tests to specify a different python main function.
2407860SN/A */
2417860SN/Aconst char * __attribute__((weak)) m5MainCommands[] = {
2427860SN/A    "import m5",
2439988Snilay@cs.wisc.edu    "m5.main()",
2447860SN/A    0 // sentinel is required
2457860SN/A};
2467860SN/A
2477860SN/A/*
2487860SN/A * Start up the M5 simulator.  This mostly vectors into the python
2497860SN/A * main function.
25010451Snilay@cs.wisc.edu */
25110451Snilay@cs.wisc.eduint
2529988Snilay@cs.wisc.edum5Main(int argc, char **argv)
25310451Snilay@cs.wisc.edu{
2547860SN/A#if HAVE_PROTOBUF
2557860SN/A    // Verify that the version of the protobuf library that we linked
2567860SN/A    // against is compatible with the version of the headers we
2579988Snilay@cs.wisc.edu    // compiled against.
2587860SN/A    GOOGLE_PROTOBUF_VERIFY_VERSION;
2597860SN/A#endif
2607860SN/A
2617860SN/A    PySys_SetArgv(argc, argv);
2627860SN/A
2637860SN/A    // We have to set things up in the special __main__ module
2649988Snilay@cs.wisc.edu    PyObject *module = PyImport_AddModule(PyCC("__main__"));
26510451Snilay@cs.wisc.edu    if (module == NULL)
2667860SN/A        panic("Could not import __main__");
26710451Snilay@cs.wisc.edu    PyObject *dict = PyModule_GetDict(module);
26810451Snilay@cs.wisc.edu
26910451Snilay@cs.wisc.edu    // import the main m5 module
27010451Snilay@cs.wisc.edu    PyObject *result;
27110451Snilay@cs.wisc.edu    const char **command = m5MainCommands;
27210451Snilay@cs.wisc.edu
27310451Snilay@cs.wisc.edu    // evaluate each command in the m5MainCommands array (basically a
27410451Snilay@cs.wisc.edu    // bunch of python statements.
2757860SN/A    while (*command) {
2767860SN/A        result = PyRun_String(*command, Py_file_input, dict, dict);
2777860SN/A        if (!result) {
27810451Snilay@cs.wisc.edu            PyErr_Print();
27910451Snilay@cs.wisc.edu            return 1;
2809988Snilay@cs.wisc.edu        }
28110451Snilay@cs.wisc.edu        Py_DECREF(result);
2827860SN/A
28310451Snilay@cs.wisc.edu        command++;
2847860SN/A    }
2859988Snilay@cs.wisc.edu
2867860SN/A#if HAVE_PROTOBUF
28710451Snilay@cs.wisc.edu    google::protobuf::ShutdownProtobufLibrary();
2887860SN/A#endif
2897860SN/A
2907860SN/A    return 0;
2917860SN/A}
29210451Snilay@cs.wisc.edu
29310451Snilay@cs.wisc.eduPyMODINIT_FUNC
2949988Snilay@cs.wisc.eduinitm5(void)
29510451Snilay@cs.wisc.edu{
2967860SN/A    initM5Python();
29710451Snilay@cs.wisc.edu    PyImport_ImportModule(PyCC("m5"));
2987860SN/A}
2999988Snilay@cs.wisc.edu