This commit is contained in:
Lunaphied 2026-06-10 08:58:11 -04:00 committed by GitHub
commit d0c8dd2247
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 72 additions and 94 deletions

View File

@ -238,14 +238,7 @@ else()
endif()
if (BUILD_GUI)
# Find the Qt6/5 libraries
find_package(Qt6 COMPONENTS Core Widgets OpenGL OpenGLWidgets QUIET)
if (Qt6_FOUND)
message(STATUS "Using Qt6")
else()
message(STATUS "Using Qt5")
find_package(Qt5 COMPONENTS Core Widgets OpenGL REQUIRED)
endif()
# For higher quality backtraces
set(CMAKE_ENABLE_EXPORTS ON)

View File

@ -195,7 +195,7 @@ sudo make install
### GUI
The nextpnr GUI is not built by default, to reduce the number of dependencies for a standard headless build. To enable it, add `-DBUILD_GUI=ON` to the CMake command line and ensure that Qt5/Qt6 and OpenGL are available:
The nextpnr GUI is not built by default, to reduce the number of dependencies for a standard headless build. To enable it, add `-DBUILD_GUI=ON` to the CMake command line and ensure that Qt6 and OpenGL are available:
For Qt6:
- On Ubuntu 22.04 LTS or later, install `qt6-base-dev`
@ -203,13 +203,6 @@ For Qt6:
- For Homebrew, install `qt6` and add qt6 in path: `echo 'export PATH="/usr/local/opt/qt/bin:$PATH"' >> ~/.bash_profile`
` - this change is effective in next terminal session, so please re-open terminal window before building
For Qt5:
- On Ubuntu 22.04 LTS, install `qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools`
- On other Ubuntu versions, install `qt5-default`
- For MSVC vcpkg, install `qt5-base` (32-bit) or `qt5-base:x64-windows` (64-bit)
- For Homebrew, install `qt5` and add qt5 in path: `echo 'export PATH="/usr/local/opt/qt/bin:$PATH"' >> ~/.bash_profile`
` - this change is effective in next terminal session, so please re-open terminal window before building
### Multiple architectures
To build nextpnr for multiple architectures at once, a semicolon-separated list can be used with `-DARCH`.

View File

@ -164,7 +164,6 @@ class HeAPPlacer
HeAPPlacer(Context *ctx, PlacerHeapCfg cfg)
: ctx(ctx), cfg(cfg), fast_bels(ctx, /*check_bel_available=*/true, -1), tmg(ctx)
{
Eigen::initParallel();
tmg.setup_only = true;
tmg.setup();

View File

@ -27,17 +27,10 @@ set(GUI_SOURCES
${family}/mainwindow.h
)
if (Qt6_FOUND)
qt6_add_resources(GUI_QT_RESOURCES
base.qrc
${family}/nextpnr.qrc
)
else()
qt5_add_resources(GUI_QT_RESOURCES
base.qrc
${family}/nextpnr.qrc
)
endif()
qt6_add_resources(GUI_QT_RESOURCES
base.qrc
${family}/nextpnr.qrc
)
add_library(nextpnr-${target}-gui OBJECT
${GUI_SOURCES}

View File

@ -32,6 +32,8 @@
NEXTPNR_NAMESPACE_BEGIN
using QtType = QMetaType::Type;
TreeView::TreeView(QWidget *parent) : QTreeView(parent) {}
TreeView::~TreeView() {}
@ -630,27 +632,27 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
BelId bel = ctx->getBelByName(c);
QtProperty *topItem = addTopLevelProperty("Bel");
addProperty(topItem, QVariant::String, "Name", ctx->nameOfBel(bel));
addProperty(topItem, QVariant::String, "Type", ctx->getBelType(bel).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkBelAvail(bel));
addProperty(topItem, QVariant::String, "Bound Cell", ctx->nameOf(ctx->getBoundBelCell(bel)), ElementType::CELL);
addProperty(topItem, QVariant::String, "Bound Cell Type",
addProperty(topItem, QtType::QString, "Name", ctx->nameOfBel(bel));
addProperty(topItem, QtType::QString, "Type", ctx->getBelType(bel).c_str(ctx));
addProperty(topItem, QtType::Bool, "Available", ctx->checkBelAvail(bel));
addProperty(topItem, QtType::QString, "Bound Cell", ctx->nameOf(ctx->getBoundBelCell(bel)), ElementType::CELL);
addProperty(topItem, QtType::QString, "Bound Cell Type",
ctx->getBoundBelCell(bel) ? ctx->getBoundBelCell(bel)->type.c_str(ctx) : "");
addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->nameOf(ctx->getConflictingBelCell(bel)),
addProperty(topItem, QtType::QString, "Conflicting Cell", ctx->nameOf(ctx->getConflictingBelCell(bel)),
ElementType::CELL);
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : ctx->getBelAttrs(bel)) {
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
addProperty(attrsItem, QtType::QString, item.first.c_str(ctx), item.second.c_str());
}
QtProperty *belpinsItem = addSubGroup(topItem, "Ports");
for (const auto &item : ctx->getBelPins(bel)) {
QtProperty *portInfoItem = addSubGroup(belpinsItem, item.c_str(ctx));
addProperty(portInfoItem, QVariant::String, "Name", item.c_str(ctx));
addProperty(portInfoItem, QVariant::Int, "Type", int(ctx->getBelPinType(bel, item)));
addProperty(portInfoItem, QtType::QString, "Name", item.c_str(ctx));
addProperty(portInfoItem, QtType::Int, "Type", int(ctx->getBelPinType(bel, item)));
WireId wire = ctx->getBelPinWire(bel, item);
addProperty(portInfoItem, QVariant::String, "Wire", ctx->nameOfWire(wire), ElementType::WIRE);
addProperty(portInfoItem, QtType::QString, "Wire", ctx->nameOfWire(wire), ElementType::WIRE);
}
} else if (type == ElementType::WIRE) {
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
@ -659,27 +661,27 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
WireId wire = ctx->getWireByName(c);
QtProperty *topItem = addTopLevelProperty("Wire");
addProperty(topItem, QVariant::String, "Name", ctx->nameOfWire(wire));
addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->nameOfWire(ctx->getConflictingWireWire(wire)),
addProperty(topItem, QtType::QString, "Name", ctx->nameOfWire(wire));
addProperty(topItem, QtType::QString, "Type", ctx->getWireType(wire).c_str(ctx));
addProperty(topItem, QtType::Bool, "Available", ctx->checkWireAvail(wire));
addProperty(topItem, QtType::QString, "Bound Net", ctx->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET);
addProperty(topItem, QtType::QString, "Conflicting Wire", ctx->nameOfWire(ctx->getConflictingWireWire(wire)),
ElementType::WIRE);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
addProperty(topItem, QtType::QString, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
ElementType::NET);
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : ctx->getWireAttrs(wire)) {
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
addProperty(attrsItem, QtType::QString, item.first.c_str(ctx), item.second.c_str());
}
DelayQuad delay = ctx->getWireDelay(wire);
QtProperty *delayItem = addSubGroup(topItem, "Delay");
addProperty(delayItem, QVariant::Double, "Min Rise", delay.minRiseDelay());
addProperty(delayItem, QVariant::Double, "Max Rise", delay.maxRiseDelay());
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
addProperty(delayItem, QtType::Double, "Min Rise", delay.minRiseDelay());
addProperty(delayItem, QtType::Double, "Max Rise", delay.maxRiseDelay());
addProperty(delayItem, QtType::Double, "Min Fall", delay.minFallDelay());
addProperty(delayItem, QtType::Double, "Max Fall", delay.maxFallDelay());
QtProperty *belpinsItem = addSubGroup(topItem, "BelPins");
for (const auto &item : ctx->getWireBelPins(wire)) {
@ -689,17 +691,17 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
QString pinname = item.pin.c_str(ctx);
QtProperty *dhItem = addSubGroup(belpinsItem, belname + "-" + pinname);
addProperty(dhItem, QVariant::String, "Bel", belname, ElementType::BEL);
addProperty(dhItem, QVariant::String, "PortPin", pinname);
addProperty(dhItem, QtType::QString, "Bel", belname, ElementType::BEL);
addProperty(dhItem, QtType::QString, "PortPin", pinname);
}
int counter = 0;
QtProperty *pipsDownItem = addSubGroup(topItem, "Pips Downhill");
for (const auto &item : ctx->getPipsDownhill(wire)) {
addProperty(pipsDownItem, QVariant::String, "", ctx->nameOfPip(item), ElementType::PIP);
addProperty(pipsDownItem, QtType::QString, "", ctx->nameOfPip(item), ElementType::PIP);
counter++;
if (counter == 50) {
addProperty(pipsDownItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE);
addProperty(pipsDownItem, QtType::QString, "Warning", "Too many items...", ElementType::NONE);
break;
}
}
@ -707,10 +709,10 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
counter = 0;
QtProperty *pipsUpItem = addSubGroup(topItem, "Pips Uphill");
for (const auto &item : ctx->getPipsUphill(wire)) {
addProperty(pipsUpItem, QVariant::String, "", ctx->nameOfPip(item), ElementType::PIP);
addProperty(pipsUpItem, QtType::QString, "", ctx->nameOfPip(item), ElementType::PIP);
counter++;
if (counter == 50) {
addProperty(pipsUpItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE);
addProperty(pipsUpItem, QtType::QString, "Warning", "Too many items...", ElementType::NONE);
break;
}
}
@ -721,34 +723,34 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
PipId pip = ctx->getPipByName(c);
QtProperty *topItem = addTopLevelProperty("Pip");
addProperty(topItem, QVariant::String, "Name", ctx->nameOfPip(pip));
addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
addProperty(topItem, QtType::QString, "Name", ctx->nameOfPip(pip));
addProperty(topItem, QtType::QString, "Type", ctx->getPipType(pip).c_str(ctx));
addProperty(topItem, QtType::Bool, "Available", ctx->checkPipAvail(pip));
addProperty(topItem, QtType::QString, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
if (ctx->getConflictingPipWire(pip) != WireId()) {
addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->nameOfWire(ctx->getConflictingPipWire(pip)),
addProperty(topItem, QtType::QString, "Conflicting Wire", ctx->nameOfWire(ctx->getConflictingPipWire(pip)),
ElementType::WIRE);
} else {
addProperty(topItem, QVariant::String, "Conflicting Wire", "", ElementType::NONE);
addProperty(topItem, QtType::QString, "Conflicting Wire", "", ElementType::NONE);
}
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
addProperty(topItem, QtType::QString, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
ElementType::NET);
addProperty(topItem, QVariant::String, "Src Wire", ctx->nameOfWire(ctx->getPipSrcWire(pip)), ElementType::WIRE);
addProperty(topItem, QVariant::String, "Dest Wire", ctx->nameOfWire(ctx->getPipDstWire(pip)),
addProperty(topItem, QtType::QString, "Src Wire", ctx->nameOfWire(ctx->getPipSrcWire(pip)), ElementType::WIRE);
addProperty(topItem, QtType::QString, "Dest Wire", ctx->nameOfWire(ctx->getPipDstWire(pip)),
ElementType::WIRE);
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : ctx->getPipAttrs(pip)) {
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
addProperty(attrsItem, QtType::QString, item.first.c_str(ctx), item.second.c_str());
}
DelayQuad delay = ctx->getPipDelay(pip);
QtProperty *delayItem = addSubGroup(topItem, "Delay");
addProperty(delayItem, QVariant::Double, "Min Rise", delay.minRiseDelay());
addProperty(delayItem, QVariant::Double, "Max Rise", delay.maxRiseDelay());
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
addProperty(delayItem, QtType::Double, "Min Rise", delay.minRiseDelay());
addProperty(delayItem, QtType::Double, "Max Rise", delay.maxRiseDelay());
addProperty(delayItem, QtType::Double, "Min Fall", delay.minFallDelay());
addProperty(delayItem, QtType::Double, "Max Fall", delay.maxFallDelay());
} else if (type == ElementType::NET) {
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
std::lock_guard<std::mutex> lock(ctx->mutex);
@ -757,29 +759,29 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
QtProperty *topItem = addTopLevelProperty("Net");
addProperty(topItem, QVariant::String, "Name", net->name.c_str(ctx));
addProperty(topItem, QtType::QString, "Name", net->name.c_str(ctx));
QtProperty *driverItem = addSubGroup(topItem, "Driver");
addProperty(driverItem, QVariant::String, "Port", net->driver.port.c_str(ctx));
addProperty(driverItem, QtType::QString, "Port", net->driver.port.c_str(ctx));
if (net->driver.cell)
addProperty(driverItem, QVariant::String, "Cell", net->driver.cell->name.c_str(ctx), ElementType::CELL);
addProperty(driverItem, QtType::QString, "Cell", net->driver.cell->name.c_str(ctx), ElementType::CELL);
else
addProperty(driverItem, QVariant::String, "Cell", "", ElementType::CELL);
addProperty(driverItem, QtType::QString, "Cell", "", ElementType::CELL);
QtProperty *usersItem = addSubGroup(topItem, "Users");
for (auto &item : net->users) {
QtProperty *portItem = addSubGroup(usersItem, item.port.c_str(ctx));
addProperty(portItem, QVariant::String, "Port", item.port.c_str(ctx));
addProperty(portItem, QtType::QString, "Port", item.port.c_str(ctx));
if (item.cell)
addProperty(portItem, QVariant::String, "Cell", item.cell->name.c_str(ctx), ElementType::CELL);
addProperty(portItem, QtType::QString, "Cell", item.cell->name.c_str(ctx), ElementType::CELL);
else
addProperty(portItem, QVariant::String, "Cell", "", ElementType::CELL);
addProperty(portItem, QtType::QString, "Cell", "", ElementType::CELL);
}
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : net->attrs) {
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx),
addProperty(attrsItem, QtType::QString, item.first.c_str(ctx),
item.second.is_string ? item.second.as_string().c_str() : item.second.to_string().c_str());
}
@ -788,14 +790,14 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
auto name = ctx->nameOfWire(item.first);
QtProperty *wireItem = addSubGroup(wiresItem, name);
addProperty(wireItem, QVariant::String, "Wire", name, ElementType::WIRE);
addProperty(wireItem, QtType::QString, "Wire", name, ElementType::WIRE);
if (item.second.pip != PipId())
addProperty(wireItem, QVariant::String, "Pip", ctx->nameOfPip(item.second.pip), ElementType::PIP);
addProperty(wireItem, QtType::QString, "Pip", ctx->nameOfPip(item.second.pip), ElementType::PIP);
else
addProperty(wireItem, QVariant::String, "Pip", "", ElementType::PIP);
addProperty(wireItem, QtType::QString, "Pip", "", ElementType::PIP);
addProperty(wireItem, QVariant::Int, "Strength", (int)item.second.strength);
addProperty(wireItem, QtType::Int, "Strength", (int)item.second.strength);
}
} else if (type == ElementType::CELL) {
@ -806,36 +808,36 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
QtProperty *topItem = addTopLevelProperty("Cell");
addProperty(topItem, QVariant::String, "Name", cell->name.c_str(ctx));
addProperty(topItem, QVariant::String, "Type", cell->type.c_str(ctx));
addProperty(topItem, QtType::QString, "Name", cell->name.c_str(ctx));
addProperty(topItem, QtType::QString, "Type", cell->type.c_str(ctx));
if (cell->bel != BelId())
addProperty(topItem, QVariant::String, "Bel", ctx->nameOfBel(cell->bel), ElementType::BEL);
addProperty(topItem, QtType::QString, "Bel", ctx->nameOfBel(cell->bel), ElementType::BEL);
else
addProperty(topItem, QVariant::String, "Bel", "", ElementType::BEL);
addProperty(topItem, QVariant::Int, "Bel strength", int(cell->belStrength));
addProperty(topItem, QtType::QString, "Bel", "", ElementType::BEL);
addProperty(topItem, QtType::Int, "Bel strength", int(cell->belStrength));
QtProperty *cellPortsItem = addSubGroup(topItem, "Ports");
for (auto &item : cell->ports) {
PortInfo p = item.second;
QtProperty *portInfoItem = addSubGroup(cellPortsItem, p.name.c_str(ctx));
addProperty(portInfoItem, QVariant::String, "Name", p.name.c_str(ctx));
addProperty(portInfoItem, QVariant::Int, "Type", int(p.type));
addProperty(portInfoItem, QtType::QString, "Name", p.name.c_str(ctx));
addProperty(portInfoItem, QtType::Int, "Type", int(p.type));
if (p.net)
addProperty(portInfoItem, QVariant::String, "Net", p.net->name.c_str(ctx), ElementType::NET);
addProperty(portInfoItem, QtType::QString, "Net", p.net->name.c_str(ctx), ElementType::NET);
else
addProperty(portInfoItem, QVariant::String, "Net", "", ElementType::NET);
addProperty(portInfoItem, QtType::QString, "Net", "", ElementType::NET);
}
QtProperty *cellAttrItem = addSubGroup(topItem, "Attributes");
for (auto &item : cell->attrs) {
addProperty(cellAttrItem, QVariant::String, item.first.c_str(ctx),
addProperty(cellAttrItem, QtType::QString, item.first.c_str(ctx),
item.second.is_string ? item.second.as_string().c_str() : item.second.to_string().c_str());
}
QtProperty *cellParamsItem = addSubGroup(topItem, "Parameters");
for (auto &item : cell->params) {
addProperty(cellParamsItem, QVariant::String, item.first.c_str(ctx),
addProperty(cellParamsItem, QtType::QString, item.first.c_str(ctx),
item.second.is_string ? item.second.as_string().c_str() : item.second.to_string().c_str());
}
}

View File

@ -29,9 +29,7 @@ const QString PythonTab::MULTILINE_PROMPT = "... ";
PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
{
QFont f("unexistent");
f.setStyleHint(QFont::Monospace);
const QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont);
// Add text area for Python output and input line
console = new PythonConsole();
console->setMinimumHeight(100);