mirror of
https://github.com/YosysHQ/yosys
synced 2025-10-09 09:21:58 +00:00
pyosys: rewrite using pybind11
- Rewrite all Python features to use the pybind11 library instead of boost::python. Unlike boost::python, pybind11 is a header-only library that is just included by Pyosys code, saving a lot of compile time on wheels. - Factor out as much "translation" code from the generator into proper C++ files - Fix running the embedded interpreter not supporting "from pyosys import libyosys as ys" like wheels - Move Python-related elements to `pyosys` directory at the root of the repo - Slight shift in bridging semantics: - Containers are declared as "opaque types" and are passed by reference to Python - many methods have been implemented to make them feel right at home without the overhead/ambiguity of copying to Python and then copying back after mutation - Monitor/Pass use "trampoline" pattern to support virual methods overridable in Python: virtual methods no longer require `py_` prefix - Create really short test set for pyosys that just exercises basic functionality
This commit is contained in:
parent
f7120e9c2a
commit
88be728353
27 changed files with 2879 additions and 2674 deletions
1
pyosys/.gitignore
vendored
Normal file
1
pyosys/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
wrappers.cc
|
20
pyosys/__init__.py
Normal file
20
pyosys/__init__.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
|
||||
|
||||
__dir__ = os.path.abspath(os.path.dirname(__file__))
|
||||
sys._pyosys_dir = os.path.abspath(__dir__)
|
||||
|
||||
bin_ext = ".exe" if os.name == "nt" else ""
|
||||
|
||||
_share_candidate = os.path.join(__dir__, "share")
|
||||
if os.path.isdir(_share_candidate):
|
||||
sys._pyosys_share_dirname = _share_candidate + os.path.sep
|
||||
|
||||
_abc_candidate = os.path.join(__dir__, f"yosys-abc{bin_ext}")
|
||||
if os.path.isfile(_abc_candidate):
|
||||
sys._pyosys_abc = _abc_candidate
|
||||
|
||||
__all__ = ["libyosys"]
|
2039
pyosys/generator.py
Normal file
2039
pyosys/generator.py
Normal file
File diff suppressed because it is too large
Load diff
275
pyosys/hashlib.h
Normal file
275
pyosys/hashlib.h
Normal file
|
@ -0,0 +1,275 @@
|
|||
// -------------------------------------------------------
|
||||
// Written by Mohamed Gaber in 2025 <me@donn.website>
|
||||
// Based on kernel/hashlib.h by Claire Xenia Wolf <claire@yosyshq.com>
|
||||
// -------------------------------------------------------
|
||||
// This header is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <https://unlicense.org/>
|
||||
// -------------------------------------------------------
|
||||
//
|
||||
// pybind11 bridging headers for hashlib template
|
||||
//
|
||||
// These are various binding functions that expose hashlib templates as opaque
|
||||
// types (https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html#making-opaque-types).
|
||||
//
|
||||
// Opaque types cross language barries by reference, not value. This allows
|
||||
// things like mutating containers that are class properties.
|
||||
//
|
||||
// All methods should be vaguely in the same order as the python reference
|
||||
// https://docs.python.org/3/library/stdtypes.html
|
||||
//
|
||||
#include <optional> // optional maps cleanest to methods that accept None in Python
|
||||
|
||||
#include <pybind11/pybind11.h> // base
|
||||
#include <pybind11/stl.h> // std::optional
|
||||
#include <pybind11/operators.h> // easier operator binding
|
||||
|
||||
#include "kernel/hashlib.h"
|
||||
|
||||
namespace pybind11 {
|
||||
|
||||
template<typename T>
|
||||
struct is_pointer { static const bool value = false; };
|
||||
template<typename T>
|
||||
struct is_pointer<T*> { static const bool value = true; };
|
||||
|
||||
bool is_mapping(object obj) {
|
||||
object mapping = module_::import("collections.abc").attr("Mapping");
|
||||
return isinstance(obj, mapping);
|
||||
}
|
||||
|
||||
|
||||
// also used for std::set because the semantics are close enough
|
||||
template <typename C, typename T>
|
||||
void bind_pool(module &m, const char *name_cstr) {
|
||||
std::string {name_cstr};
|
||||
|
||||
class_<C>(m, name_cstr)
|
||||
.def(init<>())
|
||||
.def("__len__", [](const C &s){ return (size_t)s.size(); })
|
||||
.def("__contains__", [](const C &s, const T &v){ return s.count(v); })
|
||||
.def("__delitem__", [](C &s, const T &v) {
|
||||
auto n = s.erase(v);
|
||||
if (n == 0) throw key_error(str(cast(v)));
|
||||
})
|
||||
// TODO: disjoint, subset, union, intersection, difference, symdif
|
||||
.def("copy", [](const C &s) {
|
||||
return new C(s);
|
||||
})
|
||||
.def("update", [](C &s, iterable iterable) {
|
||||
for (auto item: iterable) {
|
||||
s.insert(item.cast<T>());
|
||||
}
|
||||
})
|
||||
.def("add", [](C &s, const T &v){ s.insert(v); })
|
||||
.def("remove", [](C &s, const T &v){
|
||||
auto n = s.erase(v);
|
||||
if (n == 0) throw key_error(str(cast(v)));
|
||||
})
|
||||
.def("discard", [](C &s, const T &v){ s.erase(v); })
|
||||
.def("clear", [](C &s){ s.clear(); })
|
||||
.def("pop", [](C &s){
|
||||
if (s.size() == 0) {
|
||||
throw key_error("empty pool");
|
||||
}
|
||||
auto result = *s.begin();
|
||||
s.erase(result);
|
||||
return result;
|
||||
})
|
||||
.def("__bool__", [](const C &s) { return s.size() != 0; })
|
||||
.def("__iter__", [](const C &s){
|
||||
return make_iterator(s.begin(), s.end());
|
||||
}, keep_alive<0,1>())
|
||||
.def("__repr__", [name_cstr](const C &s){
|
||||
return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">";
|
||||
});
|
||||
}
|
||||
|
||||
template <typename C, typename K, typename V>
|
||||
void update_dict(C *target, iterable &iterable_or_mapping) {
|
||||
if (is_mapping(iterable_or_mapping)) {
|
||||
for (const auto &key: iterable_or_mapping) {
|
||||
(*target)[cast<K>(key)] = cast<V>(iterable_or_mapping[key]);
|
||||
}
|
||||
} else {
|
||||
for (const auto &pair: iterable_or_mapping) {
|
||||
if (len(pair) != 2) {
|
||||
throw value_error(str("iterable element %s has more than two elements").format(str(pair)));
|
||||
}
|
||||
(*target)[cast<K>(pair[cast(0)])] = cast<V>(pair[cast(1)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename C, typename K, typename V>
|
||||
void bind_dict(module &m, const char *name_cstr) {
|
||||
std::string {name_cstr};
|
||||
|
||||
class_<C>(m, name_cstr)
|
||||
.def(init<>())
|
||||
.def("__len__", [](const C &s){ return (size_t)s.size(); })
|
||||
.def("__getitem__", [](const C &s, const K &k) { return s.at(k); })
|
||||
.def("__setitem__", [](C &s, const K &k, const V &v) { s[k] = v; })
|
||||
.def("__delitem__", [](C &s, const K &k) {
|
||||
auto n = s.erase(k);
|
||||
if (n == 0) throw key_error("remove: key not found");
|
||||
})
|
||||
.def("__contains__", [](const C &s, const K &k) { return s.count(k) != 0; })
|
||||
.def("__iter__", [](const C &s){
|
||||
return make_key_iterator(s.begin(), s.end());
|
||||
}, keep_alive<0,1>())
|
||||
.def("clear", [](C &s){ s.clear(); })
|
||||
.def("copy", [](const C &s) {
|
||||
return new C(s);
|
||||
})
|
||||
.def("get", [](const C &s, const K& k, std::optional<const V> &default_) {
|
||||
if (default_.has_value()) {
|
||||
return s.at(k, *default_);
|
||||
} else {
|
||||
return s.at(k);
|
||||
}
|
||||
}, arg("key"), arg("default") = std::nullopt)
|
||||
.def("items", [](const C &s){
|
||||
return make_iterator(s.begin(), s.end());
|
||||
}, keep_alive<0,1>())
|
||||
.def("keys", [](const C &s){
|
||||
return make_key_iterator(s.begin(), s.end());
|
||||
}, keep_alive<0,1>())
|
||||
.def("pop", [](const C &s, const K& k, std::optional<const V> &default_) {
|
||||
if (default_.has_value()) {
|
||||
return s.at(k, *default_);
|
||||
} else {
|
||||
return s.at(k);
|
||||
}
|
||||
}, arg("key"), arg("default") = std::nullopt)
|
||||
.def("popitem", [name_cstr](args _) { throw std::runtime_error(std::string(name_cstr) + " is not an ordered dictionary"); })
|
||||
.def("setdefault", [name_cstr](C &s, const K& k, std::optional<const V> &default_) {
|
||||
auto it = s.find(k);
|
||||
if (it != s.end()) {
|
||||
return it->second;
|
||||
}
|
||||
if (default_.has_value()) {
|
||||
s[k] = *default_;
|
||||
return *default_;
|
||||
}
|
||||
// if pointer, nullptr can be our default
|
||||
if constexpr (is_pointer<V>::value) {
|
||||
s[k] = nullptr;
|
||||
return (V)nullptr;
|
||||
}
|
||||
// TODO: std::optional? do we care?
|
||||
throw type_error(std::string("the value type of ") + name_cstr + " is not nullable");
|
||||
}, arg("key"), arg("default") = std::nullopt)
|
||||
.def("update", [](C &s, iterable iterable_or_mapping) {
|
||||
update_dict<C, K, V>(&s, iterable_or_mapping);
|
||||
}, arg("iterable_or_mapping"))
|
||||
.def("values", [](const C &s){
|
||||
return make_value_iterator(s.begin(), s.end());
|
||||
}, keep_alive<0,1>())
|
||||
.def("__or__", [](const C &s, iterable iterable_or_mapping) {
|
||||
auto result = new C(s);
|
||||
update_dict<C, K, V>(result, iterable_or_mapping);
|
||||
return result;
|
||||
})
|
||||
.def("__ior__", [](C &s, iterable iterable_or_mapping) {
|
||||
update_dict<C, K, V>(&s, iterable_or_mapping);
|
||||
return s;
|
||||
})
|
||||
.def("__bool__", [](const C &s) { return s.size() != 0; })
|
||||
.def("__repr__", [name_cstr](const C &s){
|
||||
return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">";
|
||||
});
|
||||
}
|
||||
|
||||
// idict is a special bijection and doesn't map cleanly to dict
|
||||
//
|
||||
// it's cleanest, despite the inconsistency with __getitem__, to just think of
|
||||
// the hashable as key and the integer as value
|
||||
template <typename C, typename K>
|
||||
void bind_idict(module &m, const char *name_cstr) {
|
||||
std::string {name_cstr};
|
||||
|
||||
auto cls = class_<C>(m, name_cstr)
|
||||
.def(init<>())
|
||||
.def("__len__", [](const C &s){ return (size_t)s.size(); })
|
||||
.def("__getitem__", [](const C &s, int v) { return s[v]; })
|
||||
.def("__call__", [](C &s, const K &k) { return s(k); })
|
||||
.def("__contains__", [](const C &s, const K &k) {
|
||||
return s.count(k) != 0;
|
||||
})
|
||||
.def("__iter__", [](const C &s){
|
||||
return make_iterator(s.begin(), s.end());
|
||||
}, keep_alive<0,1>())
|
||||
.def("clear", [](C &s) {
|
||||
s.clear();
|
||||
})
|
||||
.def("copy", [](const C &s) {
|
||||
return new C(s);
|
||||
})
|
||||
.def("get", [](const C &s, const K& k, std::optional<int> &default_) {
|
||||
if (default_.has_value()) {
|
||||
return s.at(k, *default_);
|
||||
} else {
|
||||
return s.at(k);
|
||||
}
|
||||
}, arg("key"), arg("default") = std::nullopt)
|
||||
.def("keys", [](const C &s){
|
||||
return make_iterator(s.begin(), s.end());
|
||||
})
|
||||
.def("values", [](args _){
|
||||
throw type_error("idicts do not support iteration on the integers");
|
||||
})
|
||||
.def("items", [](args _){
|
||||
throw type_error("idicts do not support pairwise iteration");
|
||||
})
|
||||
.def("update", [](C &s, iterable iterable) {
|
||||
for (auto &e: iterable) {
|
||||
s(cast<K>(e));
|
||||
}
|
||||
})
|
||||
.def("__or__", [](const C &s, iterable iterable) {
|
||||
auto result = new C(s);
|
||||
for (auto &e: iterable) {
|
||||
(*result)(cast<K>(e));
|
||||
}
|
||||
return result;
|
||||
})
|
||||
.def("__ior__", [](C &s, iterable iterable) {
|
||||
for (auto &e: iterable) {
|
||||
s(cast<K>(e));
|
||||
}
|
||||
return s;
|
||||
})
|
||||
.def("__bool__", [](const C &s) { return s.size() != 0; })
|
||||
.def("__repr__", [name_cstr](const C &s){
|
||||
return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">";
|
||||
});
|
||||
|
||||
for (const char *mutator: {"__setitem__", "__delitem__", "pop", "popitem", "setdefault"}) {
|
||||
cls.def(mutator, [](args _) {
|
||||
throw type_error("idicts do not support arbitrary element mutation");
|
||||
});
|
||||
}
|
||||
}
|
||||
}; // namespace pybind11
|
248
pyosys/wrappers_tpl.cc
Normal file
248
pyosys/wrappers_tpl.cc
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
|
||||
// <!-- generated includes -->
|
||||
|
||||
#include <pybind11/stl_bind.h>
|
||||
#include <pybind11/native_enum.h>
|
||||
#include "pyosys/hashlib.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
// <!-- generated top-level code -->
|
||||
|
||||
namespace YOSYS_PYTHON {
|
||||
|
||||
[[noreturn]] static void log_python_exception_as_error() {
|
||||
PyErr_Print();
|
||||
log_error("Python interpreter encountered an exception.\\n");
|
||||
}
|
||||
|
||||
struct YosysStatics{};
|
||||
|
||||
// <!-- generated YOSYS_PYTHON namespace-level code -->
|
||||
|
||||
// Trampolines for Classes with Python-Overridable Virtual Methods
|
||||
// https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python
|
||||
class PassTrampoline : public Pass {
|
||||
public:
|
||||
using Pass::Pass;
|
||||
|
||||
void help() override {
|
||||
PYBIND11_OVERRIDE(void, Pass, help);
|
||||
}
|
||||
|
||||
bool formatted_help() override {
|
||||
PYBIND11_OVERRIDE(bool, Pass, formatted_help);
|
||||
}
|
||||
|
||||
void clear_flags() override {
|
||||
PYBIND11_OVERRIDE(void, Pass, clear_flags);
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override {
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
void,
|
||||
Pass,
|
||||
execute,
|
||||
args,
|
||||
design
|
||||
);
|
||||
}
|
||||
|
||||
void on_register() override {
|
||||
PYBIND11_OVERRIDE(void, Pass, on_register);
|
||||
}
|
||||
|
||||
void on_shutdown() override {
|
||||
PYBIND11_OVERRIDE(void, Pass, on_shutdown);
|
||||
}
|
||||
|
||||
bool replace_existing_pass() const override {
|
||||
PYBIND11_OVERRIDE(
|
||||
bool,
|
||||
Pass,
|
||||
replace_existing_pass
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class MonitorTrampoline : public RTLIL::Monitor {
|
||||
public:
|
||||
using RTLIL::Monitor::Monitor;
|
||||
|
||||
void notify_module_add(RTLIL::Module *module) override {
|
||||
PYBIND11_OVERRIDE(
|
||||
void,
|
||||
RTLIL::Monitor,
|
||||
notify_module_add,
|
||||
module
|
||||
);
|
||||
}
|
||||
|
||||
void notify_module_del(RTLIL::Module *module) override {
|
||||
PYBIND11_OVERRIDE(
|
||||
void,
|
||||
RTLIL::Monitor,
|
||||
notify_module_del,
|
||||
module
|
||||
);
|
||||
}
|
||||
|
||||
void notify_connect(
|
||||
RTLIL::Cell *cell,
|
||||
const RTLIL::IdString &port,
|
||||
const RTLIL::SigSpec &old_sig,
|
||||
const RTLIL::SigSpec &sig
|
||||
) override {
|
||||
PYBIND11_OVERRIDE(
|
||||
void,
|
||||
RTLIL::Monitor,
|
||||
notify_connect,
|
||||
cell,
|
||||
port,
|
||||
old_sig,
|
||||
sig
|
||||
);
|
||||
}
|
||||
|
||||
void notify_connect(
|
||||
RTLIL::Module *module,
|
||||
const RTLIL::SigSig &sigsig
|
||||
) override {
|
||||
PYBIND11_OVERRIDE(
|
||||
void,
|
||||
RTLIL::Monitor,
|
||||
notify_connect,
|
||||
module,
|
||||
sigsig
|
||||
);
|
||||
}
|
||||
|
||||
void notify_connect(
|
||||
RTLIL::Module *module,
|
||||
const std::vector<RTLIL::SigSig> &sigsig_vec
|
||||
) override {
|
||||
PYBIND11_OVERRIDE(
|
||||
void,
|
||||
RTLIL::Monitor,
|
||||
notify_connect,
|
||||
module,
|
||||
sigsig_vec
|
||||
);
|
||||
}
|
||||
|
||||
void notify_blackout(
|
||||
RTLIL::Module *module
|
||||
) override {
|
||||
PYBIND11_OVERRIDE(
|
||||
void,
|
||||
RTLIL::Monitor,
|
||||
notify_blackout,
|
||||
module
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Use an auxiliary function to adapt the legacy function.
|
||||
void log_to_stream(py::object object)
|
||||
{
|
||||
// TODO
|
||||
};
|
||||
|
||||
PYBIND11_MODULE(libyosys, m) {
|
||||
// this code is run on import
|
||||
m.doc() = "python access to libyosys";
|
||||
|
||||
if (!yosys_already_setup()) {
|
||||
log_streams.push_back(&std::cout);
|
||||
log_error_stderr = true;
|
||||
yosys_setup();
|
||||
|
||||
// Cleanup
|
||||
m.add_object("_cleanup_handle", py::capsule([](){
|
||||
yosys_shutdown();
|
||||
}));
|
||||
}
|
||||
|
||||
m.def("log_to_stream", &log_to_stream, "pipes yosys logs to a Python stream");
|
||||
|
||||
// Trampoline Classes
|
||||
py::class_<Pass, YOSYS_PYTHON::PassTrampoline, std::unique_ptr<Pass, py::nodelete>>(m, "Pass")
|
||||
.def(py::init([](std::string name, std::string short_help) {
|
||||
auto created = new YOSYS_PYTHON::PassTrampoline(name, short_help);
|
||||
Pass::init_register();
|
||||
return created;
|
||||
}), py::arg("name"), py::arg("short_help"))
|
||||
.def("help", &Pass::help)
|
||||
.def("formatted_help", &Pass::formatted_help)
|
||||
.def("execute", &Pass::execute)
|
||||
.def("clear_flags", &Pass::clear_flags)
|
||||
.def("on_register", &Pass::on_register)
|
||||
.def("on_shutdown", &Pass::on_shutdown)
|
||||
.def("replace_existing_pass", &Pass::replace_existing_pass)
|
||||
.def("experimental", &Pass::experimental)
|
||||
.def("internal", &Pass::internal)
|
||||
.def("pre_execute", &Pass::pre_execute)
|
||||
.def("post_execute", &Pass::post_execute)
|
||||
.def("cmd_log_args", &Pass::cmd_log_args)
|
||||
.def("cmd_error", &Pass::cmd_error)
|
||||
.def("extra_args", &Pass::extra_args)
|
||||
.def("call", py::overload_cast<RTLIL::Design *,std::string>(&Pass::call))
|
||||
.def("call", py::overload_cast<RTLIL::Design *,std::vector<std::string>>(&Pass::call))
|
||||
;
|
||||
|
||||
py::class_<RTLIL::Monitor, YOSYS_PYTHON::MonitorTrampoline>(m, "Monitor")
|
||||
.def(py::init([]() {
|
||||
return new YOSYS_PYTHON::MonitorTrampoline();
|
||||
}))
|
||||
.def("notify_module_add", &RTLIL::Monitor::notify_module_add)
|
||||
.def("notify_module_del", &RTLIL::Monitor::notify_module_del)
|
||||
.def(
|
||||
"notify_connect",
|
||||
py::overload_cast<
|
||||
RTLIL::Cell *,
|
||||
const RTLIL::IdString &,
|
||||
const RTLIL::SigSpec &,
|
||||
const RTLIL::SigSpec &
|
||||
>(&RTLIL::Monitor::notify_connect)
|
||||
)
|
||||
.def(
|
||||
"notify_connect",
|
||||
py::overload_cast<
|
||||
RTLIL::Module *,
|
||||
const RTLIL::SigSig &
|
||||
>(&RTLIL::Monitor::notify_connect)
|
||||
)
|
||||
.def(
|
||||
"notify_connect",
|
||||
py::overload_cast<
|
||||
RTLIL::Module *,
|
||||
const std::vector<RTLIL::SigSig> &
|
||||
>(&RTLIL::Monitor::notify_connect)
|
||||
)
|
||||
.def("notify_blackout", &RTLIL::Monitor::notify_blackout)
|
||||
;
|
||||
|
||||
// <!-- generated pymod-level code -->
|
||||
};
|
||||
};
|
||||
|
||||
#endif // WITH_PYTHON
|
Loading…
Add table
Add a link
Reference in a new issue