From 6455b5dd2661fd76bccc32a42577fecd4e43752d Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 11 Apr 2023 10:05:33 +0200 Subject: viaduct: Add support for GUIs Signed-off-by: gatecat --- docs/generic.md | 10 +++---- generic/arch.cc | 60 ++++++++++++++++++++++++++++---------- generic/arch.h | 10 +++---- generic/arch_pybindings.cc | 44 +++++++++++++++------------- generic/archdefs.h | 12 +++++++- generic/main.cc | 4 +++ generic/viaduct/example/example.cc | 28 ++++++++++++++++++ generic/viaduct_api.h | 1 + gui/generic/mainwindow.cc | 7 +++-- machxo2/arch.cc | 9 +++--- machxo2/bitstream.cc | 11 ++++--- 11 files changed, 135 insertions(+), 61 deletions(-) diff --git a/docs/generic.md b/docs/generic.md index 108d41d7..acd7ca4e 100644 --- a/docs/generic.md +++ b/docs/generic.md @@ -56,14 +56,14 @@ Adds an input, output or inout pin to a bel, with an associated wire. Note that Add a bel, wire, pip or subgroup to a group, which will be created if it doesn't already exist. Groups are purely for visual presentation purposes in the user interface and are not used by any place-and-route algorithms. -### void addDecalGraphic(DecalId decal, const GraphicElement &graphic); +### void addDecalGraphic(IdStringList decal, const GraphicElement &graphic); Add a graphic element to a _decal_, a reusable drawing that may be used to represent multiple wires, pips, bels or groups in the UI (with different offsets). The decal will be created if it doesn't already exist -### void setWireDecal(WireId wire, DecalXY decalxy); -### void setPipDecal(PipId pip, DecalXY decalxy); -### void setBelDecal(BelId bel, DecalXY decalxy); -### void setGroupDecal(GroupId group, DecalXY decalxy); +### void setWireDecal(WireId wire, float x, float y, IdStringList decal); +### void setPipDecal(PipId pip, float x, float y, IdStringList decal); +### void setBelDecal(BelId bel, float x, float y, IdStringList decal); +### void setGroupDecal(GroupId group, float x, float y, IdStringList decal); Sets the decal ID and offset for a wire, bel, pip or group in the UI. diff --git a/generic/arch.cc b/generic/arch.cc index c0575b87..238fb9fc 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -161,33 +161,47 @@ void Arch::addGroupPip(IdStringList group, PipId pip) { groups[group].pips.push_ void Arch::addGroupGroup(IdStringList group, IdStringList grp) { groups[group].groups.push_back(grp); } -void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic) +void Arch::addDecalGraphic(IdStringList decal, const GraphicElement &graphic) { - decal_graphics[decal].push_back(graphic); + decal_graphics[DecalId(decal, false)].push_back(graphic); // inactive variant + decal_graphics[DecalId(decal, true)].push_back(graphic); // active variant + + GraphicElement &active = decal_graphics[DecalId(decal, true)].back(); + if (active.style == GraphicElement::STYLE_INACTIVE) + active.style = GraphicElement::STYLE_ACTIVE; + refreshUi(); } -void Arch::setWireDecal(WireId wire, DecalXY decalxy) +void Arch::setWireDecal(WireId wire, float x, float y, IdStringList decal) { - wires.at(wire.index).decalxy = decalxy; + wires.at(wire.index).decalxy.x = x; + wires.at(wire.index).decalxy.y = y; + wires.at(wire.index).decalxy.decal = DecalId(decal, false); refreshUiWire(wire); } -void Arch::setPipDecal(PipId pip, DecalXY decalxy) +void Arch::setPipDecal(PipId pip, float x, float y, IdStringList decal) { - pips.at(pip.index).decalxy = decalxy; + pips.at(pip.index).decalxy.x = x; + pips.at(pip.index).decalxy.y = y; + pips.at(pip.index).decalxy.decal = DecalId(decal, false); refreshUiPip(pip); } -void Arch::setBelDecal(BelId bel, DecalXY decalxy) +void Arch::setBelDecal(BelId bel, float x, float y, IdStringList decal) { - bels.at(bel.index).decalxy = decalxy; + bels.at(bel.index).decalxy.x = x; + bels.at(bel.index).decalxy.y = y; + bels.at(bel.index).decalxy.decal = DecalId(decal, false); refreshUiBel(bel); } -void Arch::setGroupDecal(GroupId group, DecalXY decalxy) +void Arch::setGroupDecal(GroupId group, float x, float y, IdStringList decal) { - groups[group].decalxy = decalxy; + groups.at(group).decalxy.x = x; + groups.at(group).decalxy.y = y; + groups.at(group).decalxy.decal = DecalId(decal, false); refreshUiGroup(group); } @@ -248,7 +262,8 @@ void Arch::addCellBelPinMapping(IdString cell, IdString cell_pin, IdString bel_p Arch::Arch(ArchArgs args) : chipName("generic"), args(args) { // Dummy for empty decals - decal_graphics[DecalId()]; + decal_graphics[DecalId(IdStringList(), false)]; + decal_graphics[DecalId(IdStringList(), true)]; } void IdString::initialize_arch(const BaseCtx *ctx) {} @@ -643,16 +658,31 @@ bool Arch::route() const std::vector &Arch::getDecalGraphics(DecalId decal) const { if (!decal_graphics.count(decal)) { - std::cerr << "No decal named " << decal.str(getCtx()) << std::endl; + std::cerr << "No decal named " << decal.name.str(getCtx()) << std::endl; } return decal_graphics.at(decal); } -DecalXY Arch::getBelDecal(BelId bel) const { return bel_info(bel).decalxy; } +DecalXY Arch::getBelDecal(BelId bel) const +{ + DecalXY result = bel_info(bel).decalxy; + result.decal.active = getBoundBelCell(bel) != nullptr; + return result; +} -DecalXY Arch::getWireDecal(WireId wire) const { return wire_info(wire).decalxy; } +DecalXY Arch::getWireDecal(WireId wire) const +{ + DecalXY result = wire_info(wire).decalxy; + result.decal.active = getBoundWireNet(wire) != nullptr; + return result; +} -DecalXY Arch::getPipDecal(PipId pip) const { return pip_info(pip).decalxy; } +DecalXY Arch::getPipDecal(PipId pip) const +{ + DecalXY result = pip_info(pip).decalxy; + result.decal.active = getBoundPipNet(pip) != nullptr; + return result; +} DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decalxy; } diff --git a/generic/arch.h b/generic/arch.h index 19a0a078..40994ad0 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -211,11 +211,11 @@ struct Arch : BaseArch void addGroupPip(IdStringList group, PipId pip); void addGroupGroup(IdStringList group, IdStringList grp); - void addDecalGraphic(DecalId decal, const GraphicElement &graphic); - void setWireDecal(WireId wire, DecalXY decalxy); - void setPipDecal(PipId pip, DecalXY decalxy); - void setBelDecal(BelId bel, DecalXY decalxy); - void setGroupDecal(GroupId group, DecalXY decalxy); + void addDecalGraphic(IdStringList decal, const GraphicElement &graphic); + void setWireDecal(WireId wire, float x, float y, IdStringList decal); + void setPipDecal(PipId pip, float x, float y, IdStringList decal); + void setBelDecal(BelId bel, float x, float y, IdStringList decal); + void setGroupDecal(GroupId group, float x, float y, IdStringList decal); void setWireAttr(WireId wire, IdString key, const std::string &value); void setPipAttr(PipId pip, IdString key, const std::string &value); diff --git a/generic/arch_pybindings.cc b/generic/arch_pybindings.cc index a5a0bed9..f067936c 100644 --- a/generic/arch_pybindings.cc +++ b/generic/arch_pybindings.cc @@ -55,14 +55,6 @@ void arch_wrap_python(py::module &m) auto arch_cls = py::class_(m, "Arch").def(py::init()); - auto dxy_cls = py::class_>(m, "DecalXY_"); - 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 = py::class_(m, "Context") .def("checksum", &Context::checksum) .def("pack", &Context::pack) @@ -72,9 +64,6 @@ void arch_wrap_python(py::module &m) auto belpin_cls = py::class_(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); - fn_wrapper_3a, - conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "DecalXY"); - typedef dict> CellMap; typedef dict> NetMap; typedef dict HierarchyMap; @@ -121,16 +110,29 @@ void arch_wrap_python(py::module &m) fn_wrapper_2a_v, conv_from_str>::def_wrap(ctx_cls, "addGroupGroup", "group"_a, "grp"_a); - fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "addDecalGraphic", (py::arg("decal"), "graphic")); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setWireDecal", "wire"_a, "decalxy"_a); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setPipDecal", "pip"_a, "decalxy"_a); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setBelDecal", "bel"_a, "decalxy"_a); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setGroupDecal", "group"_a, "decalxy"_a); + fn_wrapper_2a_v, pass_through>::def_wrap(ctx_cls, "addDecalGraphic", + (py::arg("decal"), "graphic")); + fn_wrapper_4a_v, + pass_through, pass_through, conv_from_str>::def_wrap(ctx_cls, + "setWireDecal", + "wire"_a, "x"_a, + "y"_a, "decal"_a); + fn_wrapper_4a_v, + pass_through, pass_through, conv_from_str>::def_wrap(ctx_cls, + "setPipDecal", + "pip"_a, "x"_a, + "y"_a, "decal"_a); + fn_wrapper_4a_v, + pass_through, pass_through, conv_from_str>::def_wrap(ctx_cls, + "setBelDecal", + "bel"_a, "x"_a, + "y"_a, "decal"_a); + fn_wrapper_4a_v, + pass_through, pass_through, conv_from_str>::def_wrap(ctx_cls, + "setGroupDecal", + "group"_a, "x"_a, + "y"_a, "decal"_a); fn_wrapper_3a_v, conv_from_str, pass_through>::def_wrap(ctx_cls, "setWireAttr", "wire"_a, diff --git a/generic/archdefs.h b/generic/archdefs.h index 4e91ffd3..374ddeb0 100644 --- a/generic/archdefs.h +++ b/generic/archdefs.h @@ -64,8 +64,18 @@ struct PipId unsigned int hash() const { return index; } }; +struct DecalId +{ + IdStringList name; + bool active = false; + DecalId() : name(), active(false){}; + DecalId(IdStringList name, bool active) : name(name), active(active){}; + bool operator==(const DecalId &other) const { return name == other.name && active == other.active; } + bool operator!=(const DecalId &other) const { return name != other.name || active != other.active; } + unsigned int hash() const { return mkhash(name.hash(), active); } +}; + typedef IdStringList GroupId; -typedef IdStringList DecalId; typedef IdString BelBucketId; typedef IdString ClusterId; diff --git a/generic/main.cc b/generic/main.cc index 3ee1c790..7aece569 100644 --- a/generic/main.cc +++ b/generic/main.cc @@ -86,9 +86,13 @@ std::unique_ptr GenericCommandHandler::createContext(dictuarch = std::move(uarch); + if (vm.count("gui")) + ctx->uarch->with_gui = true; ctx->uarch->init(ctx.get()); } else if (vm.count("vopt")) { log_error("Viaduct options passed in non-viaduct mode!\n"); + } else if (vm.count("gui")) { + log_error("nextpnr-generic GUI only supported in viaduct mode!\n"); } return ctx; } diff --git a/generic/viaduct/example/example.cc b/generic/viaduct/example/example.cc index 7a61a594..7de0404b 100644 --- a/generic/viaduct/example/example.cc +++ b/generic/viaduct/example/example.cc @@ -38,6 +38,8 @@ struct ExampleImpl : ViaductAPI init_uarch_constids(ctx); ViaductAPI::init(ctx); h.init(ctx); + if (with_gui) + init_bel_decals(); init_wires(); init_bels(); init_pips(); @@ -150,6 +152,28 @@ struct ExampleImpl : ViaductAPI IdStringList name = IdStringList::concat(ctx->getWireName(dst), ctx->getWireName(src)); return ctx->addPip(name, ctx->id("PIP"), src, dst, delay, loc); } + + static constexpr float lut_x1 = 0.8f; + static constexpr float lut_w = 0.07f; + static constexpr float ff_x1 = 0.9f; + static constexpr float ff_w = 0.05f; + static constexpr float bel_y1 = 0.2f; + static constexpr float bel_h = 0.03f; + static constexpr float bel_dy = 0.05f; + void init_bel_decals() + { + for (int z = 0; z < N; z++) { + float y1 = bel_y1 + z * bel_dy; + float y2 = y1 + bel_h; + ctx->addDecalGraphic(IdStringList(ctx->idf("LUT%d", z)), + GraphicElement(GraphicElement::TYPE_BOX, GraphicElement::STYLE_INACTIVE, lut_x1, y1, + lut_x1 + lut_w, y2, 10.0)); + ctx->addDecalGraphic(IdStringList(ctx->idf("FF%d", z)), + GraphicElement(GraphicElement::TYPE_BOX, GraphicElement::STYLE_INACTIVE, ff_x1, y1, + ff_x1 + ff_w, y2, 10.0)); + } + } + // Create LUT and FF bels in a logic tile void add_slice_bels(int x, int y) { @@ -169,6 +193,10 @@ struct ExampleImpl : ViaductAPI ctx->addBelInput(dff, id_CLK, w.clk.at(z)); ctx->addBelInput(dff, id_D, w.d.at(z)); ctx->addBelOutput(dff, id_Q, w.q.at(z)); + if (with_gui) { + ctx->setBelDecal(lut, x, y, IdStringList(ctx->idf("LUT%d", z))); + ctx->setBelDecal(dff, x, y, IdStringList(ctx->idf("FF%d", z))); + } } } // Create bels according to tile type diff --git a/generic/viaduct_api.h b/generic/viaduct_api.h index 3caa0ba1..6d6423b6 100644 --- a/generic/viaduct_api.h +++ b/generic/viaduct_api.h @@ -55,6 +55,7 @@ struct ViaductAPI { virtual void init(Context *ctx); Context *ctx; + bool with_gui = false; // --- Bel functions --- // Called when a bel is placed/unplaced (with cell=nullptr for a unbind) diff --git a/gui/generic/mainwindow.cc b/gui/generic/mainwindow.cc index 5697718c..aeb5c04b 100644 --- a/gui/generic/mainwindow.cc +++ b/gui/generic/mainwindow.cc @@ -30,8 +30,6 @@ MainWindow::MainWindow(std::unique_ptr context, CommandHandler *handler : BaseMainWindow(std::move(context), handler, parent) { initMainResource(); - QMessageBox::critical(0, "Error - FIXME", "No GUI support for nextpnr-generic"); - std::exit(1); } MainWindow::~MainWindow() {} @@ -44,6 +42,9 @@ void MainWindow::newContext(Context *ctx) void MainWindow::createMenu() {} -void MainWindow::new_proj() {} +void MainWindow::new_proj() { + QMessageBox::critical(0, "Error", "Creating a new project not supported in Viaduct mode, please re-start from command line."); + std::exit(1); +} NEXTPNR_NAMESPACE_END diff --git a/machxo2/arch.cc b/machxo2/arch.cc index f2c87888..022fb8ff 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -315,9 +315,9 @@ IdStringList Arch::getPipName(PipId pip) const { auto &pip_data = tile_info(pip)->pip_data[pip.index]; WireId src = getPipSrcWire(pip), dst = getPipDstWire(pip); - std::string pip_name = stringf("%d_%d_%s->%d_%d_%s", pip_data.src.x, pip_data.src.y, - get_wire_basename(src).c_str(this), pip_data.dst.x, pip_data.dst.y, - get_wire_basename(dst).c_str(this)); + std::string pip_name = + stringf("%d_%d_%s->%d_%d_%s", pip_data.src.x, pip_data.src.y, get_wire_basename(src).c_str(this), + pip_data.dst.x, pip_data.dst.y, get_wire_basename(dst).c_str(this)); std::array ids{x_ids.at(pip.location.x), y_ids.at(pip.location.y), id(pip_name)}; return IdStringList(ids); @@ -490,8 +490,7 @@ std::vector> Arch::get_tiles_at_loc(int row, std::vector> ret; auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; for (auto &tn : tileloc.tile_names) { - ret.push_back(std::make_pair(tn.name.get(), - chip_info->tiletype_names[tn.type_idx].get())); + ret.push_back(std::make_pair(tn.name.get(), chip_info->tiletype_names[tn.type_idx].get())); } return ret; } diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index e6b1bb17..5b0e8664 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -176,12 +176,11 @@ static std::string get_pic_tile(Context *ctx, BelId bel) { static const std::set pio_t = {"PIC_T0", "PIC_T0_256", "PIC_TS0"}; static const std::set pio_b = {"PIC_B0", "PIC_B0_256", "PIC_BS0_256"}; - static const std::set pio_l = {"PIC_L0", "PIC_L1", "PIC_L2", "PIC_L3", "PIC_LS0", - "PIC_L0_VREF3", "PIC_L0_VREF4", "PIC_L0_VREF5", - "PIC_L1_VREF3", "PIC_L1_VREF4", "PIC_L1_VREF5", - "PIC_L2_VREF4", "PIC_L2_VREF5", - "PIC_L3_VREF4", "PIC_L3_VREF5"}; - static const std::set pio_r = {"PIC_R0", "PIC_R1", "PIC_RS0", + static const std::set pio_l = {"PIC_L0", "PIC_L1", "PIC_L2", "PIC_L3", + "PIC_LS0", "PIC_L0_VREF3", "PIC_L0_VREF4", "PIC_L0_VREF5", + "PIC_L1_VREF3", "PIC_L1_VREF4", "PIC_L1_VREF5", "PIC_L2_VREF4", + "PIC_L2_VREF5", "PIC_L3_VREF4", "PIC_L3_VREF5"}; + static const std::set pio_r = {"PIC_R0", "PIC_R1", "PIC_RS0", "PIC_R0_256", "PIC_R1_640", "PIC_RS0_256"}; std::string pio_name = ctx->tile_info(bel)->bel_data[bel.index].name.get(); -- cgit v1.2.3