Initial conversion to pybind11
This commit is contained in:
parent
444e535f00
commit
8f2b707d02
@ -45,17 +45,9 @@ if (STATIC_BUILD)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/MT")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "/MTd")
|
||||
endif()
|
||||
if (BUILD_PYTHON)
|
||||
add_definitions(-DBOOST_PYTHON_STATIC_LIB)
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")
|
||||
set(link_param "-static")
|
||||
if (BUILD_PYTHON)
|
||||
find_package(ZLIB)
|
||||
find_package(EXPAT)
|
||||
find_package(Threads)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -173,54 +165,7 @@ configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/common/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated/version.h
|
||||
)
|
||||
|
||||
if (BUILD_PYTHON)
|
||||
# Find Boost::Python of a suitable version in a cross-platform way
|
||||
# Some distributions (Arch) call it libboost_python3, others such as Ubuntu
|
||||
# call it libboost_python35. In the latter case we must consider all minor versions
|
||||
# Original source: https://github.com/BVLC/caffe/blob/master/cmake/Dependencies.cmake#L148
|
||||
set(version ${PYTHONLIBS_VERSION_STRING})
|
||||
|
||||
STRING(REGEX REPLACE "[^0-9]" "" boost_py_version "${version}")
|
||||
find_package(Boost QUIET COMPONENTS "python-py${boost_py_version}" ${boost_libs})
|
||||
set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND})
|
||||
|
||||
while (NOT "${version}" STREQUAL "" AND NOT Boost_PYTHON_FOUND)
|
||||
STRING(REGEX REPLACE "([0-9.]+).[0-9]+" "\\1" version "${version}")
|
||||
|
||||
STRING(REGEX REPLACE "[^0-9]" "" boost_py_version "${version}")
|
||||
find_package(Boost QUIET COMPONENTS "python-py${boost_py_version}" ${boost_libs})
|
||||
set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND})
|
||||
|
||||
STRING(REGEX MATCHALL "([0-9.]+).[0-9]+" has_more_version "${version}")
|
||||
if ("${has_more_version}" STREQUAL "")
|
||||
break()
|
||||
endif ()
|
||||
endwhile ()
|
||||
|
||||
if (NOT Boost_PYTHON_FOUND)
|
||||
foreach (PyVer 3 36 37 38 39)
|
||||
find_package(Boost QUIET COMPONENTS python${PyVer} ${boost_libs})
|
||||
if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" )
|
||||
set(Boost_PYTHON_FOUND TRUE)
|
||||
break()
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
if (NOT Boost_PYTHON_FOUND)
|
||||
STRING(REGEX REPLACE "([0-9]+\\.[0-9]+).*" "\\1" gentoo_version "${PYTHONLIBS_VERSION_STRING}")
|
||||
find_package(Boost QUIET COMPONENTS python-${gentoo_version} ${boost_libs})
|
||||
if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" )
|
||||
set(Boost_PYTHON_FOUND TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT Boost_PYTHON_FOUND )
|
||||
message( FATAL_ERROR "No version of Boost::Python 3.x could be found.")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
include_directories(common/ json/ frontend/ 3rdparty/json11/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
|
||||
include_directories(common/ json/ frontend/ 3rdparty/json11/ 3rdparty/pybind11/include ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
|
||||
|
||||
if(BUILD_HEAP)
|
||||
find_package (Eigen3 REQUIRED NO_MODULE)
|
||||
|
@ -1,10 +1,10 @@
|
||||
#ifndef NO_PYTHON
|
||||
|
||||
#include <Python.h>
|
||||
#include <boost/python.hpp>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include "nextpnr.h"
|
||||
|
||||
namespace py = boost::python;
|
||||
namespace py = pybind11;
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
@ -20,42 +20,36 @@ std::string parse_python_exception()
|
||||
std::string ret("Unfetchable Python error");
|
||||
// If the fetch got a type pointer, parse the type into the exception string
|
||||
if (type_ptr != NULL) {
|
||||
py::handle<> h_type(type_ptr);
|
||||
py::str type_pstr(h_type);
|
||||
// Extract the string from the boost::python object
|
||||
py::extract<std::string> e_type_pstr(type_pstr);
|
||||
py::object obj = py::reinterpret_borrow<py::object>(type_ptr);
|
||||
// If a valid string extraction is available, use it
|
||||
// otherwise use fallback
|
||||
if (e_type_pstr.check())
|
||||
ret = e_type_pstr();
|
||||
if (py::isinstance<py::str>(obj))
|
||||
ret = obj.cast<std::string>();
|
||||
else
|
||||
ret = "Unknown exception type";
|
||||
}
|
||||
// Do the same for the exception value (the stringification of the
|
||||
// exception)
|
||||
if (value_ptr != NULL) {
|
||||
py::handle<> h_val(value_ptr);
|
||||
py::str a(h_val);
|
||||
py::extract<std::string> returned(a);
|
||||
if (returned.check())
|
||||
ret += ": " + returned();
|
||||
py::object obj = py::reinterpret_borrow<py::object>(value_ptr);
|
||||
if (py::isinstance<py::str>(obj))
|
||||
ret += ": " + obj.cast<std::string>();
|
||||
else
|
||||
ret += std::string(": Unparseable Python error: ");
|
||||
}
|
||||
// Parse lines from the traceback using the Python traceback module
|
||||
if (traceback_ptr != NULL) {
|
||||
py::handle<> h_tb(traceback_ptr);
|
||||
py::handle h_tb(traceback_ptr);
|
||||
// Load the traceback module and the format_tb function
|
||||
py::object tb(py::import("traceback"));
|
||||
py::object tb(py::module::import("traceback"));
|
||||
py::object fmt_tb(tb.attr("format_tb"));
|
||||
// Call format_tb to get a list of traceback strings
|
||||
py::object tb_list(fmt_tb(h_tb));
|
||||
// Join the traceback strings into a single string
|
||||
py::object tb_str(py::str("\n").join(tb_list));
|
||||
py::object tb_str(py::str("\n") + tb_list);
|
||||
// Extract the string, check the extraction, and fallback in necessary
|
||||
py::extract<std::string> returned(tb_str);
|
||||
if (returned.check())
|
||||
ret += ": " + returned();
|
||||
if (py::isinstance<py::str>(tb_str))
|
||||
ret += ": " + tb_str.cast<std::string>();
|
||||
else
|
||||
ret += std::string(": Unparseable Python traceback");
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
// Architecture-specific bindings should be created in the below function, which
|
||||
// must be implemented in all architectures
|
||||
void arch_wrap_python();
|
||||
void arch_wrap_python(py::module &m);
|
||||
|
||||
bool operator==(const PortRef &a, const PortRef &b) { return (a.cell == b.cell) && (a.port == b.port); }
|
||||
|
||||
@ -90,13 +90,13 @@ template <> struct string_converter<Property>
|
||||
|
||||
} // namespace PythonConversion
|
||||
|
||||
BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
PYBIND11_MODULE(MODULE_NAME, m)
|
||||
{
|
||||
register_exception_translator<assertion_failure>(&translate_assertfail);
|
||||
//register_exception_translator<assertion_failure>(&translate_assertfail);
|
||||
|
||||
using namespace PythonConversion;
|
||||
|
||||
enum_<GraphicElement::type_t>("GraphicElementType")
|
||||
py::enum_<GraphicElement::type_t>(m, "GraphicElementType")
|
||||
.value("TYPE_NONE", GraphicElement::TYPE_NONE)
|
||||
.value("TYPE_LINE", GraphicElement::TYPE_LINE)
|
||||
.value("TYPE_ARROW", GraphicElement::TYPE_ARROW)
|
||||
@ -105,7 +105,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
.value("TYPE_LABEL", GraphicElement::TYPE_LABEL)
|
||||
.export_values();
|
||||
|
||||
enum_<GraphicElement::style_t>("GraphicElementStyle")
|
||||
py::enum_<GraphicElement::style_t>(m, "GraphicElementStyle")
|
||||
.value("STYLE_GRID", GraphicElement::STYLE_GRID)
|
||||
.value("STYLE_FRAME", GraphicElement::STYLE_FRAME)
|
||||
.value("STYLE_HIDDEN", GraphicElement::STYLE_HIDDEN)
|
||||
@ -113,9 +113,11 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
.value("STYLE_ACTIVE", GraphicElement::STYLE_ACTIVE)
|
||||
.export_values();
|
||||
|
||||
class_<GraphicElement>("GraphicElement")
|
||||
.def(init<GraphicElement::type_t, GraphicElement::style_t, float, float, float, float, float>(
|
||||
(args("type"), "style", "x1", "y1", "x2", "y2", "z")))
|
||||
py::class_<GraphicElement>(m, "GraphicElement")
|
||||
.def(py::init<GraphicElement::type_t, GraphicElement::style_t, float, float, float, float, float>(
|
||||
//FIXME
|
||||
//(args("type"), "style", "x1", "y1", "x2", "y2", "z")
|
||||
))
|
||||
.def_readwrite("type", &GraphicElement::type)
|
||||
.def_readwrite("x1", &GraphicElement::x1)
|
||||
.def_readwrite("y1", &GraphicElement::y1)
|
||||
@ -123,13 +125,13 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
.def_readwrite("y2", &GraphicElement::y2)
|
||||
.def_readwrite("text", &GraphicElement::text);
|
||||
|
||||
enum_<PortType>("PortType")
|
||||
py::enum_<PortType>(m, "PortType")
|
||||
.value("PORT_IN", PORT_IN)
|
||||
.value("PORT_OUT", PORT_OUT)
|
||||
.value("PORT_INOUT", PORT_INOUT)
|
||||
.export_values();
|
||||
|
||||
enum_<PlaceStrength>("PlaceStrength")
|
||||
py::enum_<PlaceStrength>(m, "PlaceStrength")
|
||||
.value("STRENGTH_NONE", STRENGTH_NONE)
|
||||
.value("STRENGTH_WEAK", STRENGTH_WEAK)
|
||||
.value("STRENGTH_STRONG", STRENGTH_STRONG)
|
||||
@ -143,15 +145,15 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
typedef std::unordered_map<IdString, IdString> IdIdMap;
|
||||
typedef std::unordered_map<IdString, std::unique_ptr<Region>> RegionMap;
|
||||
|
||||
class_<BaseCtx, BaseCtx *, boost::noncopyable>("BaseCtx", no_init);
|
||||
py::class_<BaseCtx, std::unique_ptr<BaseCtx, py::nodelete>>(m, "BaseCtx");
|
||||
|
||||
auto loc_cls = class_<Loc>("Loc")
|
||||
.def(init<int, int, int>())
|
||||
auto loc_cls = py::class_<Loc>(m, "Loc")
|
||||
.def(py::init<int, int, int>())
|
||||
.def_readwrite("x", &Loc::x)
|
||||
.def_readwrite("y", &Loc::y)
|
||||
.def_readwrite("z", &Loc::z);
|
||||
|
||||
auto ci_cls = class_<ContextualWrapper<CellInfo &>>("CellInfo", no_init);
|
||||
auto ci_cls = py::class_<ContextualWrapper<CellInfo &>>(m, "CellInfo");
|
||||
readwrite_wrapper<CellInfo &, decltype(&CellInfo::name), &CellInfo::name, conv_to_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(ci_cls, "name");
|
||||
readwrite_wrapper<CellInfo &, decltype(&CellInfo::type), &CellInfo::type, conv_to_str<IdString>,
|
||||
@ -185,7 +187,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
fn_wrapper_1a_v<CellInfo &, decltype(&CellInfo::unsetAttr), &CellInfo::unsetAttr,
|
||||
conv_from_str<IdString>>::def_wrap(ci_cls, "unsetAttr");
|
||||
|
||||
auto pi_cls = class_<ContextualWrapper<PortInfo &>>("PortInfo", no_init);
|
||||
auto pi_cls = py::class_<ContextualWrapper<PortInfo &>>(m, "PortInfo");
|
||||
readwrite_wrapper<PortInfo &, decltype(&PortInfo::name), &PortInfo::name, conv_to_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(pi_cls, "name");
|
||||
readonly_wrapper<PortInfo &, decltype(&PortInfo::net), &PortInfo::net, deref_and_wrap<NetInfo>>::def_wrap(pi_cls,
|
||||
@ -198,7 +200,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
typedef std::unordered_set<BelId> BelSet;
|
||||
typedef std::unordered_set<WireId> WireSet;
|
||||
|
||||
auto ni_cls = class_<ContextualWrapper<NetInfo &>>("NetInfo", no_init);
|
||||
auto ni_cls = py::class_<ContextualWrapper<NetInfo &>>(m, "NetInfo");
|
||||
readwrite_wrapper<NetInfo &, decltype(&NetInfo::name), &NetInfo::name, conv_to_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(ni_cls, "name");
|
||||
readwrite_wrapper<NetInfo &, decltype(&NetInfo::driver), &NetInfo::driver, wrap_context<PortRef &>,
|
||||
@ -208,7 +210,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
readonly_wrapper<NetInfo &, decltype(&NetInfo::wires), &NetInfo::wires, wrap_context<WireMap &>>::def_wrap(ni_cls,
|
||||
"wires");
|
||||
|
||||
auto pr_cls = class_<ContextualWrapper<PortRef &>>("PortRef", no_init);
|
||||
auto pr_cls = py::class_<ContextualWrapper<PortRef &>>(m, "PortRef");
|
||||
readonly_wrapper<PortRef &, decltype(&PortRef::cell), &PortRef::cell, deref_and_wrap<CellInfo>>::def_wrap(pr_cls,
|
||||
"cell");
|
||||
readwrite_wrapper<PortRef &, decltype(&PortRef::port), &PortRef::port, conv_to_str<IdString>,
|
||||
@ -216,16 +218,16 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
readwrite_wrapper<PortRef &, decltype(&PortRef::budget), &PortRef::budget, pass_through<delay_t>,
|
||||
pass_through<delay_t>>::def_wrap(pr_cls, "budget");
|
||||
|
||||
auto pm_cls = class_<ContextualWrapper<PipMap &>>("PipMap", no_init);
|
||||
auto pm_cls = py::class_<ContextualWrapper<PipMap &>>(m, "PipMap");
|
||||
readwrite_wrapper<PipMap &, decltype(&PipMap::pip), &PipMap::pip, conv_to_str<PipId>,
|
||||
conv_from_str<PipId>>::def_wrap(pm_cls, "pip");
|
||||
readwrite_wrapper<PipMap &, decltype(&PipMap::strength), &PipMap::strength, pass_through<PlaceStrength>,
|
||||
pass_through<PlaceStrength>>::def_wrap(pm_cls, "strength");
|
||||
|
||||
def("parse_json", parse_json_shim);
|
||||
def("load_design", load_design_shim, return_value_policy<manage_new_object>());
|
||||
m.def("parse_json", parse_json_shim);
|
||||
m.def("load_design", load_design_shim, py::return_value_policy::take_ownership);
|
||||
|
||||
auto region_cls = class_<ContextualWrapper<Region &>>("Region", no_init);
|
||||
auto region_cls = py::class_<ContextualWrapper<Region &>>(m, "Region");
|
||||
readwrite_wrapper<Region &, decltype(&Region::name), &Region::name, conv_to_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(region_cls, "name");
|
||||
readwrite_wrapper<Region &, decltype(&Region::constr_bels), &Region::constr_bels, pass_through<bool>,
|
||||
@ -239,7 +241,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
readonly_wrapper<Region &, decltype(&Region::wires), &Region::wires, wrap_context<WireSet &>>::def_wrap(region_cls,
|
||||
"wires");
|
||||
|
||||
auto hierarchy_cls = class_<ContextualWrapper<HierarchicalCell &>>("HierarchicalCell", no_init);
|
||||
auto hierarchy_cls = py::class_<ContextualWrapper<HierarchicalCell &>>(m, "HierarchicalCell");
|
||||
readwrite_wrapper<HierarchicalCell &, decltype(&HierarchicalCell::name), &HierarchicalCell::name,
|
||||
conv_to_str<IdString>, conv_from_str<IdString>>::def_wrap(hierarchy_cls, "name");
|
||||
readwrite_wrapper<HierarchicalCell &, decltype(&HierarchicalCell::type), &HierarchicalCell::type,
|
||||
@ -255,15 +257,15 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
wrap_context<IdIdMap &>>::def_wrap(hierarchy_cls, "nets");
|
||||
readonly_wrapper<HierarchicalCell &, decltype(&HierarchicalCell::hier_cells), &HierarchicalCell::hier_cells,
|
||||
wrap_context<IdIdMap &>>::def_wrap(hierarchy_cls, "hier_cells");
|
||||
WRAP_MAP(AttrMap, conv_to_str<Property>, "AttrMap");
|
||||
WRAP_MAP(PortMap, wrap_context<PortInfo &>, "PortMap");
|
||||
WRAP_MAP(IdIdMap, conv_to_str<IdString>, "IdIdMap");
|
||||
WRAP_MAP(WireMap, wrap_context<PipMap &>, "WireMap");
|
||||
WRAP_MAP_UPTR(RegionMap, "RegionMap");
|
||||
WRAP_MAP(m, AttrMap, conv_to_str<Property>, "AttrMap");
|
||||
WRAP_MAP(m, PortMap, wrap_context<PortInfo &>, "PortMap");
|
||||
WRAP_MAP(m, IdIdMap, conv_to_str<IdString>, "IdIdMap");
|
||||
WRAP_MAP(m, WireMap, wrap_context<PipMap &>, "WireMap");
|
||||
WRAP_MAP_UPTR(m, RegionMap, "RegionMap");
|
||||
|
||||
WRAP_VECTOR(PortRefVector, wrap_context<PortRef &>);
|
||||
WRAP_VECTOR(m, PortRefVector, wrap_context<PortRef &>);
|
||||
|
||||
arch_wrap_python();
|
||||
arch_wrap_python(m);
|
||||
}
|
||||
|
||||
#ifdef MAIN_EXECUTABLE
|
||||
@ -291,7 +293,7 @@ void init_python(const char *executable, bool first)
|
||||
|
||||
PyImport_ImportModule(TOSTRING(MODULE_NAME));
|
||||
PyRun_SimpleString("from " TOSTRING(MODULE_NAME) " import *");
|
||||
} catch (boost::python::error_already_set const &) {
|
||||
} catch (py::error_already_set const &) {
|
||||
// Parse and output the exception
|
||||
std::string perror_str = parse_python_exception();
|
||||
std::cout << "Error in Python: " << perror_str << std::endl;
|
||||
@ -321,7 +323,7 @@ void execute_python_file(const char *python_file)
|
||||
if (result == -1) {
|
||||
log_error("Error occurred while executing Python script %s\n", python_file);
|
||||
}
|
||||
} catch (boost::python::error_already_set const &) {
|
||||
} catch (py::error_already_set const &) {
|
||||
// Parse and output the exception
|
||||
std::string perror_str = parse_python_exception();
|
||||
log_error("Error in Python: %s\n", perror_str.c_str());
|
||||
|
@ -22,11 +22,10 @@
|
||||
#define COMMON_PYBINDINGS_H
|
||||
|
||||
#include <Python.h>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
|
||||
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
#include "pycontainers.h"
|
||||
#include "pywrappers.h"
|
||||
|
||||
@ -34,7 +33,7 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
using namespace boost::python;
|
||||
namespace py = pybind11;
|
||||
|
||||
std::string parse_python_exception();
|
||||
|
||||
@ -46,9 +45,9 @@ template <typename Tn> void python_export_global(const char *name, Tn &x)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
try {
|
||||
PyObject *p = incref(object(boost::ref(x)).ptr());
|
||||
PyDict_SetItemString(d, name, p);
|
||||
} catch (boost::python::error_already_set const &) {
|
||||
py::object obj = py::cast(x);
|
||||
PyDict_SetItemString(d, name, obj.ptr());
|
||||
} catch (py::error_already_set const &) {
|
||||
// Parse and output the exception
|
||||
std::string perror_str = parse_python_exception();
|
||||
std::cout << "Error in Python: " << perror_str << std::endl;
|
||||
|
@ -21,9 +21,7 @@
|
||||
#ifndef COMMON_PYCONTAINERS_H
|
||||
#define COMMON_PYCONTAINERS_H
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
|
||||
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
@ -33,12 +31,12 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
using namespace boost::python;
|
||||
namespace py = pybind11;
|
||||
|
||||
inline void KeyError()
|
||||
{
|
||||
PyErr_SetString(PyExc_KeyError, "Key not found");
|
||||
boost::python::throw_error_already_set();
|
||||
throw py::error_already_set();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -47,7 +45,7 @@ pair<Iterator, Iterator> containing (current, end), wrapped in a ContextualWrapp
|
||||
|
||||
*/
|
||||
|
||||
template <typename T, typename P, typename value_conv = PythonConversion::pass_through<T>> struct iterator_wrapper
|
||||
template <typename T, py::return_value_policy P, typename value_conv = PythonConversion::pass_through<T>> struct iterator_wrapper
|
||||
{
|
||||
typedef decltype(*(std::declval<T>())) value_t;
|
||||
|
||||
@ -62,16 +60,13 @@ template <typename T, typename P, typename value_conv = PythonConversion::pass_t
|
||||
return val;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_StopIteration, "End of range reached");
|
||||
boost::python::throw_error_already_set();
|
||||
// Should be unreachable, but prevent control may reach end of
|
||||
// non-void
|
||||
throw std::runtime_error("unreachable");
|
||||
throw py::error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
static void wrap(const char *python_name)
|
||||
static void wrap(py::module &m, const char *python_name)
|
||||
{
|
||||
class_<wrapped_iter_t>(python_name, no_init).def("__next__", next, P());
|
||||
py::class_<wrapped_iter_t>(m, python_name).def("__next__", next, P);
|
||||
}
|
||||
};
|
||||
|
||||
@ -81,7 +76,7 @@ and end() which return iterator-like objects supporting ++, * and !=
|
||||
Full STL iterator semantics are not required, unlike the standard Boost wrappers
|
||||
*/
|
||||
|
||||
template <typename T, typename P = return_value_policy<return_by_value>,
|
||||
template <typename T, py::return_value_policy P = py::return_value_policy::copy,
|
||||
typename value_conv = PythonConversion::pass_through<T>>
|
||||
struct range_wrapper
|
||||
{
|
||||
@ -110,23 +105,23 @@ struct range_wrapper
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static void wrap(const char *range_name, const char *iter_name)
|
||||
static void wrap(py::module &m, const char *range_name, const char *iter_name)
|
||||
{
|
||||
class_<wrapped_range>(range_name, no_init).def("__iter__", iter).def("__repr__", repr);
|
||||
iterator_wrapper<iterator_t, P, value_conv>().wrap(iter_name);
|
||||
py::class_<wrapped_range>(m, range_name).def("__iter__", iter).def("__repr__", repr);
|
||||
iterator_wrapper<iterator_t, P, value_conv>().wrap(m, iter_name);
|
||||
}
|
||||
|
||||
typedef iterator_wrapper<iterator_t, P, value_conv> iter_wrap;
|
||||
};
|
||||
|
||||
#define WRAP_RANGE(t, conv) \
|
||||
range_wrapper<t##Range, return_value_policy<return_by_value>, conv>().wrap(#t "Range", #t "Iterator")
|
||||
#define WRAP_RANGE(m, t, conv) \
|
||||
range_wrapper<t##Range, py::return_value_policy::copy, conv>().wrap(m, #t "Range", #t "Iterator")
|
||||
|
||||
/*
|
||||
A wrapper for a vector or similar structure. With support for conversion
|
||||
*/
|
||||
|
||||
template <typename T, typename P = return_value_policy<return_by_value>,
|
||||
template <typename T, py::return_value_policy P = py::return_value_policy::copy,
|
||||
typename value_conv = PythonConversion::pass_through<T>>
|
||||
struct vector_wrapper
|
||||
{
|
||||
@ -163,21 +158,21 @@ struct vector_wrapper
|
||||
return value_conv()(range.ctx, boost::ref(range.base.at(i)));
|
||||
}
|
||||
|
||||
static void wrap(const char *range_name, const char *iter_name)
|
||||
static void wrap(py::module &m, const char *range_name, const char *iter_name)
|
||||
{
|
||||
class_<wrapped_vector>(range_name, no_init)
|
||||
py::class_<wrapped_vector>(m, range_name)
|
||||
.def("__iter__", iter)
|
||||
.def("__repr__", repr)
|
||||
.def("__len__", len)
|
||||
.def("__getitem__", getitem);
|
||||
|
||||
iterator_wrapper<iterator_t, P, value_conv>().wrap(iter_name);
|
||||
iterator_wrapper<iterator_t, P, value_conv>().wrap(m, iter_name);
|
||||
}
|
||||
|
||||
typedef iterator_wrapper<iterator_t, P, value_conv> iter_wrap;
|
||||
};
|
||||
|
||||
#define WRAP_VECTOR(t, conv) vector_wrapper<t, return_value_policy<return_by_value>, conv>().wrap(#t, #t "Iterator")
|
||||
#define WRAP_VECTOR(m, t, conv) vector_wrapper<t, py::return_value_policy::copy, conv>().wrap(m, #t, #t "Iterator")
|
||||
|
||||
/*
|
||||
Wrapper for a pair, allows accessing either using C++-style members (.first and
|
||||
@ -189,58 +184,55 @@ template <typename T1, typename T2> struct pair_wrapper
|
||||
|
||||
struct pair_iterator_wrapper
|
||||
{
|
||||
static object next(std::pair<T &, int> &iter)
|
||||
static py::object next(std::pair<T &, int> &iter)
|
||||
{
|
||||
if (iter.second == 0) {
|
||||
iter.second++;
|
||||
return object(iter.first.first);
|
||||
return py::cast(iter.first.first);
|
||||
} else if (iter.second == 1) {
|
||||
iter.second++;
|
||||
return object(iter.first.second);
|
||||
return py::cast(iter.first.second);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_StopIteration, "End of range reached");
|
||||
boost::python::throw_error_already_set();
|
||||
// Should be unreachable, but prevent control may reach end of
|
||||
// non-void
|
||||
throw std::runtime_error("unreachable");
|
||||
throw py::error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
static void wrap(const char *python_name)
|
||||
static void wrap(py::module &m, const char *python_name)
|
||||
{
|
||||
class_<std::pair<T &, int>>(python_name, no_init).def("__next__", next);
|
||||
py::class_<std::pair<T &, int>>(m, python_name).def("__next__", next);
|
||||
}
|
||||
};
|
||||
|
||||
static object get(T &x, int i)
|
||||
static py::object get(T &x, int i)
|
||||
{
|
||||
if ((i >= 2) || (i < 0))
|
||||
KeyError();
|
||||
return (i == 1) ? object(x.second) : object(x.first);
|
||||
return (i == 1) ? py::object(x.second) : py::object(x.first);
|
||||
}
|
||||
|
||||
static void set(T &x, int i, object val)
|
||||
static void set(T &x, int i, py::object val)
|
||||
{
|
||||
if ((i >= 2) || (i < 0))
|
||||
KeyError();
|
||||
if (i == 0)
|
||||
x.first = extract<T1>(val);
|
||||
x.first = val.cast<T1>();
|
||||
if (i == 1)
|
||||
x.second = extract<T2>(val);
|
||||
x.second = val.cast<T2>();
|
||||
}
|
||||
|
||||
static int len(T &x) { return 2; }
|
||||
|
||||
static std::pair<T &, int> iter(T &x) { return std::make_pair(boost::ref(x), 0); };
|
||||
|
||||
static void wrap(const char *pair_name, const char *iter_name)
|
||||
static void wrap(py::module &m, const char *pair_name, const char *iter_name)
|
||||
{
|
||||
pair_iterator_wrapper::wrap(iter_name);
|
||||
class_<T>(pair_name, no_init)
|
||||
pair_iterator_wrapper::wrap(m, iter_name);
|
||||
py::class_<T>(m, pair_name)
|
||||
.def("__iter__", iter)
|
||||
.def("__len__", len)
|
||||
.def("__getitem__", get)
|
||||
.def("__setitem__", set, with_custodian_and_ward<1, 2>())
|
||||
.def("__setitem__", set, py::keep_alive<1, 2>())
|
||||
.def_readwrite("first", &T::first)
|
||||
.def_readwrite("second", &T::second);
|
||||
}
|
||||
@ -257,36 +249,34 @@ template <typename T1, typename T2, typename value_conv> struct map_pair_wrapper
|
||||
|
||||
struct pair_iterator_wrapper
|
||||
{
|
||||
static object next(std::pair<wrapped_pair &, int> &iter)
|
||||
static py::object next(std::pair<wrapped_pair &, int> &iter)
|
||||
{
|
||||
if (iter.second == 0) {
|
||||
iter.second++;
|
||||
return object(PythonConversion::string_converter<decltype(iter.first.base.first)>().to_str(
|
||||
return py::cast(PythonConversion::string_converter<decltype(iter.first.base.first)>().to_str(
|
||||
iter.first.ctx, iter.first.base.first));
|
||||
} else if (iter.second == 1) {
|
||||
iter.second++;
|
||||
return object(value_conv()(iter.first.ctx, iter.first.base.second));
|
||||
return py::cast(value_conv()(iter.first.ctx, iter.first.base.second));
|
||||
} else {
|
||||
PyErr_SetString(PyExc_StopIteration, "End of range reached");
|
||||
boost::python::throw_error_already_set();
|
||||
// Should be unreachable, but prevent control may reach end of
|
||||
// non-void
|
||||
throw std::runtime_error("unreachable");
|
||||
throw py::error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
static void wrap(const char *python_name)
|
||||
static void wrap(py::module &m, const char *python_name)
|
||||
{
|
||||
class_<std::pair<wrapped_pair &, int>>(python_name, no_init).def("__next__", next);
|
||||
//FIXME
|
||||
//py::class_<std::pair<wrapped_pair &, int>>(m, python_name).def("__next__", next);
|
||||
}
|
||||
};
|
||||
|
||||
static object get(wrapped_pair &x, int i)
|
||||
static py::object get(wrapped_pair &x, int i)
|
||||
{
|
||||
if ((i >= 2) || (i < 0))
|
||||
KeyError();
|
||||
return (i == 1) ? object(value_conv()(x.ctx, x.base.second))
|
||||
: object(PythonConversion::string_converter<decltype(x.base.first)>().to_str(x.ctx,
|
||||
return (i == 1) ? py::cast(value_conv()(x.ctx, x.base.second))
|
||||
: py::cast(PythonConversion::string_converter<decltype(x.base.first)>().to_str(x.ctx,
|
||||
x.base.first));
|
||||
}
|
||||
|
||||
@ -301,15 +291,15 @@ template <typename T1, typename T2, typename value_conv> struct map_pair_wrapper
|
||||
|
||||
static typename value_conv::ret_type second_getter(wrapped_pair &t) { return value_conv()(t.ctx, t.base.second); }
|
||||
|
||||
static void wrap(const char *pair_name, const char *iter_name)
|
||||
static void wrap(py::module &m, const char *pair_name, const char *iter_name)
|
||||
{
|
||||
pair_iterator_wrapper::wrap(iter_name);
|
||||
class_<wrapped_pair>(pair_name, no_init)
|
||||
pair_iterator_wrapper::wrap(m, iter_name);
|
||||
py::class_<wrapped_pair>(m, pair_name)
|
||||
.def("__iter__", iter)
|
||||
.def("__len__", len)
|
||||
.def("__getitem__", get)
|
||||
.add_property("first", first_getter)
|
||||
.add_property("second", second_getter);
|
||||
.def_property_readonly("first", first_getter)
|
||||
.def_property_readonly("second", second_getter);
|
||||
}
|
||||
};
|
||||
|
||||
@ -358,17 +348,17 @@ template <typename T, typename value_conv> struct map_wrapper
|
||||
return x.base.count(k);
|
||||
}
|
||||
|
||||
static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name)
|
||||
static void wrap(py::module &m, const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name)
|
||||
{
|
||||
map_pair_wrapper<typename KV::first_type, typename KV::second_type, value_conv>::wrap(kv_name, kv_iter_name);
|
||||
typedef range_wrapper<T &, return_value_policy<return_by_value>, PythonConversion::wrap_context<KV &>> rw;
|
||||
typename rw::iter_wrap().wrap(iter_name);
|
||||
class_<wrapped_map>(map_name, no_init)
|
||||
map_pair_wrapper<typename KV::first_type, typename KV::second_type, value_conv>::wrap(m, kv_name, kv_iter_name);
|
||||
typedef range_wrapper<T &, py::return_value_policy::copy, PythonConversion::wrap_context<KV &>> rw;
|
||||
typename rw::iter_wrap().wrap(m, iter_name);
|
||||
py::class_<wrapped_map>(m, map_name)
|
||||
.def("__iter__", rw::iter)
|
||||
.def("__len__", len)
|
||||
.def("__contains__", contains)
|
||||
.def("__getitem__", get)
|
||||
.def("__setitem__", set, with_custodian_and_ward<1, 2>());
|
||||
.def("__setitem__", set, py::keep_alive<1, 2>());
|
||||
}
|
||||
};
|
||||
|
||||
@ -383,36 +373,34 @@ template <typename T1, typename T2> struct map_pair_wrapper_uptr
|
||||
|
||||
struct pair_iterator_wrapper
|
||||
{
|
||||
static object next(std::pair<wrapped_pair &, int> &iter)
|
||||
static py::object next(std::pair<wrapped_pair &, int> &iter)
|
||||
{
|
||||
if (iter.second == 0) {
|
||||
iter.second++;
|
||||
return object(PythonConversion::string_converter<decltype(iter.first.base.first)>().to_str(
|
||||
return py::cast(PythonConversion::string_converter<decltype(iter.first.base.first)>().to_str(
|
||||
iter.first.ctx, iter.first.base.first));
|
||||
} else if (iter.second == 1) {
|
||||
iter.second++;
|
||||
return object(PythonConversion::ContextualWrapper<V &>(iter.first.ctx, *iter.first.base.second.get()));
|
||||
return py::cast(PythonConversion::ContextualWrapper<V &>(iter.first.ctx, *iter.first.base.second.get()));
|
||||
} else {
|
||||
PyErr_SetString(PyExc_StopIteration, "End of range reached");
|
||||
boost::python::throw_error_already_set();
|
||||
// Should be unreachable, but prevent control may reach end of
|
||||
// non-void
|
||||
throw std::runtime_error("unreachable");
|
||||
throw py::error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
static void wrap(const char *python_name)
|
||||
static void wrap(py::module &m, const char *python_name)
|
||||
{
|
||||
class_<std::pair<wrapped_pair &, int>>(python_name, no_init).def("__next__", next);
|
||||
//FIXME
|
||||
//py::class_<std::pair<wrapped_pair &, int>>(m, python_name).def("__next__", next);
|
||||
}
|
||||
};
|
||||
|
||||
static object get(wrapped_pair &x, int i)
|
||||
static py::object get(wrapped_pair &x, int i)
|
||||
{
|
||||
if ((i >= 2) || (i < 0))
|
||||
KeyError();
|
||||
return (i == 1) ? object(PythonConversion::ContextualWrapper<V &>(x.ctx, *x.base.second.get()))
|
||||
: object(PythonConversion::string_converter<decltype(x.base.first)>().to_str(x.ctx,
|
||||
return (i == 1) ? py::cast(PythonConversion::ContextualWrapper<V &>(x.ctx, *x.base.second.get()))
|
||||
: py::cast(PythonConversion::string_converter<decltype(x.base.first)>().to_str(x.ctx,
|
||||
x.base.first));
|
||||
}
|
||||
|
||||
@ -430,15 +418,15 @@ template <typename T1, typename T2> struct map_pair_wrapper_uptr
|
||||
return PythonConversion::ContextualWrapper<V &>(t.ctx, *t.base.second.get());
|
||||
}
|
||||
|
||||
static void wrap(const char *pair_name, const char *iter_name)
|
||||
static void wrap(py::module &m, const char *pair_name, const char *iter_name)
|
||||
{
|
||||
pair_iterator_wrapper::wrap(iter_name);
|
||||
class_<wrapped_pair>(pair_name, no_init)
|
||||
pair_iterator_wrapper::wrap(m, iter_name);
|
||||
py::class_<wrapped_pair>(m, pair_name)
|
||||
.def("__iter__", iter)
|
||||
.def("__len__", len)
|
||||
.def("__getitem__", get)
|
||||
.add_property("first", first_getter)
|
||||
.add_property("second", second_getter);
|
||||
.def_property_readonly("first", first_getter)
|
||||
.def_property_readonly("second", second_getter);
|
||||
}
|
||||
};
|
||||
|
||||
@ -487,24 +475,24 @@ template <typename T> struct map_wrapper_uptr
|
||||
return x.base.count(k);
|
||||
}
|
||||
|
||||
static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name)
|
||||
static void wrap(py::module &m, const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name)
|
||||
{
|
||||
map_pair_wrapper_uptr<typename KV::first_type, typename KV::second_type>::wrap(kv_name, kv_iter_name);
|
||||
typedef range_wrapper<T &, return_value_policy<return_by_value>, PythonConversion::wrap_context<KV &>> rw;
|
||||
typename rw::iter_wrap().wrap(iter_name);
|
||||
class_<wrapped_map>(map_name, no_init)
|
||||
map_pair_wrapper_uptr<typename KV::first_type, typename KV::second_type>::wrap(m, kv_name, kv_iter_name);
|
||||
typedef range_wrapper<T &, py::return_value_policy::copy, PythonConversion::wrap_context<KV &>> rw;
|
||||
typename rw::iter_wrap().wrap(m, iter_name);
|
||||
py::class_<wrapped_map>(m, map_name)
|
||||
.def("__iter__", rw::iter)
|
||||
.def("__len__", len)
|
||||
.def("__contains__", contains)
|
||||
.def("__getitem__", get)
|
||||
.def("__setitem__", set, with_custodian_and_ward<1, 2>());
|
||||
.def("__setitem__", set, py::keep_alive<1, 2>());
|
||||
}
|
||||
};
|
||||
|
||||
#define WRAP_MAP(t, conv, name) \
|
||||
map_wrapper<t, conv>().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator")
|
||||
#define WRAP_MAP_UPTR(t, name) \
|
||||
map_wrapper_uptr<t>().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator")
|
||||
#define WRAP_MAP(m, t, conv, name) \
|
||||
map_wrapper<t, conv>().wrap(m, #name, #name "KeyValue", #name "KeyValueIter", #name "Iterator")
|
||||
#define WRAP_MAP_UPTR(m, t, name) \
|
||||
map_wrapper_uptr<t>().wrap(m, #name, #name "KeyValue", #name "KeyValueIter", #name "Iterator")
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
|
@ -21,19 +21,13 @@
|
||||
#ifndef PYWRAPPERS_H
|
||||
#define PYWRAPPERS_H
|
||||
|
||||
#include <boost/function_types/function_arity.hpp>
|
||||
#include <boost/function_types/function_type.hpp>
|
||||
#include <boost/function_types/parameter_types.hpp>
|
||||
#include <boost/function_types/result_type.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
|
||||
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <utility>
|
||||
#include "nextpnr.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
using namespace boost::python;
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace PythonConversion {
|
||||
template <typename T> struct ContextualWrapper
|
||||
@ -155,14 +149,14 @@ template <typename Class, typename FuncT, FuncT fn, typename rv_conv> struct fn_
|
||||
using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t;
|
||||
using conv_result_type = typename rv_conv::ret_type;
|
||||
|
||||
static object wrapped_fn(class_type &cls)
|
||||
static py::object wrapped_fn(class_type &cls)
|
||||
{
|
||||
Context *ctx = get_ctx<Class>(cls);
|
||||
Class &base = get_base<Class>(cls);
|
||||
try {
|
||||
return object(rv_conv()(ctx, (base.*fn)()));
|
||||
return py::cast(rv_conv()(ctx, (base.*fn)()));
|
||||
} catch (bad_wrap &) {
|
||||
return object();
|
||||
return py::object();
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,14 +170,14 @@ template <typename Class, typename FuncT, FuncT fn, typename rv_conv, typename a
|
||||
using conv_result_type = typename rv_conv::ret_type;
|
||||
using conv_arg1_type = typename arg1_conv::arg_type;
|
||||
|
||||
static object wrapped_fn(class_type &cls, conv_arg1_type arg1)
|
||||
static py::object wrapped_fn(class_type &cls, conv_arg1_type arg1)
|
||||
{
|
||||
Context *ctx = get_ctx<Class>(cls);
|
||||
Class &base = get_base<Class>(cls);
|
||||
try {
|
||||
return object(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1))));
|
||||
return py::cast(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1))));
|
||||
} catch (bad_wrap &) {
|
||||
return object();
|
||||
return py::object();
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,14 +193,14 @@ struct fn_wrapper_2a
|
||||
using conv_arg1_type = typename arg1_conv::arg_type;
|
||||
using conv_arg2_type = typename arg2_conv::arg_type;
|
||||
|
||||
static object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2)
|
||||
static py::object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2)
|
||||
{
|
||||
Context *ctx = get_ctx<Class>(cls);
|
||||
Class &base = get_base<Class>(cls);
|
||||
try {
|
||||
return object(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2))));
|
||||
return py::cast(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2))));
|
||||
} catch (bad_wrap &) {
|
||||
return object();
|
||||
return py::object();
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,15 +218,15 @@ struct fn_wrapper_3a
|
||||
using conv_arg2_type = typename arg2_conv::arg_type;
|
||||
using conv_arg3_type = typename arg3_conv::arg_type;
|
||||
|
||||
static object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2, conv_arg3_type arg3)
|
||||
static py::object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2, conv_arg3_type arg3)
|
||||
{
|
||||
Context *ctx = get_ctx<Class>(cls);
|
||||
Class &base = get_base<Class>(cls);
|
||||
try {
|
||||
return object(
|
||||
return py::cast(
|
||||
rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3))));
|
||||
} catch (bad_wrap &) {
|
||||
return object();
|
||||
return py::object();
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +262,7 @@ template <typename Class, typename FuncT, FuncT fn, typename arg1_conv> struct f
|
||||
|
||||
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); }
|
||||
|
||||
template <typename WrapCls, typename Ta> static void def_wrap(WrapCls cls_, const char *name, Ta a = arg("arg1"))
|
||||
template <typename WrapCls, typename Ta> static void def_wrap(WrapCls cls_, const char *name, Ta a = py::arg("arg1"))
|
||||
{
|
||||
cls_.def(name, wrapped_fn, a);
|
||||
}
|
||||
@ -413,20 +407,20 @@ template <typename Class, typename MemT, MemT mem, typename v_conv> struct reado
|
||||
using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t;
|
||||
using conv_val_type = typename v_conv::ret_type;
|
||||
|
||||
static object wrapped_getter(class_type &cls)
|
||||
static py::object wrapped_getter(class_type &cls)
|
||||
{
|
||||
Context *ctx = get_ctx<Class>(cls);
|
||||
Class &base = get_base<Class>(cls);
|
||||
try {
|
||||
return object(v_conv()(ctx, (base.*mem)));
|
||||
return py::cast(v_conv()(ctx, (base.*mem)));
|
||||
} catch (bad_wrap &) {
|
||||
return object();
|
||||
return py::object();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name)
|
||||
{
|
||||
cls_.add_property(name, wrapped_getter);
|
||||
cls_.def_property_readonly(name, wrapped_getter);
|
||||
}
|
||||
};
|
||||
|
||||
@ -436,14 +430,14 @@ template <typename Class, typename MemT, MemT mem, typename get_conv, typename s
|
||||
using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t;
|
||||
using conv_val_type = typename get_conv::ret_type;
|
||||
|
||||
static object wrapped_getter(class_type &cls)
|
||||
static py::object wrapped_getter(class_type &cls)
|
||||
{
|
||||
Context *ctx = get_ctx<Class>(cls);
|
||||
Class &base = get_base<Class>(cls);
|
||||
try {
|
||||
return object(get_conv()(ctx, (base.*mem)));
|
||||
return py::cast(get_conv()(ctx, (base.*mem)));
|
||||
} catch (bad_wrap &) {
|
||||
return object();
|
||||
return py::object();
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,7 +452,7 @@ template <typename Class, typename MemT, MemT mem, typename get_conv, typename s
|
||||
|
||||
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name)
|
||||
{
|
||||
cls_.add_property(name, wrapped_getter, wrapped_setter);
|
||||
cls_.def_property(name, wrapped_getter, wrapped_setter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -26,21 +26,19 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
void arch_wrap_python()
|
||||
void arch_wrap_python(py::module &m)
|
||||
{
|
||||
using namespace PythonConversion;
|
||||
class_<ArchArgs>("ArchArgs").def_readwrite("type", &ArchArgs::type);
|
||||
py::class_<ArchArgs>(m, "ArchArgs").def_readwrite("type", &ArchArgs::type);
|
||||
|
||||
class_<BelId>("BelId").def_readwrite("index", &BelId::index);
|
||||
py::class_<BelId>(m, "BelId").def_readwrite("index", &BelId::index);
|
||||
|
||||
class_<WireId>("WireId").def_readwrite("index", &WireId::index);
|
||||
py::class_<WireId>(m, "WireId").def_readwrite("index", &WireId::index);
|
||||
|
||||
class_<PipId>("PipId").def_readwrite("index", &PipId::index);
|
||||
py::class_<PipId>(m, "PipId").def_readwrite("index", &PipId::index);
|
||||
|
||||
class_<BelPin>("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||
|
||||
auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>());
|
||||
auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init)
|
||||
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
|
||||
auto ctx_cls = py::class_<Context, Arch>(m, "Context")
|
||||
.def("checksum", &Context::checksum)
|
||||
.def("pack", &Context::pack)
|
||||
.def("place", &Context::place)
|
||||
@ -54,21 +52,21 @@ void arch_wrap_python()
|
||||
typedef std::unordered_map<IdString, IdString> AliasMap;
|
||||
typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
|
||||
|
||||
auto belpin_cls = class_<ContextualWrapper<BelPin>>("BelPin", no_init);
|
||||
auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin");
|
||||
readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel");
|
||||
readonly_wrapper<BelPin, decltype(&BelPin::pin), &BelPin::pin, conv_to_str<IdString>>::def_wrap(belpin_cls, "pin");
|
||||
|
||||
#include "arch_pybindings_shared.h"
|
||||
|
||||
WRAP_RANGE(Bel, conv_to_str<BelId>);
|
||||
WRAP_RANGE(Wire, conv_to_str<WireId>);
|
||||
WRAP_RANGE(AllPip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(Pip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(BelPin, wrap_context<BelPin>);
|
||||
WRAP_RANGE(m, Bel, conv_to_str<BelId>);
|
||||
WRAP_RANGE(m, Wire, conv_to_str<WireId>);
|
||||
WRAP_RANGE(m, AllPip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(m, Pip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(m, BelPin, wrap_context<BelPin>);
|
||||
|
||||
WRAP_MAP_UPTR(CellMap, "IdCellMap");
|
||||
WRAP_MAP_UPTR(NetMap, "IdNetMap");
|
||||
WRAP_MAP(HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
||||
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
|
||||
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
|
||||
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -35,13 +35,13 @@ template <> struct string_converter<const IdString &>
|
||||
};
|
||||
} // namespace PythonConversion
|
||||
|
||||
void arch_wrap_python()
|
||||
void arch_wrap_python(py::module &m)
|
||||
{
|
||||
using namespace PythonConversion;
|
||||
|
||||
auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>());
|
||||
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
|
||||
|
||||
auto dxy_cls = class_<ContextualWrapper<DecalXY>>("DecalXY_", no_init);
|
||||
auto dxy_cls = py::class_<ContextualWrapper<DecalXY>>(m, "DecalXY_");
|
||||
readwrite_wrapper<DecalXY, decltype(&DecalXY::decal), &DecalXY::decal, conv_to_str<DecalId>,
|
||||
conv_from_str<DecalId>>::def_wrap(dxy_cls, "decal");
|
||||
readwrite_wrapper<DecalXY, decltype(&DecalXY::x), &DecalXY::x, pass_through<float>, pass_through<float>>::def_wrap(
|
||||
@ -49,15 +49,15 @@ void arch_wrap_python()
|
||||
readwrite_wrapper<DecalXY, decltype(&DecalXY::y), &DecalXY::y, pass_through<float>, pass_through<float>>::def_wrap(
|
||||
dxy_cls, "y");
|
||||
|
||||
auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init)
|
||||
auto ctx_cls = py::class_<Context, Arch>(m, "Context")
|
||||
.def("checksum", &Context::checksum)
|
||||
.def("pack", &Context::pack)
|
||||
.def("place", &Context::place)
|
||||
.def("route", &Context::route);
|
||||
|
||||
class_<BelPin>("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||
|
||||
class_<DelayInfo>("DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
|
||||
py::class_<DelayInfo>(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
||||
@ -154,86 +154,86 @@ void arch_wrap_python()
|
||||
// Generic arch construction API
|
||||
fn_wrapper_4a_v<Context, decltype(&Context::addWire), &Context::addWire, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>, pass_through<int>, pass_through<int>>::def_wrap(ctx_cls, "addWire",
|
||||
(arg("name"), "type", "x",
|
||||
(py::arg("name"), "type", "x",
|
||||
"y"));
|
||||
fn_wrapper_6a_v<Context, decltype(&Context::addPip), &Context::addPip, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, pass_through<DelayInfo>,
|
||||
pass_through<Loc>>::def_wrap(ctx_cls, "addPip",
|
||||
(arg("name"), "type", "srcWire", "dstWire", "delay", "loc"));
|
||||
(py::arg("name"), "type", "srcWire", "dstWire", "delay", "loc"));
|
||||
fn_wrapper_5a_v<Context, decltype(&Context::addAlias), &Context::addAlias, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addAlias",
|
||||
(arg("name"), "type", "srcWire", "dstWire", "delay"));
|
||||
(py::arg("name"), "type", "srcWire", "dstWire", "delay"));
|
||||
|
||||
fn_wrapper_4a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>, pass_through<Loc>, pass_through<bool>>::def_wrap(ctx_cls, "addBel",
|
||||
(arg("name"), "type",
|
||||
(py::arg("name"), "type",
|
||||
"loc", "gb"));
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::addBelInput), &Context::addBelInput, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "addBelInput",
|
||||
(arg("bel"), "name", "wire"));
|
||||
(py::arg("bel"), "name", "wire"));
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::addBelOutput), &Context::addBelOutput, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "addBelOutput",
|
||||
(arg("bel"), "name", "wire"));
|
||||
(py::arg("bel"), "name", "wire"));
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::addBelInout), &Context::addBelInout, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "addBelInout",
|
||||
(arg("bel"), "name", "wire"));
|
||||
(py::arg("bel"), "name", "wire"));
|
||||
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::addGroupBel), &Context::addGroupBel, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupBel", (arg("group"), "bel"));
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupBel", (py::arg("group"), "bel"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::addGroupWire), &Context::addGroupWire, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupWire", (arg("group"), "wire"));
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupWire", (py::arg("group"), "wire"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::addGroupPip), &Context::addGroupPip, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupPip", (arg("group"), "pip"));
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupPip", (py::arg("group"), "pip"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::addGroupGroup), &Context::addGroupPip, conv_from_str<IdString>,
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupGroup", (arg("group"), "grp"));
|
||||
conv_from_str<IdString>>::def_wrap(ctx_cls, "addGroupGroup", (py::arg("group"), "grp"));
|
||||
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::addDecalGraphic), &Context::addDecalGraphic, conv_from_str<DecalId>,
|
||||
pass_through<GraphicElement>>::def_wrap(ctx_cls, "addDecalGraphic", (arg("decal"), "graphic"));
|
||||
pass_through<GraphicElement>>::def_wrap(ctx_cls, "addDecalGraphic", (py::arg("decal"), "graphic"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::setWireDecal), &Context::setWireDecal, conv_from_str<DecalId>,
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setWireDecal", (arg("wire"), "decalxy"));
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setWireDecal", (py::arg("wire"), "decalxy"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::setPipDecal), &Context::setPipDecal, conv_from_str<DecalId>,
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setPipDecal", (arg("pip"), "decalxy"));
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setPipDecal", (py::arg("pip"), "decalxy"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::setBelDecal), &Context::setBelDecal, conv_from_str<DecalId>,
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setBelDecal", (arg("bel"), "decalxy"));
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setBelDecal", (py::arg("bel"), "decalxy"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::setGroupDecal), &Context::setGroupDecal, conv_from_str<DecalId>,
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setGroupDecal", (arg("group"), "decalxy"));
|
||||
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setGroupDecal", (py::arg("group"), "decalxy"));
|
||||
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::setWireAttr), &Context::setWireAttr, conv_from_str<DecalId>,
|
||||
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setWireAttr",
|
||||
(arg("wire"), "key", "value"));
|
||||
(py::arg("wire"), "key", "value"));
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::setBelAttr), &Context::setBelAttr, conv_from_str<DecalId>,
|
||||
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setBelAttr",
|
||||
(arg("bel"), "key", "value"));
|
||||
(py::arg("bel"), "key", "value"));
|
||||
fn_wrapper_3a_v<Context, decltype(&Context::setPipAttr), &Context::setPipAttr, conv_from_str<DecalId>,
|
||||
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setPipAttr",
|
||||
(arg("pip"), "key", "value"));
|
||||
(py::arg("pip"), "key", "value"));
|
||||
|
||||
fn_wrapper_1a_v<Context, decltype(&Context::setLutK), &Context::setLutK, pass_through<int>>::def_wrap(
|
||||
ctx_cls, "setLutK", arg("K"));
|
||||
ctx_cls, "setLutK", py::arg("K"));
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::setDelayScaling), &Context::setDelayScaling, pass_through<double>,
|
||||
pass_through<double>>::def_wrap(ctx_cls, "setDelayScaling", (arg("scale"), "offset"));
|
||||
pass_through<double>>::def_wrap(ctx_cls, "setDelayScaling", (py::arg("scale"), "offset"));
|
||||
|
||||
fn_wrapper_2a_v<Context, decltype(&Context::addCellTimingClock), &Context::addCellTimingClock,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "addCellTimingClock",
|
||||
(arg("cell"), "port"));
|
||||
(py::arg("cell"), "port"));
|
||||
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingDelay), &Context::addCellTimingDelay,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingDelay",
|
||||
(arg("cell"), "fromPort", "toPort", "delay"));
|
||||
(py::arg("cell"), "fromPort", "toPort", "delay"));
|
||||
fn_wrapper_5a_v<Context, decltype(&Context::addCellTimingSetupHold), &Context::addCellTimingSetupHold,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, pass_through<DelayInfo>,
|
||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingSetupHold",
|
||||
(arg("cell"), "port", "clock", "setup", "hold"));
|
||||
(py::arg("cell"), "port", "clock", "setup", "hold"));
|
||||
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingClockToOut), &Context::addCellTimingClockToOut,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingClockToOut",
|
||||
(arg("cell"), "port", "clock", "clktoq"));
|
||||
(py::arg("cell"), "port", "clock", "clktoq"));
|
||||
|
||||
WRAP_MAP_UPTR(CellMap, "IdCellMap");
|
||||
WRAP_MAP_UPTR(NetMap, "IdNetMap");
|
||||
WRAP_MAP(HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
||||
WRAP_VECTOR(const std::vector<IdString>, conv_to_str<IdString>);
|
||||
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
|
||||
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
|
||||
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
||||
WRAP_VECTOR(m, const std::vector<IdString>, conv_to_str<IdString>);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -26,12 +26,12 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
void arch_wrap_python()
|
||||
void arch_wrap_python(py::module &m)
|
||||
{
|
||||
using namespace PythonConversion;
|
||||
class_<ArchArgs>("ArchArgs").def_readwrite("type", &ArchArgs::type);
|
||||
py::class_<ArchArgs>(m, "ArchArgs").def_readwrite("type", &ArchArgs::type);
|
||||
|
||||
enum_<decltype(std::declval<ArchArgs>().type)>("iCE40Type")
|
||||
py::enum_<decltype(std::declval<ArchArgs>().type)>(m, "iCE40Type")
|
||||
.value("NONE", ArchArgs::NONE)
|
||||
.value("LP384", ArchArgs::LP384)
|
||||
.value("LP1K", ArchArgs::LP1K)
|
||||
@ -47,16 +47,14 @@ void arch_wrap_python()
|
||||
.value("U4K", ArchArgs::U4K)
|
||||
.export_values();
|
||||
|
||||
class_<BelId>("BelId").def_readwrite("index", &BelId::index);
|
||||
py::class_<BelId>(m, "BelId").def_readwrite("index", &BelId::index);
|
||||
|
||||
class_<WireId>("WireId").def_readwrite("index", &WireId::index);
|
||||
py::class_<WireId>(m, "WireId").def_readwrite("index", &WireId::index);
|
||||
|
||||
class_<PipId>("PipId").def_readwrite("index", &PipId::index);
|
||||
py::class_<PipId>(m, "PipId").def_readwrite("index", &PipId::index);
|
||||
|
||||
class_<BelPin>("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||
|
||||
auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>());
|
||||
auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init)
|
||||
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
|
||||
auto ctx_cls = py::class_<Context, Arch>(m, "Context")
|
||||
.def("checksum", &Context::checksum)
|
||||
.def("pack", &Context::pack)
|
||||
.def("place", &Context::place)
|
||||
@ -70,21 +68,21 @@ void arch_wrap_python()
|
||||
typedef std::unordered_map<IdString, IdString> AliasMap;
|
||||
typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
|
||||
|
||||
auto belpin_cls = class_<ContextualWrapper<BelPin>>("BelPin", no_init);
|
||||
auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin");
|
||||
readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel");
|
||||
readonly_wrapper<BelPin, decltype(&BelPin::pin), &BelPin::pin, conv_to_str<IdString>>::def_wrap(belpin_cls, "pin");
|
||||
|
||||
#include "arch_pybindings_shared.h"
|
||||
|
||||
WRAP_RANGE(Bel, conv_to_str<BelId>);
|
||||
WRAP_RANGE(Wire, conv_to_str<WireId>);
|
||||
WRAP_RANGE(AllPip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(Pip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(BelPin, wrap_context<BelPin>);
|
||||
WRAP_RANGE(m, Bel, conv_to_str<BelId>);
|
||||
WRAP_RANGE(m, Wire, conv_to_str<WireId>);
|
||||
WRAP_RANGE(m, AllPip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(m, Pip, conv_to_str<PipId>);
|
||||
WRAP_RANGE(m, BelPin, wrap_context<BelPin>);
|
||||
|
||||
WRAP_MAP_UPTR(CellMap, "IdCellMap");
|
||||
WRAP_MAP_UPTR(NetMap, "IdNetMap");
|
||||
WRAP_MAP(HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
||||
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
|
||||
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
|
||||
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
Loading…
Reference in New Issue
Block a user