mirror of
https://github.com/YosysHQ/yosys.git
synced 2026-10-06 01:53:53 +02:00
425 lines
12 KiB
C++
425 lines
12 KiB
C++
/*
|
|
* yosys -- Yosys Open SYnthesis Suite
|
|
*
|
|
* Copyright (C) 2012 Claire Xenia Wolf <[email protected]>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
// <!-- generated includes -->
|
|
#include <pybind11/pybind11.h>
|
|
#include <pybind11/native_enum.h>
|
|
#include <pybind11/functional.h>
|
|
|
|
// duplicates for LSPs
|
|
#include "kernel/register.h"
|
|
#include "kernel/yosys_common.h"
|
|
|
|
#include "pyosys/hashlib.h"
|
|
|
|
namespace py = pybind11;
|
|
|
|
USING_YOSYS_NAMESPACE
|
|
|
|
using std::set;
|
|
using std::function;
|
|
using std::ostream;
|
|
using namespace RTLIL;
|
|
|
|
#include "wrappers.inc.cc"
|
|
|
|
namespace pyosys {
|
|
struct Globals {};
|
|
|
|
static bool name_renderable(const RTLIL::PooledName &n)
|
|
{
|
|
return n.pool() != nullptr || n.ref().empty() || ID::is_static(n.ref());
|
|
}
|
|
|
|
static std::string name_str(const RTLIL::PooledName &n)
|
|
{
|
|
if (!name_renderable(n))
|
|
throw std::runtime_error(
|
|
"this name has no twine pool to resolve against; render it with Design.str(name)");
|
|
return n.str();
|
|
}
|
|
|
|
static std::string name_repr(const RTLIL::PooledName &n)
|
|
{
|
|
if (n.ref().empty())
|
|
return "<IdString Null>";
|
|
if (!name_renderable(n))
|
|
return stringf("<IdString #%zu%s>", n.ref().untag().raw(), n.ref().isPublic() ? " public" : "");
|
|
return stringf("<IdString %s>", n.str().c_str());
|
|
}
|
|
|
|
static size_t name_hash(const RTLIL::PooledName &n) { return run_hash(name_str(n)); }
|
|
|
|
static bool name_eq(const RTLIL::PooledName &lhs, const RTLIL::PooledName &rhs)
|
|
{
|
|
return name_str(lhs) == name_str(rhs);
|
|
}
|
|
|
|
static bool name_eq_str(const RTLIL::PooledName &lhs, const std::string &rhs)
|
|
{
|
|
return name_str(lhs) == rhs;
|
|
}
|
|
|
|
static bool name_ne(const RTLIL::PooledName &lhs, const RTLIL::PooledName &rhs) { return !name_eq(lhs, rhs); }
|
|
static bool name_ne_str(const RTLIL::PooledName &lhs, const std::string &rhs) { return !name_eq_str(lhs, rhs); }
|
|
static bool name_lt(const RTLIL::PooledName &lhs, const RTLIL::PooledName &rhs)
|
|
{
|
|
return name_str(lhs) < name_str(rhs);
|
|
}
|
|
static const TwinePool *pool_of(const RTLIL::Design &design) { return &design.twines; }
|
|
static const TwinePool *pool_of(const RTLIL::Module &module)
|
|
{
|
|
return module.design ? &module.design->twines : nullptr;
|
|
}
|
|
|
|
template<typename Owner, typename Map>
|
|
static py::dict name_keyed_snapshot(Owner &self, const Map &map)
|
|
{
|
|
const TwinePool *pool = pool_of(self);
|
|
py::dict out;
|
|
for (const auto &entry : map)
|
|
out[py::cast(RTLIL::PooledName(pool, entry.first))] =
|
|
py::cast(entry.second, py::return_value_policy::reference);
|
|
return out;
|
|
}
|
|
|
|
static py::dict design_modules(RTLIL::Design &self) { return name_keyed_snapshot(self, self.modules_); }
|
|
static py::dict module_wires(RTLIL::Module &self) { return name_keyed_snapshot(self, self.wires_); }
|
|
static py::dict module_cells(RTLIL::Module &self) { return name_keyed_snapshot(self, self.cells_); }
|
|
|
|
static RTLIL::PooledName design_id_add(RTLIL::Design &self, const std::string &name)
|
|
{
|
|
return RTLIL::PooledName(&self.twines, self.twines.add(name));
|
|
}
|
|
|
|
static py::object design_id_find(RTLIL::Design &self, const std::string &name)
|
|
{
|
|
RTLIL::IdString ref = self.twines.find(name);
|
|
if (ref.empty())
|
|
return py::none();
|
|
return py::cast(RTLIL::PooledName(&self.twines, ref));
|
|
}
|
|
|
|
static std::string design_str(RTLIL::Design &self, const RTLIL::PooledName &name)
|
|
{
|
|
if (name_renderable(name))
|
|
return name.str();
|
|
return self.twines.str(name.ref());
|
|
}
|
|
|
|
static py::list module_ports(RTLIL::Module &self)
|
|
{
|
|
const TwinePool *pool = pool_of(self);
|
|
py::list out;
|
|
for (RTLIL::IdString port : self.ports)
|
|
out.append(py::cast(RTLIL::PooledName(pool, port)));
|
|
return out;
|
|
}
|
|
|
|
static bool lookup_constid(const std::string &text, RTLIL::IdString &out)
|
|
{
|
|
try {
|
|
out = ID::lookup(text);
|
|
return true;
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace pybind11 {
|
|
namespace detail {
|
|
|
|
template <> struct type_caster<Yosys::RTLIL::IdString> {
|
|
public:
|
|
PYBIND11_TYPE_CASTER(Yosys::RTLIL::IdString, const_name("IdString"));
|
|
|
|
bool load(handle src, bool)
|
|
{
|
|
if (!src)
|
|
return false;
|
|
if (isinstance<Yosys::RTLIL::PooledName>(src)) {
|
|
value = src.cast<const Yosys::RTLIL::PooledName &>().ref();
|
|
return true;
|
|
}
|
|
if (PyUnicode_Check(src.ptr()))
|
|
return pyosys::lookup_constid(src.cast<std::string>(), value);
|
|
return false;
|
|
}
|
|
|
|
static handle cast(Yosys::RTLIL::IdString src, return_value_policy, handle)
|
|
{
|
|
return pybind11::cast(Yosys::RTLIL::PooledName(src)).release();
|
|
}
|
|
};
|
|
|
|
template <typename Masq> struct masq_caster {
|
|
static constexpr auto name = const_name("IdString");
|
|
|
|
static handle cast(const Masq &src, return_value_policy, handle)
|
|
{
|
|
return pybind11::cast(Yosys::RTLIL::PooledName(src)).release();
|
|
}
|
|
};
|
|
|
|
template <typename Owner, auto Field>
|
|
struct type_caster<Yosys::RTLIL::IdFieldMasq<Owner, Field>> : masq_caster<Yosys::RTLIL::IdFieldMasq<Owner, Field>> {};
|
|
|
|
}
|
|
}
|
|
|
|
namespace pyosys {
|
|
|
|
// 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,
|
|
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
|
|
);
|
|
}
|
|
};
|
|
|
|
PYBIND11_MODULE(libyosys, m) {
|
|
// this code is run on import
|
|
m.doc() = "python access to libyosys";
|
|
|
|
if (!yosys_already_setup()) {
|
|
logger().add_sink<ConsoleLogSink>();
|
|
yosys_setup();
|
|
|
|
// Cleanup
|
|
m.add_object("_cleanup_handle", py::capsule([](){
|
|
yosys_shutdown();
|
|
}));
|
|
}
|
|
|
|
// Logging Methods
|
|
m.def("log_header", [](Design *d, std::string s) { logger().formatted_header(d, "%s", s); });
|
|
m.def("log", [](std::string s) { logger().formatted_string(LogSeverity::Info, LogSourceLocation{}, {}, "%s", s); });
|
|
m.def("log_file_info", [](std::string file, int line, std::string s) { logger().formatted_string(LogSeverity::Info, LogSourceLocation(file,line), "Info: ", "%s", s); });
|
|
m.def("log_warning", [](std::string s) { logger().formatted_warning(LogSourceLocation{}, "Warning: ", "%s", s); });
|
|
m.def("log_warning_noprefix", [](std::string s) { logger().formatted_warning(LogSourceLocation{}, "", "%s", s); });
|
|
m.def("log_file_warning", [](std::string file, int line, std::string s) { logger().formatted_warning(LogSourceLocation(file,line), "Warning: ", "%s", s); });
|
|
m.def("log_error", [](std::string s) { logger().formatted_error(LogSourceLocation{}, "ERROR: ", "%s", s); });
|
|
m.def("log_file_error", [](std::string file, int line, std::string s) { logger().formatted_error(LogSourceLocation(file,line), "ERROR: ", "%s", s); });
|
|
|
|
// Namespace to host global objects
|
|
auto global_variables = py::class_<Globals>(m, "Globals");
|
|
|
|
// Trampoline Classes
|
|
py::class_<Pass, pyosys::PassTrampoline, std::unique_ptr<Pass, py::nodelete>>(m, "Pass")
|
|
.def(py::init([](std::string name, std::string short_help) {
|
|
auto created = new pyosys::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, pyosys::MonitorTrampoline>(m, "Monitor")
|
|
.def(py::init([]() {
|
|
return new pyosys::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 *,
|
|
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)
|
|
;
|
|
|
|
py::class_<RTLIL::PooledName>(m, "IdString")
|
|
.def("str", &name_str)
|
|
.def("empty", &RTLIL::PooledName::empty)
|
|
.def("isPublic", &RTLIL::PooledName::isPublic)
|
|
.def("__str__", &name_str)
|
|
.def("__repr__", &name_repr)
|
|
.def("__hash__", &name_hash)
|
|
.def("__eq__", &name_eq)
|
|
.def("__eq__", &name_eq_str)
|
|
.def("__ne__", &name_ne)
|
|
.def("__ne__", &name_ne_str)
|
|
.def("__lt__", &name_lt)
|
|
;
|
|
|
|
// Bind Opaque Containers
|
|
bind_autogenerated_opaque_containers(m);
|
|
|
|
// <!-- generated pymod-level code -->
|
|
|
|
py::reinterpret_borrow<py::class_<RTLIL::Design>>(m.attr("Design"))
|
|
.def_property_readonly("modules_", &design_modules)
|
|
.def("id_add", &design_id_add, py::arg("name"))
|
|
.def("id_find", &design_id_find, py::arg("name"))
|
|
.def("str", &design_str, py::arg("name"));
|
|
py::reinterpret_borrow<py::class_<RTLIL::Module>>(m.attr("Module"))
|
|
.def_property_readonly("wires_", &module_wires)
|
|
.def_property_readonly("cells_", &module_cells)
|
|
.def_property_readonly("ports", &module_ports);
|
|
|
|
};
|
|
};
|