aboutsummaryrefslogtreecommitdiffstats
path: root/gui
diff options
context:
space:
mode:
authorYRabbit <rabbit@yrabbit.cyou>2022-01-29 14:45:17 +1000
committerYRabbit <rabbit@yrabbit.cyou>2022-01-29 14:45:17 +1000
commit22e4081c73ab7eec3c9f0841fcb1f247a85b5265 (patch)
treea6356121c9ea35e6221a42ed5e67c260f280f4ad /gui
parente069b3bc6ab4d504e84ef62086d2bb9e5144717b (diff)
downloadnextpnr-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.cc6
-rw-r--r--gui/fpgaviewwidget.cc83
-rw-r--r--gui/gowin/mainwindow.cc60
-rw-r--r--gui/gowin/mainwindow.h12
-rw-r--r--gui/gowin/nextpnr.qrc3
-rw-r--r--gui/gowin/resources/open_cst.pngbin0 -> 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
new file mode 100644
index 00000000..23fe9cf8
--- /dev/null
+++ b/gui/gowin/resources/open_cst.png
Binary files differ