diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 54333b15..daaadf28 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -444,5 +444,13 @@ void BaseCtx::constrainCellToRegion(IdString cell, IdString region_name) { cells[cell]->region = region[region_name].get(); } +DecalXY BaseCtx::constructDecalXY(DecalId decal, float x, float y) +{ + DecalXY dxy; + dxy.decal = decal; + dxy.x = x; + dxy.y = y; + return dxy; +} NEXTPNR_NAMESPACE_END diff --git a/common/nextpnr.h b/common/nextpnr.h index 5967ecee..79dbbaca 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -181,6 +181,9 @@ struct GraphicElement float x1 = 0, y1 = 0, x2 = 0, y2 = 0, z = 0; std::string text; + GraphicElement() {}; + GraphicElement(type_t type, style_t style, float x1, float y1, float x2, float y2, float z) : type(type), + style(style), x1(x1), y1(y1), x2(x2), y2(y2), z(z) {}; }; struct Loc @@ -640,6 +643,9 @@ struct BaseCtx void createRectangularRegion(IdString name, int x0, int y0, int x1, int y1); void addBelToRegion(IdString name, BelId bel); void constrainCellToRegion(IdString cell, IdString region_name); + + // Workaround for lack of wrappable constructors + DecalXY constructDecalXY(DecalId decal, float x, float y); }; NEXTPNR_NAMESPACE_END diff --git a/common/pybindings.cc b/common/pybindings.cc index bf5382eb..e1fc8534 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -87,7 +87,26 @@ BOOST_PYTHON_MODULE(MODULE_NAME) using namespace PythonConversion; + enum_("GraphicElementType") + .value("TYPE_NONE", GraphicElement::TYPE_NONE) + .value("TYPE_LINE", GraphicElement::TYPE_LINE) + .value("TYPE_ARROW", GraphicElement::TYPE_ARROW) + .value("TYPE_BOX", GraphicElement::TYPE_BOX) + .value("TYPE_CIRCLE", GraphicElement::TYPE_CIRCLE) + .value("TYPE_LABEL", GraphicElement::TYPE_LABEL) + .export_values(); + + enum_("GraphicElementStyle") + .value("STYLE_GRID", GraphicElement::STYLE_GRID) + .value("STYLE_FRAME", GraphicElement::STYLE_FRAME) + .value("STYLE_HIDDEN", GraphicElement::STYLE_HIDDEN) + .value("STYLE_INACTIVE", GraphicElement::STYLE_INACTIVE) + .value("STYLE_ACTIVE", GraphicElement::STYLE_ACTIVE) + .export_values(); + class_("GraphicElement") + .def(init( + (args("type"), "style", "x1", "y1", "x2", "y2", "z"))) .def_readwrite("type", &GraphicElement::type) .def_readwrite("x1", &GraphicElement::x1) .def_readwrite("y1", &GraphicElement::y1) @@ -214,8 +233,7 @@ void init_python(const char *executable, bool first) PyImport_AppendInittab(TOSTRING(MODULE_NAME), PYINIT_MODULE_NAME); Py_SetProgramName(program); Py_Initialize(); - if (first) - PyImport_ImportModule(TOSTRING(MODULE_NAME)); + PyImport_ImportModule(TOSTRING(MODULE_NAME)); PyRun_SimpleString("from " TOSTRING(MODULE_NAME) " import *"); } catch (boost::python::error_already_set const &) { // Parse and output the exception diff --git a/generic/arch.cc b/generic/arch.cc index 01f7ef55..08146b65 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -18,6 +18,7 @@ */ #include +#include #include "nextpnr.h" #include "placer1.h" #include "router1.h" @@ -201,7 +202,10 @@ void Arch::setDelayScaling(double scale, double offset) // --------------------------------------------------------------- -Arch::Arch(ArchArgs args) : chipName("generic"), args(args) {} +Arch::Arch(ArchArgs args) : chipName("generic"), args(args) { + // Dummy for empty decals + decal_graphics[IdString()]; +} void IdString::initialize_arch(const BaseCtx *ctx) {} @@ -469,7 +473,13 @@ bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); } // --------------------------------------------------------------- -const std::vector &Arch::getDecalGraphics(DecalId decal) const { return decal_graphics.at(decal); } +const std::vector &Arch::getDecalGraphics(DecalId decal) const { + if (!decal_graphics.count(decal)) { + std::cerr << "No decal named " << decal.str(this) << std::endl; + log_error("No decal named %s!\n", decal.c_str(this)); + } + return decal_graphics.at(decal); +} DecalXY Arch::getBelDecal(BelId bel) const { return bels.at(bel).decalxy; } diff --git a/generic/arch_pybindings.cc b/generic/arch_pybindings.cc index eae78c9a..5eb2f2c8 100644 --- a/generic/arch_pybindings.cc +++ b/generic/arch_pybindings.cc @@ -40,6 +40,15 @@ void arch_wrap_python() using namespace PythonConversion; auto arch_cls = class_, boost::noncopyable>("Arch", init()); + + auto dxy_cls = class_>("DecalXY_", no_init); + readwrite_wrapper, + conv_from_str>::def_wrap(dxy_cls, "decal"); + readwrite_wrapper, pass_through>::def_wrap( + dxy_cls, "x"); + readwrite_wrapper, pass_through>::def_wrap( + dxy_cls, "y"); + auto ctx_cls = class_, boost::noncopyable>("Context", no_init) .def("checksum", &Context::checksum) .def("pack", &Context::pack) @@ -127,6 +136,9 @@ void arch_wrap_python() fn_wrapper_0a>::def_wrap(ctx_cls, "archId"); + fn_wrapper_3a, + conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "DecalXY"); + typedef std::unordered_map> CellMap; typedef std::unordered_map> NetMap; @@ -178,13 +190,13 @@ void arch_wrap_python() fn_wrapper_2a_v, pass_through>::def_wrap(ctx_cls, "addDecalGraphic", (arg("decal"), "graphic")); fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "setWireDecal", (arg("wire"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setWireDecal", (arg("wire"), "decalxy")); fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "setPipDecal", (arg("pip"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setPipDecal", (arg("pip"), "decalxy")); fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "setBelDecal", (arg("bel"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setBelDecal", (arg("bel"), "decalxy")); fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "setGroupDecal", (arg("group"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setGroupDecal", (arg("group"), "decalxy")); fn_wrapper_3a_v, conv_from_str, pass_through>::def_wrap(ctx_cls, "setWireAttr", diff --git a/generic/examples/simple.py b/generic/examples/simple.py index b8ca3f78..2628c041 100644 --- a/generic/examples/simple.py +++ b/generic/examples/simple.py @@ -14,6 +14,10 @@ Sq = 4 # "Sparsity" of local to neighbour local wire pips Sl = 8 +# Create graphic elements +# Bels +ctx.addDecalGraphic("bel", GraphicElement(type=TYPE_BOX, style=STYLE_INACTIVE, x1=0, y1=0, x2=0.2, y2=(1/(Z+1))-0.02, z=0)) + def is_io(x, y): return x == 0 or x == X-1 or y == 0 or y == Y-1 @@ -37,7 +41,7 @@ for x in range(X): ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="I", wire="X%dY%dZ%d_I0" % (x, y, z)) ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="EN", wire="X%dY%dZ%d_I1" % (x, y, z)) ctx.addBelOutput(bel="X%dY%d_IO%d" % (x, y, z), name="O", wire="X%dY%dZ%d_Q" % (x, y, z)) - + ctx.setBelDecal(bel="X%dY%d_IO%d" % (x, y, z), decalxy=ctx.DecalXY("bel", 0.6, z * (1/(Z+1)))) else: for z in range(Z): ctx.addBel(name="X%dY%d_SLICE%d" % (x, y, z), type="GENERIC_SLICE", loc=Loc(x, y, z), gb=False) @@ -45,6 +49,7 @@ for x in range(X): for k in range(K): ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="I[%d]" % k, wire="X%dY%dZ%d_I%d" % (x, y, z, k)) ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="Q", wire="X%dY%dZ%d_Q" % (x, y, z)) + ctx.setBelDecal(bel="X%dY%d_SLICE%d" % (x, y, z), decalxy=ctx.DecalXY("bel", 0.6, z * (1/(Z+1)))) for x in range(X): for y in range(Y): diff --git a/gui/pythontab.cc b/gui/pythontab.cc index 827f1907..c83f1ece 100644 --- a/gui/pythontab.cc +++ b/gui/pythontab.cc @@ -96,9 +96,10 @@ void PythonTab::newContext(Context *ctx) console->clear(); pyinterpreter_preinit(); - init_python("nextpnr", !initialized); + init_python("nextpnr", true); pyinterpreter_initialize(); pyinterpreter_aquire(); + init_python("nextpnr", false); python_export_global("ctx", ctx); pyinterpreter_release();