viaduct: Add support for GUIs

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2023-04-11 10:05:33 +02:00 committed by myrtle
parent 9bcefe46a8
commit 6455b5dd26
11 changed files with 135 additions and 61 deletions

View File

@ -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. 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 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 setWireDecal(WireId wire, float x, float y, IdStringList decal);
### void setPipDecal(PipId pip, DecalXY decalxy); ### void setPipDecal(PipId pip, float x, float y, IdStringList decal);
### void setBelDecal(BelId bel, DecalXY decalxy); ### void setBelDecal(BelId bel, float x, float y, IdStringList decal);
### void setGroupDecal(GroupId group, DecalXY decalxy); ### 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. Sets the decal ID and offset for a wire, bel, pip or group in the UI.

View File

@ -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::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(); 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); 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); 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); 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); 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) Arch::Arch(ArchArgs args) : chipName("generic"), args(args)
{ {
// Dummy for empty decals // Dummy for empty decals
decal_graphics[DecalId()]; decal_graphics[DecalId(IdStringList(), false)];
decal_graphics[DecalId(IdStringList(), true)];
} }
void IdString::initialize_arch(const BaseCtx *ctx) {} void IdString::initialize_arch(const BaseCtx *ctx) {}
@ -643,16 +658,31 @@ bool Arch::route()
const std::vector<GraphicElement> &Arch::getDecalGraphics(DecalId decal) const const std::vector<GraphicElement> &Arch::getDecalGraphics(DecalId decal) const
{ {
if (!decal_graphics.count(decal)) { 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); 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; } DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decalxy; }

View File

@ -211,11 +211,11 @@ struct Arch : BaseArch<ArchRanges>
void addGroupPip(IdStringList group, PipId pip); void addGroupPip(IdStringList group, PipId pip);
void addGroupGroup(IdStringList group, IdStringList grp); void addGroupGroup(IdStringList group, IdStringList grp);
void addDecalGraphic(DecalId decal, const GraphicElement &graphic); void addDecalGraphic(IdStringList decal, const GraphicElement &graphic);
void setWireDecal(WireId wire, DecalXY decalxy); void setWireDecal(WireId wire, float x, float y, IdStringList decal);
void setPipDecal(PipId pip, DecalXY decalxy); void setPipDecal(PipId pip, float x, float y, IdStringList decal);
void setBelDecal(BelId bel, DecalXY decalxy); void setBelDecal(BelId bel, float x, float y, IdStringList decal);
void setGroupDecal(GroupId group, DecalXY decalxy); void setGroupDecal(GroupId group, float x, float y, IdStringList decal);
void setWireAttr(WireId wire, IdString key, const std::string &value); void setWireAttr(WireId wire, IdString key, const std::string &value);
void setPipAttr(PipId pip, IdString key, const std::string &value); void setPipAttr(PipId pip, IdString key, const std::string &value);

View File

@ -55,14 +55,6 @@ void arch_wrap_python(py::module &m)
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>()); auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
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(
dxy_cls, "x");
readwrite_wrapper<DecalXY, decltype(&DecalXY::y), &DecalXY::y, pass_through<float>, pass_through<float>>::def_wrap(
dxy_cls, "y");
auto ctx_cls = py::class_<Context, Arch>(m, "Context") auto ctx_cls = py::class_<Context, Arch>(m, "Context")
.def("checksum", &Context::checksum) .def("checksum", &Context::checksum)
.def("pack", &Context::pack) .def("pack", &Context::pack)
@ -72,9 +64,6 @@ void arch_wrap_python(py::module &m)
auto belpin_cls = auto belpin_cls =
py::class_<BelPin>(m, "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);
fn_wrapper_3a<Context, decltype(&Context::constructDecalXY), &Context::constructDecalXY, wrap_context<DecalXY>,
conv_from_str<DecalId>, pass_through<float>, pass_through<float>>::def_wrap(ctx_cls, "DecalXY");
typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap; typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap; typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef dict<IdString, HierarchicalCell> HierarchyMap; typedef dict<IdString, HierarchicalCell> HierarchyMap;
@ -121,16 +110,29 @@ void arch_wrap_python(py::module &m)
fn_wrapper_2a_v<Context, decltype(&Context::addGroupGroup), &Context::addGroupGroup, conv_from_str<IdStringList>, fn_wrapper_2a_v<Context, decltype(&Context::addGroupGroup), &Context::addGroupGroup, conv_from_str<IdStringList>,
conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addGroupGroup", "group"_a, "grp"_a); conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addGroupGroup", "group"_a, "grp"_a);
fn_wrapper_2a_v<Context, decltype(&Context::addDecalGraphic), &Context::addDecalGraphic, conv_from_str<DecalId>, fn_wrapper_2a_v<Context, decltype(&Context::addDecalGraphic), &Context::addDecalGraphic,
pass_through<GraphicElement>>::def_wrap(ctx_cls, "addDecalGraphic", (py::arg("decal"), "graphic")); conv_from_str<IdStringList>, pass_through<GraphicElement>>::def_wrap(ctx_cls, "addDecalGraphic",
fn_wrapper_2a_v<Context, decltype(&Context::setWireDecal), &Context::setWireDecal, conv_from_str<WireId>, (py::arg("decal"), "graphic"));
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setWireDecal", "wire"_a, "decalxy"_a); fn_wrapper_4a_v<Context, decltype(&Context::setWireDecal), &Context::setWireDecal, conv_from_str<WireId>,
fn_wrapper_2a_v<Context, decltype(&Context::setPipDecal), &Context::setPipDecal, conv_from_str<PipId>, pass_through<float>, pass_through<float>, conv_from_str<IdStringList>>::def_wrap(ctx_cls,
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setPipDecal", "pip"_a, "decalxy"_a); "setWireDecal",
fn_wrapper_2a_v<Context, decltype(&Context::setBelDecal), &Context::setBelDecal, conv_from_str<BelId>, "wire"_a, "x"_a,
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setBelDecal", "bel"_a, "decalxy"_a); "y"_a, "decal"_a);
fn_wrapper_2a_v<Context, decltype(&Context::setGroupDecal), &Context::setGroupDecal, conv_from_str<DecalId>, fn_wrapper_4a_v<Context, decltype(&Context::setPipDecal), &Context::setPipDecal, conv_from_str<PipId>,
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setGroupDecal", "group"_a, "decalxy"_a); pass_through<float>, pass_through<float>, conv_from_str<IdStringList>>::def_wrap(ctx_cls,
"setPipDecal",
"pip"_a, "x"_a,
"y"_a, "decal"_a);
fn_wrapper_4a_v<Context, decltype(&Context::setBelDecal), &Context::setBelDecal, conv_from_str<BelId>,
pass_through<float>, pass_through<float>, conv_from_str<IdStringList>>::def_wrap(ctx_cls,
"setBelDecal",
"bel"_a, "x"_a,
"y"_a, "decal"_a);
fn_wrapper_4a_v<Context, decltype(&Context::setGroupDecal), &Context::setGroupDecal, conv_from_str<GroupId>,
pass_through<float>, pass_through<float>, conv_from_str<IdStringList>>::def_wrap(ctx_cls,
"setGroupDecal",
"group"_a, "x"_a,
"y"_a, "decal"_a);
fn_wrapper_3a_v<Context, decltype(&Context::setWireAttr), &Context::setWireAttr, conv_from_str<WireId>, fn_wrapper_3a_v<Context, decltype(&Context::setWireAttr), &Context::setWireAttr, conv_from_str<WireId>,
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setWireAttr", "wire"_a, conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setWireAttr", "wire"_a,

View File

@ -64,8 +64,18 @@ struct PipId
unsigned int hash() const { return index; } 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 GroupId;
typedef IdStringList DecalId;
typedef IdString BelBucketId; typedef IdString BelBucketId;
typedef IdString ClusterId; typedef IdString ClusterId;

View File

@ -86,9 +86,13 @@ std::unique_ptr<Context> GenericCommandHandler::createContext(dict<std::string,
log_error("Unknown viaduct uarch '%s'; available options: '%s'\n", uarch_name.c_str(), all_uarches.c_str()); log_error("Unknown viaduct uarch '%s'; available options: '%s'\n", uarch_name.c_str(), all_uarches.c_str());
} }
ctx->uarch = std::move(uarch); ctx->uarch = std::move(uarch);
if (vm.count("gui"))
ctx->uarch->with_gui = true;
ctx->uarch->init(ctx.get()); ctx->uarch->init(ctx.get());
} else if (vm.count("vopt")) { } else if (vm.count("vopt")) {
log_error("Viaduct options passed in non-viaduct mode!\n"); 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; return ctx;
} }

View File

@ -38,6 +38,8 @@ struct ExampleImpl : ViaductAPI
init_uarch_constids(ctx); init_uarch_constids(ctx);
ViaductAPI::init(ctx); ViaductAPI::init(ctx);
h.init(ctx); h.init(ctx);
if (with_gui)
init_bel_decals();
init_wires(); init_wires();
init_bels(); init_bels();
init_pips(); init_pips();
@ -150,6 +152,28 @@ struct ExampleImpl : ViaductAPI
IdStringList name = IdStringList::concat(ctx->getWireName(dst), ctx->getWireName(src)); IdStringList name = IdStringList::concat(ctx->getWireName(dst), ctx->getWireName(src));
return ctx->addPip(name, ctx->id("PIP"), src, dst, delay, loc); 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 // Create LUT and FF bels in a logic tile
void add_slice_bels(int x, int y) 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_CLK, w.clk.at(z));
ctx->addBelInput(dff, id_D, w.d.at(z)); ctx->addBelInput(dff, id_D, w.d.at(z));
ctx->addBelOutput(dff, id_Q, w.q.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 // Create bels according to tile type

View File

@ -55,6 +55,7 @@ struct ViaductAPI
{ {
virtual void init(Context *ctx); virtual void init(Context *ctx);
Context *ctx; Context *ctx;
bool with_gui = false;
// --- Bel functions --- // --- Bel functions ---
// Called when a bel is placed/unplaced (with cell=nullptr for a unbind) // Called when a bel is placed/unplaced (with cell=nullptr for a unbind)

View File

@ -30,8 +30,6 @@ MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler
: BaseMainWindow(std::move(context), handler, parent) : BaseMainWindow(std::move(context), handler, parent)
{ {
initMainResource(); initMainResource();
QMessageBox::critical(0, "Error - FIXME", "No GUI support for nextpnr-generic");
std::exit(1);
} }
MainWindow::~MainWindow() {} MainWindow::~MainWindow() {}
@ -44,6 +42,9 @@ void MainWindow::newContext(Context *ctx)
void MainWindow::createMenu() {} 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 NEXTPNR_NAMESPACE_END

View File

@ -315,9 +315,9 @@ IdStringList Arch::getPipName(PipId pip) const
{ {
auto &pip_data = tile_info(pip)->pip_data[pip.index]; auto &pip_data = tile_info(pip)->pip_data[pip.index];
WireId src = getPipSrcWire(pip), dst = getPipDstWire(pip); 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, std::string pip_name =
get_wire_basename(src).c_str(this), pip_data.dst.x, pip_data.dst.y, stringf("%d_%d_%s->%d_%d_%s", pip_data.src.x, pip_data.src.y, get_wire_basename(src).c_str(this),
get_wire_basename(dst).c_str(this)); pip_data.dst.x, pip_data.dst.y, get_wire_basename(dst).c_str(this));
std::array<IdString, 3> ids{x_ids.at(pip.location.x), y_ids.at(pip.location.y), id(pip_name)}; std::array<IdString, 3> ids{x_ids.at(pip.location.x), y_ids.at(pip.location.y), id(pip_name)};
return IdStringList(ids); return IdStringList(ids);
@ -490,8 +490,7 @@ std::vector<std::pair<std::string, std::string>> Arch::get_tiles_at_loc(int row,
std::vector<std::pair<std::string, std::string>> ret; std::vector<std::pair<std::string, std::string>> ret;
auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; auto &tileloc = chip_info->tile_info[row * chip_info->width + col];
for (auto &tn : tileloc.tile_names) { for (auto &tn : tileloc.tile_names) {
ret.push_back(std::make_pair(tn.name.get(), ret.push_back(std::make_pair(tn.name.get(), chip_info->tiletype_names[tn.type_idx].get()));
chip_info->tiletype_names[tn.type_idx].get()));
} }
return ret; return ret;
} }

View File

@ -176,12 +176,11 @@ static std::string get_pic_tile(Context *ctx, BelId bel)
{ {
static const std::set<std::string> pio_t = {"PIC_T0", "PIC_T0_256", "PIC_TS0"}; static const std::set<std::string> pio_t = {"PIC_T0", "PIC_T0_256", "PIC_TS0"};
static const std::set<std::string> pio_b = {"PIC_B0", "PIC_B0_256", "PIC_BS0_256"}; static const std::set<std::string> pio_b = {"PIC_B0", "PIC_B0_256", "PIC_BS0_256"};
static const std::set<std::string> pio_l = {"PIC_L0", "PIC_L1", "PIC_L2", "PIC_L3", "PIC_LS0", static const std::set<std::string> pio_l = {"PIC_L0", "PIC_L1", "PIC_L2", "PIC_L3",
"PIC_L0_VREF3", "PIC_L0_VREF4", "PIC_L0_VREF5", "PIC_LS0", "PIC_L0_VREF3", "PIC_L0_VREF4", "PIC_L0_VREF5",
"PIC_L1_VREF3", "PIC_L1_VREF4", "PIC_L1_VREF5", "PIC_L1_VREF3", "PIC_L1_VREF4", "PIC_L1_VREF5", "PIC_L2_VREF4",
"PIC_L2_VREF4", "PIC_L2_VREF5", "PIC_L2_VREF5", "PIC_L3_VREF4", "PIC_L3_VREF5"};
"PIC_L3_VREF4", "PIC_L3_VREF5"}; static const std::set<std::string> pio_r = {"PIC_R0", "PIC_R1", "PIC_RS0",
static const std::set<std::string> pio_r = {"PIC_R0", "PIC_R1", "PIC_RS0",
"PIC_R0_256", "PIC_R1_640", "PIC_RS0_256"}; "PIC_R0_256", "PIC_R1_640", "PIC_RS0_256"};
std::string pio_name = ctx->tile_info(bel)->bel_data[bel.index].name.get(); std::string pio_name = ctx->tile_info(bel)->bel_data[bel.index].name.get();