| /* |
| * Copyright (c) 2017 ARM Limited |
| * All rights reserved |
| * |
| * The license below extends only to copyright in the software and shall |
| * not be construed as granting a license to any other intellectual |
| * property including but not limited to intellectual property relating |
| * to a hardware implementation of the functionality of the software |
| * licensed hereunder. You may use the software subject to the license |
| * terms below provided that you ensure that this notice is replicated |
| * unmodified and in its entirety in all distributions of the software, |
| * modified or unmodified, in source code or in binary form. |
| * |
| * Copyright (c) 2006 The Regents of The University of Michigan |
| * Copyright (c) 2013 Advanced Micro Devices, Inc. |
| * Copyright (c) 2013 Mark D. Hill and David A. Wood |
| * All rights reserved. |
| * |
| * 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. |
| */ |
| |
| #include "pybind11/pybind11.h" |
| #include "pybind11/stl.h" |
| |
| #include "base/logging.hh" |
| #include "sim/eventq.hh" |
| #include "sim/sim_events.hh" |
| #include "sim/sim_exit.hh" |
| #include "sim/simulate.hh" |
| |
| namespace py = pybind11; |
| |
| |
| /** |
| * PyBind wrapper for Events |
| * |
| * We need to wrap the Event class with some Python glue code to |
| * enable method overrides in Python and memory management. Unlike its |
| * C++ cousin, PyEvents need to override __call__ instead of |
| * Event::process(). |
| * |
| * Memory management is done using reference counting in Python. |
| */ |
| class PyEvent : public Event |
| { |
| public: |
| PyEvent(Event::Priority priority) |
| : Event(priority, Event::Managed) |
| { |
| } |
| |
| void process() override { |
| // Call the Python implementation as __call__. This provides a |
| // slightly more Python-friendly interface. |
| PYBIND11_OVERLOAD_PURE_NAME(void, PyEvent, "__call__", process); |
| } |
| |
| protected: |
| void acquireImpl() override { |
| py::object obj = py::cast(this); |
| |
| if (obj) { |
| obj.inc_ref(); |
| } else { |
| panic("Failed to get PyBind object to increase ref count\n"); |
| } |
| } |
| |
| void releaseImpl() override { |
| py::object obj = py::cast(this); |
| |
| if (obj) { |
| obj.dec_ref(); |
| } else { |
| panic("Failed to get PyBind object to decrease ref count\n"); |
| } |
| } |
| }; |
| |
| void |
| pybind_init_event(py::module &m_native) |
| { |
| py::module m = m_native.def_submodule("event"); |
| |
| m.def("simulate", &simulate, |
| py::arg("ticks") = MaxTick); |
| m.def("exitSimLoop", &exitSimLoop); |
| m.def("getEventQueue", []() { return curEventQueue(); }, |
| py::return_value_policy::reference); |
| m.def("setEventQueue", [](EventQueue *q) { return curEventQueue(q); }); |
| m.def("getEventQueue", &getEventQueue, |
| py::return_value_policy::reference); |
| |
| py::class_<EventQueue>(m, "EventQueue") |
| .def("name", [](EventQueue *eq) { return eq->name(); }) |
| .def("dump", &EventQueue::dump) |
| .def("schedule", [](EventQueue *eq, PyEvent *e, Tick t) { |
| eq->schedule(e, t); |
| }, py::arg("event"), py::arg("when")) |
| .def("deschedule", &EventQueue::deschedule, |
| py::arg("event")) |
| .def("reschedule", &EventQueue::reschedule, |
| py::arg("event"), py::arg("tick"), py::arg("always") = false) |
| ; |
| |
| // TODO: Ownership of global exit events has always been a bit |
| // questionable. We currently assume they are owned by the C++ |
| // world. This is what the old SWIG code did, but that will result |
| // in memory leaks. |
| py::class_<GlobalSimLoopExitEvent, |
| std::unique_ptr<GlobalSimLoopExitEvent, py::nodelete>>( |
| m, "GlobalSimLoopExitEvent") |
| .def("getCause", &GlobalSimLoopExitEvent::getCause) |
| #if PY_MAJOR_VERSION >= 3 |
| .def("getCode", &GlobalSimLoopExitEvent::getCode) |
| #else |
| // Workaround for an issue where PyBind11 converts the exit |
| // code to a long. This is normally fine, but sys.exit treats |
| // any non-int type as an error and exits with status 1 if it |
| // is passed a long. |
| .def("getCode", [](GlobalSimLoopExitEvent *e) { |
| return py::reinterpret_steal<py::object>( |
| PyInt_FromLong(e->getCode())); |
| }) |
| #endif |
| ; |
| |
| // Event base class. These should never be returned directly to |
| // Python since they don't have a well-defined life cycle. Python |
| // events should be derived from PyEvent instead. |
| py::class_<Event> c_event( |
| m, "Event"); |
| c_event |
| .def("name", &Event::name) |
| .def("dump", &Event::dump) |
| .def("scheduled", &Event::scheduled) |
| .def("squash", &Event::squash) |
| .def("squashed", &Event::squashed) |
| .def("isExitEvent", &Event::isExitEvent) |
| .def("when", &Event::when) |
| .def("priority", &Event::priority) |
| ; |
| |
| py::class_<PyEvent, Event>(m, "PyEvent") |
| .def(py::init<Event::Priority>(), |
| py::arg("priority") = (int)Event::Default_Pri) |
| ; |
| |
| #define PRIO(n) c_event.attr(# n) = py::cast((int)Event::n) |
| PRIO(Minimum_Pri); |
| PRIO(Minimum_Pri); |
| PRIO(Debug_Enable_Pri); |
| PRIO(Debug_Break_Pri); |
| PRIO(CPU_Switch_Pri); |
| PRIO(Delayed_Writeback_Pri); |
| PRIO(Default_Pri); |
| PRIO(DVFS_Update_Pri); |
| PRIO(Serialize_Pri); |
| PRIO(CPU_Tick_Pri); |
| PRIO(Stat_Event_Pri); |
| PRIO(Progress_Event_Pri); |
| PRIO(Sim_Exit_Pri); |
| PRIO(Maximum_Pri); |
| } |