diff options
author | YRabbit <rabbit@yrabbit.cyou> | 2022-01-29 14:45:17 +1000 |
---|---|---|
committer | YRabbit <rabbit@yrabbit.cyou> | 2022-01-29 14:45:17 +1000 |
commit | 22e4081c73ab7eec3c9f0841fcb1f247a85b5265 (patch) | |
tree | a6356121c9ea35e6221a42ed5e67c260f280f4ad /gui | |
parent | e069b3bc6ab4d504e84ef62086d2bb9e5144717b (diff) | |
download | nextpnr-22e4081c73ab7eec3c9f0841fcb1f247a85b5265.tar.gz nextpnr-22e4081c73ab7eec3c9f0841fcb1f247a85b5265.tar.bz2 nextpnr-22e4081c73ab7eec3c9f0841fcb1f247a85b5265.zip |
gowin: Add GUI.
* Items such as LUT, DFF, MUX, ALU, IOB are displayed;
* Local wires, 1-2-4-8 wires are displayed;
* The clock spines, taps and branches are displayed with some caveats.
For now, you can not create a project in the GUI because of possible
conflict with another PR (about GW1NR-9C support), but you can specify
the board in the command line and load .JSON and .CST in the GUI.
Although ALUs are displayed, but the CIN and COUT wires are not. This is
still an unsolved problem.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
Diffstat (limited to 'gui')
-rw-r--r-- | gui/designwidget.cc | 6 | ||||
-rw-r--r-- | gui/fpgaviewwidget.cc | 83 | ||||
-rw-r--r-- | gui/gowin/mainwindow.cc | 60 | ||||
-rw-r--r-- | gui/gowin/mainwindow.h | 12 | ||||
-rw-r--r-- | gui/gowin/nextpnr.qrc | 3 | ||||
-rw-r--r-- | gui/gowin/resources/open_cst.png | bin | 0 -> 9399 bytes |
6 files changed, 124 insertions, 40 deletions
diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 749c25a6..bd2578de 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -318,6 +318,12 @@ void DesignWidget::newContext(Context *ctx) wireMap[std::pair<int, int>(wire.location.x, wire.location.y)].push_back(wire);
}
#endif
+#ifdef ARCH_GOWIN
+ for (const auto &wire : ctx->getWires()) {
+ WireInfo wi = ctx->wire_info(wire);
+ wireMap[std::pair<int, int>(wi.x, wi.y)].push_back(wire);
+ }
+#endif
auto wireGetter = [](Context *ctx, WireId id) { return ctx->getWireName(id); };
getTreeByElementType(ElementType::WIRE)
->loadData(ctx,
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index b99c2bfc..692eb27b 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -129,40 +129,47 @@ float FPGAViewWidget::PickedElement::distance(Context *ctx, float wx, float wy) // Go over its' GraphicElements, and calculate the distance to them. std::vector<float> distances; - std::transform(graphics.begin(), graphics.end(), std::back_inserter(distances), - [&](const GraphicElement &ge) -> float { - switch (ge.type) { - case GraphicElement::TYPE_BOX: { - // If outside the box, return unit distance to closest border. - float outside_x = -1, outside_y = -1; - if (dx < ge.x1 || dx > ge.x2) { - outside_x = std::min(std::abs(dx - ge.x1), std::abs(dx - ge.x2)); - } - if (dy < ge.y1 || dy > ge.y2) { - outside_y = std::min(std::abs(dy - ge.y1), std::abs(dy - ge.y2)); - } - if (outside_x != -1 && outside_y != -1) - return std::min(outside_x, outside_y); - - // If in box, return 0. - return 0; - } - case GraphicElement::TYPE_LINE: - case GraphicElement::TYPE_ARROW: { - // Return somewhat primitively calculated distance to segment. - // TODO(q3k): consider coming up with a better algorithm - QVector2D w(wx, wy); - QVector2D a(ge.x1, ge.y1); - QVector2D b(ge.x2, ge.y2); - float dw = a.distanceToPoint(w) + b.distanceToPoint(w); - float dab = a.distanceToPoint(b); - return std::abs(dw - dab) / dab; - } - default: - // Not close to anything. - return -1; - } - }); + std::transform( + graphics.begin(), graphics.end(), std::back_inserter(distances), [&](const GraphicElement &ge) -> float { + switch (ge.type) { + case GraphicElement::TYPE_BOX: { + // If outside the box, return unit distance to closest border. + float outside_x = -1, outside_y = -1; + if (dx < ge.x1 || dx > ge.x2) { + outside_x = std::min(std::abs(dx - ge.x1), std::abs(dx - ge.x2)); + } + if (dy < ge.y1 || dy > ge.y2) { + outside_y = std::min(std::abs(dy - ge.y1), std::abs(dy - ge.y2)); + } + if (outside_x != -1 && outside_y != -1) + return std::min(outside_x, outside_y); + + // If in box, return 0. + return 0; + } + case GraphicElement::TYPE_LOCAL_LINE: + case GraphicElement::TYPE_LOCAL_ARROW: + case GraphicElement::TYPE_LINE: + case GraphicElement::TYPE_ARROW: { + // Return somewhat primitively calculated distance to segment. + // TODO(q3k): consider coming up with a better algorithm + QVector2D w; + if (ge.type == GraphicElement::TYPE_LOCAL_LINE || ge.type == GraphicElement::TYPE_LOCAL_ARROW) { + w = QVector2D(dx, dy); + } else { + w = QVector2D(wx, wy); + } + QVector2D a(ge.x1, ge.y1); + QVector2D b(ge.x2, ge.y2); + float dw = a.distanceToPoint(w) + b.distanceToPoint(w); + float dab = a.distanceToPoint(b); + return std::abs(dw - dab) / dab; + } + default: + // Not close to anything. + return -1; + } + }); // Find smallest non -1 distance. // Find closest element. @@ -193,7 +200,8 @@ void FPGAViewWidget::renderGraphicElement(LineShaderData &out, PickQuadTree::Bou return; } - if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { + if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW || + el.type == GraphicElement::TYPE_LOCAL_LINE || el.type == GraphicElement::TYPE_LOCAL_ARROW) { PolyLine(x + el.x1, y + el.y1, x + el.x2, y + el.y2).build(out); bb.setX0(std::min(bb.x0(), x + el.x1)); bb.setY0(std::min(bb.y0(), y + el.y1)); @@ -251,7 +259,8 @@ void FPGAViewWidget::populateQuadTree(RendererData *data, const DecalXY &decal, res = data->qt->insert(PickQuadTree::BoundingBox(x + el.x1, y + el.y1, x + el.x2, y + el.y2), element); } - if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { + if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW || + el.type == GraphicElement::TYPE_LOCAL_LINE || el.type == GraphicElement::TYPE_LOCAL_ARROW) { // Lines are bounded by their AABB slightly enlarged. float x0 = x + el.x1; float y0 = y + el.y1; @@ -540,7 +549,7 @@ void FPGAViewWidget::renderLines(void) QMutexLocker lock(&rendererDataLock_); // If we're not re-rendering any highlights/selections, let's - // copy them over from teh current object. + // copy them over from the current object. data->gfxGrid = rendererData_->gfxGrid; if (!highlightedOrSelectedChanged) { data->gfxSelected = rendererData_->gfxSelected; diff --git a/gui/gowin/mainwindow.cc b/gui/gowin/mainwindow.cc index 9dafcef5..c7ba44ab 100644 --- a/gui/gowin/mainwindow.cc +++ b/gui/gowin/mainwindow.cc @@ -19,9 +19,12 @@ #include "mainwindow.h"
+#include <QFileDialog>
#include <QMessageBox>
#include <cstdlib>
+#include "cst.h"
+
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
NEXTPNR_NAMESPACE_BEGIN
@@ -30,8 +33,10 @@ MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler : BaseMainWindow(std::move(context), handler, parent)
{
initMainResource();
- QMessageBox::critical(0, "Error - FIXME", "No GUI support for nextpnr-gowin");
- std::exit(1);
+ std::string title = "nextpnr-gowin - [EMPTY]";
+ setWindowTitle(title.c_str());
+ connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
+ createMenu();
}
MainWindow::~MainWindow() {}
@@ -42,8 +47,57 @@ void MainWindow::newContext(Context *ctx) setWindowTitle(title.c_str());
}
-void MainWindow::createMenu() {}
+void MainWindow::load_cst(std::string filename)
+{
+ disableActions();
+ std::ifstream f(filename);
+ if (read_cst(ctx.get(), f)) {
+ log("Loading CST successful.\n");
+ actionPack->setEnabled(true);
+ } else {
+ actionLoadCST->setEnabled(true);
+ log("Loading CST failed.\n");
+ }
+}
+
+void MainWindow::createMenu()
+{
+ actionLoadCST = new QAction("Open CST", this);
+ actionLoadCST->setIcon(QIcon(":/icons/resources/open_cst.png"));
+ actionLoadCST->setStatusTip("Open CST file");
+ actionLoadCST->setEnabled(false);
+ connect(actionLoadCST, &QAction::triggered, this, &MainWindow::open_cst);
+
+ // Add actions in menus
+ mainActionBar->addSeparator();
+ mainActionBar->addAction(actionLoadCST);
+
+ menuDesign->addSeparator();
+ menuDesign->addAction(actionLoadCST);
+}
void MainWindow::new_proj() {}
+void MainWindow::open_cst()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, QString("Open CST"), QString(), QString("*.cst"));
+ if (!fileName.isEmpty()) {
+ load_cst(fileName.toStdString());
+ }
+}
+
+void MainWindow::onDisableActions() { actionLoadCST->setEnabled(false); }
+
+void MainWindow::onUpdateActions()
+{
+ if (ctx->settings.find(ctx->id("synth")) != ctx->settings.end()) {
+ actionLoadCST->setEnabled(true);
+ }
+ if (ctx->settings.find(ctx->id("cst")) != ctx->settings.end()) {
+ actionLoadCST->setEnabled(false);
+ }
+ if (ctx->settings.find(ctx->id("pack")) != ctx->settings.end()) {
+ actionLoadCST->setEnabled(false);
+ }
+}
NEXTPNR_NAMESPACE_END
diff --git a/gui/gowin/mainwindow.h b/gui/gowin/mainwindow.h index 1e39b63f..0d65ed1c 100644 --- a/gui/gowin/mainwindow.h +++ b/gui/gowin/mainwindow.h @@ -35,9 +35,21 @@ class MainWindow : public BaseMainWindow public:
void createMenu();
+ protected:
+ void onDisableActions() override;
+ void onUpdateActions() override;
+
+ void load_cst(std::string filename);
+
protected Q_SLOTS:
void new_proj() override;
+
+ void open_cst();
+
void newContext(Context *ctx);
+
+ private:
+ QAction *actionLoadCST;
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/gowin/nextpnr.qrc b/gui/gowin/nextpnr.qrc index 03585ec0..921cfdd1 100644 --- a/gui/gowin/nextpnr.qrc +++ b/gui/gowin/nextpnr.qrc @@ -1,2 +1,5 @@ <RCC> + <qresource prefix="/icons"> + <file>resources/open_cst.png</file> + </qresource> </RCC> diff --git a/gui/gowin/resources/open_cst.png b/gui/gowin/resources/open_cst.png Binary files differnew file mode 100644 index 00000000..23fe9cf8 --- /dev/null +++ b/gui/gowin/resources/open_cst.png |