aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerge Bazanski <serge@bazanski.pl>2018-07-15 21:57:42 +0100
committerSerge Bazanski <serge@bazanski.pl>2018-07-15 21:57:42 +0100
commitf3c6c76fff90d89dd65af2c02124c098dab63892 (patch)
tree48aad4eb072d9972a5a1c298c9fde7922038d74d
parent91db413c60c965b6b7cc095f53c8d03a1658566e (diff)
parent5531546d6bcf188c27449b6256108c6c722b5b5b (diff)
downloadnextpnr-f3c6c76fff90d89dd65af2c02124c098dab63892.tar.gz
nextpnr-f3c6c76fff90d89dd65af2c02124c098dab63892.tar.bz2
nextpnr-f3c6c76fff90d89dd65af2c02124c098dab63892.zip
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into q3k/lock-2-electric-boogaloo
-rw-r--r--3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp11
-rw-r--r--3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h4
-rw-r--r--gui/base.qrc1
-rw-r--r--gui/basewindow.cc44
-rw-r--r--gui/basewindow.h6
-rw-r--r--gui/designwidget.cc672
-rw-r--r--gui/designwidget.h41
-rw-r--r--gui/fpgaviewwidget.cc39
-rw-r--r--gui/fpgaviewwidget.h9
-rw-r--r--gui/ice40/mainwindow.cc21
-rw-r--r--gui/resources/splash.pngbin0 -> 4651 bytes
-rw-r--r--ice40/arch.cc23
-rw-r--r--ice40/arch.h2
-rw-r--r--ice40/chipdb.py30
-rw-r--r--ice40/gfx.cc219
-rw-r--r--ice40/gfx.h1
16 files changed, 810 insertions, 313 deletions
diff --git a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp
index a92ab537..673252d2 100644
--- a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp
+++ b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp
@@ -74,6 +74,7 @@ public:
QtProperty *indexToProperty(const QModelIndex &index) const;
QTreeWidgetItem *indexToItem(const QModelIndex &index) const;
QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const;
+ QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item) const { return m_itemToIndex.value(item); };
bool lastColumn(int column) const;
void disableItem(QTreeWidgetItem *item) const;
void enableItem(QTreeWidgetItem *item) const;
@@ -1068,6 +1069,16 @@ void QtTreePropertyBrowser::editItem(QtBrowserItem *item)
d_ptr->editItem(item);
}
+QTreeWidget *QtTreePropertyBrowser::treeWidget() const
+{
+ return d_ptr->treeWidget();
+}
+
+QtBrowserItem *QtTreePropertyBrowser::itemToBrowserItem(QTreeWidgetItem *item)
+{
+ return d_ptr->itemToBrowserItem(item);
+}
+
#if QT_VERSION >= 0x040400
QT_END_NAMESPACE
#endif
diff --git a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h
index c5f7fa88..7bc96b69 100644
--- a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h
+++ b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h
@@ -47,6 +47,7 @@
QT_BEGIN_NAMESPACE
#endif
+class QTreeWidget;
class QTreeWidgetItem;
class QtTreePropertyBrowserPrivate;
@@ -107,6 +108,9 @@ public:
void editItem(QtBrowserItem *item);
+ //ADDED:miodrag
+ QTreeWidget *treeWidget() const;
+ QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item);
Q_SIGNALS:
void collapsed(QtBrowserItem *item);
diff --git a/gui/base.qrc b/gui/base.qrc
index 8f07aabe..bf21986b 100644
--- a/gui/base.qrc
+++ b/gui/base.qrc
@@ -9,5 +9,6 @@
<file>resources/resultset_previous.png</file>
<file>resources/resultset_next.png</file>
<file>resources/resultset_last.png</file>
+ <file>resources/splash.png</file>
</qresource>
</RCC>
diff --git a/gui/basewindow.cc b/gui/basewindow.cc
index 0c7632ee..07b71105 100644
--- a/gui/basewindow.cc
+++ b/gui/basewindow.cc
@@ -18,6 +18,7 @@
*/
#include <QAction>
+#include <QCoreApplication>
#include <QFileDialog>
#include <QGridLayout>
#include <QIcon>
@@ -61,15 +62,10 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
setCentralWidget(centralWidget);
- DesignWidget *designview = new DesignWidget();
+ designview = new DesignWidget();
designview->setMinimumWidth(300);
splitter_h->addWidget(designview);
- connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *)));
- connect(this, SIGNAL(updateTreeView()), designview, SLOT(updateTree()));
-
- connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string)));
-
tabWidget = new QTabWidget();
console = new PythonTab();
@@ -81,38 +77,64 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
centralTabWidget->addTab(fpgaView, "Graphics");
connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *)));
- connect(designview, SIGNAL(selected(std::vector<DecalXY>)), fpgaView, SLOT(onSelectedArchItem(std::vector<DecalXY>)));
+ connect(designview, SIGNAL(selected(std::vector<DecalXY>)), fpgaView,
+ SLOT(onSelectedArchItem(std::vector<DecalXY>)));
+
+ connect(designview, SIGNAL(highlight(std::vector<DecalXY>, int)), fpgaView,
+ SLOT(onHighlightGroupChanged(std::vector<DecalXY>, int)));
+
+ connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *)));
+ connect(this, SIGNAL(updateTreeView()), designview, SLOT(updateTree()));
+
+ connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string)));
splitter_v->addWidget(centralTabWidget);
splitter_v->addWidget(tabWidget);
+ displaySplash();
}
BaseMainWindow::~BaseMainWindow() {}
+void BaseMainWindow::displaySplash()
+{
+ splash = new QSplashScreen();
+ splash->setPixmap(QPixmap(":/icons/resources/splash.png"));
+ splash->show();
+ connect(designview, SIGNAL(finishContextLoad()), splash, SLOT(close()));
+ connect(designview, SIGNAL(contextLoadStatus(std::string)), this, SLOT(displaySplashMessage(std::string)));
+ QCoreApplication::instance()->processEvents();
+}
+
+void BaseMainWindow::displaySplashMessage(std::string msg)
+{
+ splash->showMessage(msg.c_str(), Qt::AlignCenter | Qt::AlignBottom, Qt::white);
+ QCoreApplication::instance()->processEvents();
+}
+
void BaseMainWindow::writeInfo(std::string text) { console->info(text); }
void BaseMainWindow::createMenusAndBars()
{
- actionNew = new QAction("New", this);
+ actionNew = new QAction("New", this);
actionNew->setIcon(QIcon(":/icons/resources/new.png"));
actionNew->setShortcuts(QKeySequence::New);
actionNew->setStatusTip("New project file");
connect(actionNew, SIGNAL(triggered()), this, SLOT(new_proj()));
- actionOpen = new QAction("Open", this);
+ actionOpen = new QAction("Open", this);
actionOpen->setIcon(QIcon(":/icons/resources/open.png"));
actionOpen->setShortcuts(QKeySequence::Open);
actionOpen->setStatusTip("Open an existing project file");
connect(actionOpen, SIGNAL(triggered()), this, SLOT(open_proj()));
- QAction *actionSave = new QAction("Save", this);
+ QAction *actionSave = new QAction("Save", this);
actionSave->setIcon(QIcon(":/icons/resources/save.png"));
actionSave->setShortcuts(QKeySequence::Save);
actionSave->setStatusTip("Save existing project to disk");
actionSave->setEnabled(false);
connect(actionSave, SIGNAL(triggered()), this, SLOT(save_proj()));
- QAction *actionExit = new QAction("Exit", this);
+ QAction *actionExit = new QAction("Exit", this);
actionExit->setIcon(QIcon(":/icons/resources/exit.png"));
actionExit->setShortcuts(QKeySequence::Quit);
actionExit->setStatusTip("Exit the application");
diff --git a/gui/basewindow.h b/gui/basewindow.h
index 4d3d80a1..18b5339e 100644
--- a/gui/basewindow.h
+++ b/gui/basewindow.h
@@ -26,6 +26,7 @@
#include <QMenu>
#include <QMenuBar>
#include <QProgressBar>
+#include <QSplashScreen>
#include <QStatusBar>
#include <QTabWidget>
#include <QToolBar>
@@ -36,6 +37,7 @@ Q_DECLARE_METATYPE(NEXTPNR_NAMESPACE_PREFIX DecalXY)
NEXTPNR_NAMESPACE_BEGIN
class PythonTab;
+class DesignWidget;
class BaseMainWindow : public QMainWindow
{
@@ -48,9 +50,11 @@ class BaseMainWindow : public QMainWindow
protected:
void createMenusAndBars();
+ void displaySplash();
protected Q_SLOTS:
void writeInfo(std::string text);
+ void displaySplashMessage(std::string msg);
virtual void new_proj() = 0;
virtual void open_proj() = 0;
@@ -72,6 +76,8 @@ class BaseMainWindow : public QMainWindow
QAction *actionNew;
QAction *actionOpen;
QProgressBar *progressBar;
+ QSplashScreen *splash;
+ DesignWidget *designview;
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/designwidget.cc b/gui/designwidget.cc
index edf9f1ec..335ed929 100644
--- a/gui/designwidget.cc
+++ b/gui/designwidget.cc
@@ -29,16 +29,6 @@
NEXTPNR_NAMESPACE_BEGIN
-enum class ElementType
-{
- NONE,
- BEL,
- WIRE,
- PIP,
- NET,
- CELL
-};
-
class ElementTreeItem : public QTreeWidgetItem
{
public:
@@ -87,29 +77,53 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net
propertyEditor = new QtTreePropertyBrowser(this);
propertyEditor->setFactoryForManager(variantManager, variantFactory);
propertyEditor->setPropertiesWithoutValueMarked(true);
-
propertyEditor->show();
-
+ propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu);
+
QLineEdit *lineEdit = new QLineEdit();
lineEdit->setClearButtonEnabled(true);
lineEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition);
lineEdit->setPlaceholderText("Search...");
- actionFirst = new QAction("", this);
+ actionFirst = new QAction("", this);
actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png"));
actionFirst->setEnabled(false);
-
- actionPrev = new QAction("", this);
+ connect(actionFirst, &QAction::triggered, this, [this] {
+ history_ignore = true;
+ history_index = 0;
+ treeWidget->setCurrentItem(history.at(history_index));
+ updateButtons();
+ });
+
+ actionPrev = new QAction("", this);
actionPrev->setIcon(QIcon(":/icons/resources/resultset_previous.png"));
actionPrev->setEnabled(false);
-
- actionNext = new QAction("", this);
+ connect(actionPrev, &QAction::triggered, this, [this] {
+ history_ignore = true;
+ history_index--;
+ treeWidget->setCurrentItem(history.at(history_index));
+ updateButtons();
+ });
+
+ actionNext = new QAction("", this);
actionNext->setIcon(QIcon(":/icons/resources/resultset_next.png"));
actionNext->setEnabled(false);
-
- actionLast = new QAction("", this);
+ connect(actionNext, &QAction::triggered, this, [this] {
+ history_ignore = true;
+ history_index++;
+ treeWidget->setCurrentItem(history.at(history_index));
+ updateButtons();
+ });
+
+ actionLast = new QAction("", this);
actionLast->setIcon(QIcon(":/icons/resources/resultset_last.png"));
actionLast->setEnabled(false);
+ connect(actionLast, &QAction::triggered, this, [this] {
+ history_ignore = true;
+ history_index = int(history.size() - 1);
+ treeWidget->setCurrentItem(history.at(history_index));
+ updateButtons();
+ });
QToolBar *toolbar = new QToolBar();
toolbar->addAction(actionFirst);
@@ -153,16 +167,61 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net
setLayout(mainLayout);
// Connection
- connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenu);
+ connect(propertyEditor->treeWidget(), &QTreeWidget::customContextMenuRequested, this,
+ &DesignWidget::prepareMenuProperty);
+ connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked);
connect(treeWidget, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged()));
+ connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenuTree);
+
+ history_index = -1;
+ history_ignore = false;
+
+ highlightColors[0] = QColor("#6495ed");
+ highlightColors[1] = QColor("#7fffd4");
+ highlightColors[2] = QColor("#98fb98");
+ highlightColors[3] = QColor("#ffd700");
+ highlightColors[4] = QColor("#cd5c5c");
+ highlightColors[5] = QColor("#fa8072");
+ highlightColors[6] = QColor("#ff69b4");
+ highlightColors[7] = QColor("#da70d6");
}
DesignWidget::~DesignWidget() {}
+void DesignWidget::updateButtons()
+{
+ int count = int(history.size());
+ actionFirst->setEnabled(history_index > 0);
+ actionPrev->setEnabled(history_index > 0);
+ actionNext->setEnabled(history_index < (count - 1));
+ actionLast->setEnabled(history_index < (count - 1));
+}
+
+void DesignWidget::addToHistory(QTreeWidgetItem *item)
+{
+ if (!history_ignore) {
+ int count = int(history.size());
+ for (int i = count - 1; i > history_index; i--)
+ history.pop_back();
+ history.push_back(item);
+ history_index++;
+ }
+ history_ignore = false;
+ updateButtons();
+}
+
void DesignWidget::newContext(Context *ctx)
{
treeWidget->clear();
+ history_ignore = false;
+ history_index = -1;
+ history.clear();
+ updateButtons();
+
+ for (int i = 0; i < 6; i++)
+ nameToItem[i].clear();
+
this->ctx = ctx;
// Add bels to tree
@@ -171,6 +230,7 @@ void DesignWidget::newContext(Context *ctx)
bel_root->setText(0, "Bels");
treeWidget->insertTopLevelItem(0, bel_root);
if (ctx) {
+ Q_EMIT contextLoadStatus("Configuring bels...");
for (auto bel : ctx->getBels()) {
auto id = ctx->getBelName(bel);
QStringList items = QString(id.c_str(ctx)).split("/");
@@ -182,7 +242,7 @@ void DesignWidget::newContext(Context *ctx)
name += items.at(i);
if (!bel_items.contains(name)) {
if (i == items.size() - 1)
- bel_items.insert(name, new IdStringTreeItem(id, ElementType::BEL, items.at(i), parent));
+ nameToItem[0].insert(name, new IdStringTreeItem(id, ElementType::BEL, items.at(i), parent));
else
bel_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent));
}
@@ -193,6 +253,9 @@ void DesignWidget::newContext(Context *ctx)
for (auto bel : bel_items.toStdMap()) {
bel_root->addChild(bel.second);
}
+ for (auto bel : nameToItem[0].toStdMap()) {
+ bel_root->addChild(bel.second);
+ }
// Add wires to tree
QTreeWidgetItem *wire_root = new QTreeWidgetItem(treeWidget);
@@ -200,6 +263,7 @@ void DesignWidget::newContext(Context *ctx)
wire_root->setText(0, "Wires");
treeWidget->insertTopLevelItem(0, wire_root);
if (ctx) {
+ Q_EMIT contextLoadStatus("Configuring wires...");
for (auto wire : ctx->getWires()) {
auto id = ctx->getWireName(wire);
QStringList items = QString(id.c_str(ctx)).split("/");
@@ -211,7 +275,7 @@ void DesignWidget::newContext(Context *ctx)
name += items.at(i);
if (!wire_items.contains(name)) {
if (i == items.size() - 1)
- wire_items.insert(name, new IdStringTreeItem(id, ElementType::WIRE, items.at(i), parent));
+ nameToItem[1].insert(name, new IdStringTreeItem(id, ElementType::WIRE, items.at(i), parent));
else
wire_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent));
}
@@ -222,13 +286,16 @@ void DesignWidget::newContext(Context *ctx)
for (auto wire : wire_items.toStdMap()) {
wire_root->addChild(wire.second);
}
-
+ for (auto wire : nameToItem[1].toStdMap()) {
+ wire_root->addChild(wire.second);
+ }
// Add pips to tree
QTreeWidgetItem *pip_root = new QTreeWidgetItem(treeWidget);
QMap<QString, QTreeWidgetItem *> pip_items;
pip_root->setText(0, "Pips");
treeWidget->insertTopLevelItem(0, pip_root);
if (ctx) {
+ Q_EMIT contextLoadStatus("Configuring pips...");
for (auto pip : ctx->getPips()) {
auto id = ctx->getPipName(pip);
QStringList items = QString(id.c_str(ctx)).split("/");
@@ -240,7 +307,7 @@ void DesignWidget::newContext(Context *ctx)
name += items.at(i);
if (!pip_items.contains(name)) {
if (i == items.size() - 1)
- pip_items.insert(name, new IdStringTreeItem(id, ElementType::PIP, items.at(i), parent));
+ nameToItem[2].insert(name, new IdStringTreeItem(id, ElementType::PIP, items.at(i), parent));
else
pip_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent));
}
@@ -251,6 +318,9 @@ void DesignWidget::newContext(Context *ctx)
for (auto pip : pip_items.toStdMap()) {
pip_root->addChild(pip.second);
}
+ for (auto pip : nameToItem[2].toStdMap()) {
+ pip_root->addChild(pip.second);
+ }
// Add nets to tree
nets_root = new QTreeWidgetItem(treeWidget);
@@ -261,6 +331,8 @@ void DesignWidget::newContext(Context *ctx)
cells_root = new QTreeWidgetItem(treeWidget);
cells_root->setText(0, "Cells");
treeWidget->insertTopLevelItem(0, cells_root);
+
+ Q_EMIT finishContextLoad();
}
void DesignWidget::updateTree()
@@ -268,45 +340,48 @@ void DesignWidget::updateTree()
clearProperties();
delete nets_root;
delete cells_root;
+ nameToItem[3].clear();
+ nameToItem[4].clear();
// Add nets to tree
nets_root = new QTreeWidgetItem(treeWidget);
- QMap<QString, QTreeWidgetItem *> nets_items;
nets_root->setText(0, "Nets");
treeWidget->insertTopLevelItem(0, nets_root);
if (ctx) {
for (auto &item : ctx->nets) {
auto id = item.first;
QString name = QString(id.c_str(ctx));
- nets_items.insert(name, new IdStringTreeItem(id, ElementType::NET, name, nullptr));
+ IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::NET, name, nullptr);
+ nameToItem[3].insert(name, newItem);
}
}
- for (auto item : nets_items.toStdMap()) {
+ for (auto item : nameToItem[3].toStdMap()) {
nets_root->addChild(item.second);
}
// Add cells to tree
cells_root = new QTreeWidgetItem(treeWidget);
- QMap<QString, QTreeWidgetItem *> cells_items;
cells_root->setText(0, "Cells");
treeWidget->insertTopLevelItem(0, cells_root);
if (ctx) {
for (auto &item : ctx->cells) {
auto id = item.first;
QString name = QString(id.c_str(ctx));
- cells_items.insert(name, new IdStringTreeItem(id, ElementType::CELL, name, nullptr));
+ IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::CELL, name, nullptr);
+ nameToItem[4].insert(name, newItem);
}
}
- for (auto item : cells_items.toStdMap()) {
+ for (auto item : nameToItem[4].toStdMap()) {
cells_root->addChild(item.second);
}
}
-
-void DesignWidget::addProperty(QtProperty *property, const QString &id)
+QtProperty *DesignWidget::addTopLevelProperty(const QString &id)
{
- propertyToId[property] = id;
- idToProperty[id] = property;
- propertyEditor->addProperty(property);
+ QtProperty *topItem = groupManager->addProperty(id);
+ propertyToId[topItem] = id;
+ idToProperty[id] = topItem;
+ propertyEditor->addProperty(topItem);
+ return topItem;
}
void DesignWidget::clearProperties()
@@ -320,10 +395,73 @@ void DesignWidget::clearProperties()
idToProperty.clear();
}
+QString DesignWidget::getElementTypeName(ElementType type)
+{
+ if (type == ElementType::NONE)
+ return "";
+ if (type == ElementType::BEL)
+ return "BEL";
+ if (type == ElementType::WIRE)
+ return "WIRE";
+ if (type == ElementType::PIP)
+ return "PIP";
+ if (type == ElementType::NET)
+ return "NET";
+ if (type == ElementType::CELL)
+ return "CELL";
+ return "";
+}
+int DesignWidget::getElementIndex(ElementType type)
+{
+ if (type == ElementType::BEL)
+ return 0;
+ if (type == ElementType::WIRE)
+ return 1;
+ if (type == ElementType::PIP)
+ return 2;
+ if (type == ElementType::NET)
+ return 3;
+ if (type == ElementType::CELL)
+ return 4;
+ return -1;
+}
+
+ElementType DesignWidget::getElementTypeByName(QString type)
+{
+ if (type == "BEL")
+ return ElementType::BEL;
+ if (type == "WIRE")
+ return ElementType::WIRE;
+ if (type == "PIP")
+ return ElementType::PIP;
+ if (type == "NET")
+ return ElementType::NET;
+ if (type == "CELL")
+ return ElementType::CELL;
+ return ElementType::NONE;
+}
+
+void DesignWidget::addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value,
+ const ElementType &type)
+{
+ QtVariantProperty *item = readOnlyManager->addProperty(propertyType, name);
+ item->setValue(value);
+ item->setPropertyId(getElementTypeName(type));
+ topItem->addSubProperty(item);
+}
+
+QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name)
+{
+ QtProperty *item = groupManager->addProperty(name);
+ topItem->addSubProperty(item);
+ return item;
+}
+
void DesignWidget::onItemSelectionChanged()
{
- if (treeWidget->selectedItems().size()== 0) return;
-
+ if (treeWidget->selectedItems().size() == 0)
+ return;
+
QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0);
if (!clickItem->parent())
@@ -336,36 +474,24 @@ void DesignWidget::onItemSelectionChanged()
std::vector<DecalXY> decals;
+ addToHistory(clickItem);
+
clearProperties();
if (type == ElementType::BEL) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
BelId bel = ctx->getBelByName(c);
-
- decals.push_back(ctx->getBelDecal(bel));
- Q_EMIT selected(decals);
-
- QtProperty *topItem = groupManager->addProperty("Bel");
- addProperty(topItem, "Bel");
-
- QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
- nameItem->setValue(c.c_str(ctx));
- topItem->addSubProperty(nameItem);
- QtVariantProperty *typeItem = readOnlyManager->addProperty(QVariant::String, "Type");
- typeItem->setValue(ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx));
- topItem->addSubProperty(typeItem);
-
- QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
- availItem->setValue(ctx->checkBelAvail(bel));
- topItem->addSubProperty(availItem);
+ decals.push_back(ctx->getBelDecal(bel));
+ Q_EMIT selected(decals);
- QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Cell");
- cellItem->setValue(ctx->getBoundBelCell(bel).c_str(ctx));
- topItem->addSubProperty(cellItem);
+ QtProperty *topItem = addTopLevelProperty("Bel");
- QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Cell");
- conflictItem->setValue(ctx->getConflictingBelCell(bel).c_str(ctx));
- topItem->addSubProperty(conflictItem);
+ addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
+ addProperty(topItem, QVariant::String, "Type", ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx));
+ addProperty(topItem, QVariant::Bool, "Available", ctx->checkBelAvail(bel));
+ addProperty(topItem, QVariant::String, "Bound Cell", ctx->getBoundBelCell(bel).c_str(ctx), ElementType::CELL);
+ addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->getConflictingBelCell(bel).c_str(ctx),
+ ElementType::CELL);
} else if (type == ElementType::WIRE) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
@@ -374,76 +500,56 @@ void DesignWidget::onItemSelectionChanged()
decals.push_back(ctx->getWireDecal(wire));
Q_EMIT selected(decals);
- QtProperty *topItem = groupManager->addProperty("Wire");
- addProperty(topItem, "Wire");
-
- QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
- nameItem->setValue(c.c_str(ctx));
- topItem->addSubProperty(nameItem);
-
- QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
- availItem->setValue(ctx->checkWireAvail(wire));
- topItem->addSubProperty(availItem);
+ QtProperty *topItem = addTopLevelProperty("Wire");
- QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net");
- cellItem->setValue(ctx->getBoundWireNet(wire).c_str(ctx));
- topItem->addSubProperty(cellItem);
-
- QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net");
- conflictItem->setValue(ctx->getConflictingWireNet(wire).c_str(ctx));
- topItem->addSubProperty(conflictItem);
+ addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
+ addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
+ addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundWireNet(wire).c_str(ctx), ElementType::NET);
+ addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingWireNet(wire).c_str(ctx),
+ ElementType::NET);
+ QtProperty *belpinItem = addSubGroup(topItem, "BelPin Uphill");
BelPin uphill = ctx->getBelPinUphill(wire);
- QtProperty *belpinItem = groupManager->addProperty("BelPin Uphill");
- topItem->addSubProperty(belpinItem);
-
- QtVariantProperty *belUphillItem = readOnlyManager->addProperty(QVariant::String, "Bel");
if (uphill.bel != BelId())
- belUphillItem->setValue(ctx->getBelName(uphill.bel).c_str(ctx));
+ addProperty(belpinItem, QVariant::String, "Bel", ctx->getBelName(uphill.bel).c_str(ctx), ElementType::BEL);
else
- belUphillItem->setValue("");
- belpinItem->addSubProperty(belUphillItem);
+ addProperty(belpinItem, QVariant::String, "Bel", "", ElementType::BEL);
- QtVariantProperty *portUphillItem = readOnlyManager->addProperty(QVariant::String, "PortPin");
- portUphillItem->setValue(ctx->portPinToId(uphill.pin).c_str(ctx));
- belpinItem->addSubProperty(portUphillItem);
+ addProperty(belpinItem, QVariant::String, "PortPin", ctx->portPinToId(uphill.pin).c_str(ctx), ElementType::BEL);
- QtProperty *downhillItem = groupManager->addProperty("BelPins Downhill");
- topItem->addSubProperty(downhillItem);
+ QtProperty *downhillItem = addSubGroup(topItem, "BelPin Downhill");
for (const auto &item : ctx->getBelPinsDownhill(wire)) {
QString belname = "";
if (item.bel != BelId())
belname = ctx->getBelName(item.bel).c_str(ctx);
QString pinname = ctx->portPinToId(item.pin).c_str(ctx);
- QtProperty *dhItem = groupManager->addProperty(belname + "-" + pinname);
- downhillItem->addSubProperty(dhItem);
-
- QtVariantProperty *belItem = readOnlyManager->addProperty(QVariant::String, "Bel");
- belItem->setValue(belname);
- dhItem->addSubProperty(belItem);
-
- QtVariantProperty *portItem = readOnlyManager->addProperty(QVariant::String, "PortPin");
- portItem->setValue(pinname);
- dhItem->addSubProperty(portItem);
+ QtProperty *dhItem = addSubGroup(downhillItem, belname + "-" + pinname);
+ addProperty(dhItem, QVariant::String, "Bel", belname, ElementType::BEL);
+ addProperty(dhItem, QVariant::String, "PortPin", pinname);
}
-/*
- QtProperty *pipsDownItem = groupManager->addProperty("Pips Downhill");
- topItem->addSubProperty(pipsDownItem);
+
+ int counter = 0;
+ QtProperty *pipsDownItem = addSubGroup(downhillItem, "Pips Downhill");
for (const auto &item : ctx->getPipsDownhill(wire)) {
- QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, "");
- pipItem->setValue(ctx->getPipName(item).c_str(ctx));
- pipsDownItem->addSubProperty(pipItem);
+ addProperty(pipsDownItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP);
+ counter++;
+ if (counter == 50) {
+ addProperty(pipsDownItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE);
+ break;
+ }
}
- QtProperty *pipsUpItem = groupManager->addProperty("Pips Uphill");
- topItem->addSubProperty(pipsUpItem);
+ counter = 0;
+ QtProperty *pipsUpItem = addSubGroup(downhillItem, "Pips Uphill");
for (const auto &item : ctx->getPipsUphill(wire)) {
- QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, "");
- pipItem->setValue(ctx->getPipName(item).c_str(ctx));
- pipsUpItem->addSubProperty(pipItem);
+ addProperty(pipsUpItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP);
+ counter++;
+ if (counter == 50) {
+ addProperty(pipsUpItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE);
+ break;
+ }
}
-*/
} else if (type == ElementType::PIP) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
PipId pip = ctx->getPipByName(c);
@@ -451,199 +557,108 @@ void DesignWidget::onItemSelectionChanged()
decals.push_back(ctx->getPipDecal(pip));
Q_EMIT selected(decals);
- QtProperty *topItem = groupManager->addProperty("Pip");
- addProperty(topItem, "Pip");
-
- QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
- nameItem->setValue(c.c_str(ctx));
- topItem->addSubProperty(nameItem);
-
- QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
- availItem->setValue(ctx->checkPipAvail(pip));
- topItem->addSubProperty(availItem);
-
- QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net");
- cellItem->setValue(ctx->getBoundPipNet(pip).c_str(ctx));
- topItem->addSubProperty(cellItem);
+ QtProperty *topItem = addTopLevelProperty("Pip");
- QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net");
- conflictItem->setValue(ctx->getConflictingPipNet(pip).c_str(ctx));
- topItem->addSubProperty(conflictItem);
-
- QtVariantProperty *srcWireItem = readOnlyManager->addProperty(QVariant::String, "Src Wire");
- srcWireItem->setValue(ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx));
- topItem->addSubProperty(srcWireItem);
-
- QtVariantProperty *destWireItem = readOnlyManager->addProperty(QVariant::String, "Dest Wire");
- destWireItem->setValue(ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx));
- topItem->addSubProperty(destWireItem);
+ addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
+ addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
+ addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundPipNet(pip).c_str(ctx), ElementType::NET);
+ addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingPipNet(pip).c_str(ctx),
+ ElementType::NET);
+ addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
+ ElementType::WIRE);
+ addProperty(topItem, QVariant::String, "Dest Wire", ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx),
+ ElementType::WIRE);
DelayInfo delay = ctx->getPipDelay(pip);
- QtProperty *delayItem = groupManager->addProperty("Delay");
- topItem->addSubProperty(delayItem);
-
- QtVariantProperty *raiseDelayItem = readOnlyManager->addProperty(QVariant::Double, "Raise");
- raiseDelayItem->setValue(delay.raiseDelay());
- delayItem->addSubProperty(raiseDelayItem);
-
- QtVariantProperty *fallDelayItem = readOnlyManager->addProperty(QVariant::Double, "Fall");
- fallDelayItem->setValue(delay.fallDelay());
- delayItem->addSubProperty(fallDelayItem);
-
- QtVariantProperty *avgDelayItem = readOnlyManager->addProperty(QVariant::Double, "Average");
- avgDelayItem->setValue(delay.avgDelay());
- delayItem->addSubProperty(avgDelayItem);
+ QtProperty *delayItem = addSubGroup(topItem, "Delay");
+ addProperty(delayItem, QVariant::Double, "Raise", delay.raiseDelay());
+ addProperty(delayItem, QVariant::Double, "Fall", delay.fallDelay());
+ addProperty(delayItem, QVariant::Double, "Average", delay.avgDelay());
} else if (type == ElementType::NET) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
NetInfo *net = ctx->nets.at(c).get();
- QtProperty *topItem = groupManager->addProperty("Net");
- addProperty(topItem, "Net");
-
- QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
- nameItem->setValue(net->name.c_str(ctx));
- topItem->addSubProperty(nameItem);
-
- QtProperty *driverItem = groupManager->addProperty("Driver");
- topItem->addSubProperty(driverItem);
-
- QtVariantProperty *portItem = readOnlyManager->addProperty(QVariant::String, "Port");
- portItem->setValue(net->driver.port.c_str(ctx));
- driverItem->addSubProperty(portItem);
+ QtProperty *topItem = addTopLevelProperty("Net");
- QtVariantProperty *budgetItem = readOnlyManager->addProperty(QVariant::Double, "Budget");
- budgetItem->setValue(net->driver.budget);
- driverItem->addSubProperty(budgetItem);
+ addProperty(topItem, QVariant::String, "Name", net->name.c_str(ctx));
- QtVariantProperty *cellNameItem = readOnlyManager->addProperty(QVariant::String, "Cell");
+ QtProperty *driverItem = addSubGroup(topItem, "Driver");
+ addProperty(driverItem, QVariant::String, "Port", net->driver.port.c_str(ctx));
+ addProperty(driverItem, QVariant::Double, "Budget", net->driver.budget);
if (net->driver.cell)
- cellNameItem->setValue(net->driver.cell->name.c_str(ctx));
+ addProperty(driverItem, QVariant::String, "Cell", net->driver.cell->name.c_str(ctx), ElementType::CELL);
else
- cellNameItem->setValue("");
- driverItem->addSubProperty(cellNameItem);
+ addProperty(driverItem, QVariant::String, "Cell", "", ElementType::CELL);
- QtProperty *usersItem = groupManager->addProperty("Users");
- topItem->addSubProperty(usersItem);
+ QtProperty *usersItem = addSubGroup(topItem, "Users");
for (auto &item : net->users) {
- QtProperty *portItem = groupManager->addProperty(item.port.c_str(ctx));
- usersItem->addSubProperty(portItem);
+ QtProperty *portItem = addSubGroup(usersItem, item.port.c_str(ctx));
- QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Port");
- nameItem->setValue(item.port.c_str(ctx));
- portItem->addSubProperty(nameItem);
-
- QtVariantProperty *budgetItem = readOnlyManager->addProperty(QVariant::Double, "Budget");
- budgetItem->setValue(item.budget);
- portItem->addSubProperty(budgetItem);
-
- QtVariantProperty *userItem = readOnlyManager->addProperty(QVariant::String, "Cell");
+ addProperty(portItem, QVariant::String, "Port", item.port.c_str(ctx));
+ addProperty(portItem, QVariant::Double, "Budget", item.budget);
if (item.cell)
- userItem->setValue(item.cell->name.c_str(ctx));
+ addProperty(portItem, QVariant::String, "Cell", item.cell->name.c_str(ctx), ElementType::CELL);
else
- userItem->setValue("");
- portItem->addSubProperty(userItem);
+ addProperty(portItem, QVariant::String, "Cell", "", ElementType::CELL);
}
- QtProperty *attrsItem = groupManager->addProperty("Attributes");
- topItem->addSubProperty(attrsItem);
+ QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : net->attrs) {
- QtVariantProperty *attrItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx));
- attrItem->setValue(item.second.c_str());
- attrsItem->addSubProperty(attrItem);
+ addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
- QtProperty *wiresItem = groupManager->addProperty("Wires");
- topItem->addSubProperty(wiresItem);
+ QtProperty *wiresItem = addSubGroup(topItem, "Wires");
for (auto &item : net->wires) {
auto name = ctx->getWireName(item.first).c_str(ctx);
- QtProperty *wireItem = groupManager->addProperty(name);
-
- QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
- nameItem->setValue(name);
- wireItem->addSubProperty(nameItem);
-
- QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, "Pip");
+ QtProperty *wireItem = addSubGroup(wiresItem, name);
+ addProperty(wireItem, QVariant::String, "Name", name);
if (item.second.pip != PipId())
- pipItem->setValue(ctx->getPipName(item.second.pip).c_str(ctx));
+ addProperty(wireItem, QVariant::String, "Pip", ctx->getPipName(item.second.pip).c_str(ctx),
+ ElementType::PIP);
else
- pipItem->setValue("");
- wireItem->addSubProperty(pipItem);
+ addProperty(wireItem, QVariant::String, "Pip", "", ElementType::PIP);
- QtVariantProperty *strengthItem = readOnlyManager->addProperty(QVariant::Int, "Strength");
- strengthItem->setValue((int)item.second.strength);
- wireItem->addSubProperty(strengthItem);
-
- wiresItem->addSubProperty(wireItem);
+ addProperty(wireItem, QVariant::Int, "Strength", (int)item.second.strength);
}
} else if (type == ElementType::CELL) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
CellInfo *cell = ctx->cells.at(c).get();
- QtProperty *topItem = groupManager->addProperty("Cell");
- addProperty(topItem, "Cell");
-
- QtVariantProperty *cellNameItem = readOnlyManager->addProperty(QVariant::String, "Name");
- cellNameItem->setValue(cell->name.c_str(ctx));
- topItem->addSubProperty(cellNameItem);
-
- QtVariantProperty *cellTypeItem = readOnlyManager->addProperty(QVariant::String, "Type");
- cellTypeItem->setValue(cell->type.c_str(ctx));
- topItem->addSubProperty(cellTypeItem);
+ QtProperty *topItem = addTopLevelProperty("Cell");
- QtVariantProperty *cellBelItem = readOnlyManager->addProperty(QVariant::String, "Bel");
+ addProperty(topItem, QVariant::String, "Name", cell->name.c_str(ctx));
+ addProperty(topItem, QVariant::String, "Type", cell->type.c_str(ctx));
if (cell->bel != BelId())
- cellBelItem->setValue(ctx->getBelName(cell->bel).c_str(ctx));
+ addProperty(topItem, QVariant::String, "Bel", ctx->getBelName(cell->bel).c_str(ctx), ElementType::BEL);
else
- cellBelItem->setValue("");
- topItem->addSubProperty(cellBelItem);
+ addProperty(topItem, QVariant::String, "Bel", "", ElementType::BEL);
+ addProperty(topItem, QVariant::Int, "Bel strength", int(cell->belStrength));
- QtVariantProperty *cellBelStrItem = readOnlyManager->addProperty(QVariant::Int, "Bel strength");
- cellBelStrItem->setValue(int(cell->belStrength));
- topItem->addSubProperty(cellBelStrItem);
-
- QtProperty *cellPortsItem = groupManager->addProperty("Ports");
- topItem->addSubProperty(cellPortsItem);
+ QtProperty *cellPortsItem = addSubGroup(topItem, "Ports");
for (auto &item : cell->ports) {
PortInfo p = item.second;
- QtProperty *portInfoItem = groupManager->addProperty(p.name.c_str(ctx));
-
- QtVariantProperty *portInfoNameItem = readOnlyManager->addProperty(QVariant::String, "Name");
- portInfoNameItem->setValue(p.name.c_str(ctx));
- portInfoItem->addSubProperty(portInfoNameItem);
-
- QtVariantProperty *portInfoTypeItem = readOnlyManager->addProperty(QVariant::Int, "Type");
- portInfoTypeItem->setValue(int(p.type));
- portInfoItem->addSubProperty(portInfoTypeItem);
-
- QtVariantProperty *portInfoNetItem = readOnlyManager->addProperty(QVariant::String, "Net");
+ 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));
if (p.net)
- portInfoNetItem->setValue(p.net->name.c_str(ctx));
+ addProperty(portInfoItem, QVariant::String, "Net", p.net->name.c_str(ctx), ElementType::NET);
else
- portInfoNetItem->setValue("");
- portInfoItem->addSubProperty(portInfoNetItem);
-
- cellPortsItem->addSubProperty(portInfoItem);
+ addProperty(portInfoItem, QVariant::String, "Net", "", ElementType::NET);
}
- QtProperty *cellAttrItem = groupManager->addProperty("Attributes");
- topItem->addSubProperty(cellAttrItem);
+ QtProperty *cellAttrItem = addSubGroup(topItem, "Attributes");
for (auto &item : cell->attrs) {
- QtVariantProperty *attrItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx));
- attrItem->setValue(item.second.c_str());
- cellAttrItem->addSubProperty(attrItem);
+ addProperty(cellAttrItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
- QtProperty *cellParamsItem = groupManager->addProperty("Parameters");
- topItem->addSubProperty(cellParamsItem);
+ QtProperty *cellParamsItem = addSubGroup(topItem, "Parameters");
for (auto &item : cell->params) {
- QtVariantProperty *paramItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx));
- paramItem->setValue(item.second.c_str());
- cellParamsItem->addSubProperty(paramItem);
+ addProperty(cellParamsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
QtProperty *cellPinsItem = groupManager->addProperty("Pins");
@@ -652,38 +667,159 @@ void DesignWidget::onItemSelectionChanged()
std::string cell_port = item.first.c_str(ctx);
std::string bel_pin = item.second.c_str(ctx);
- QtProperty *pinGroupItem = groupManager->addProperty((cell_port + " -> " + bel_pin).c_str());
+ QtProperty *pinGroupItem = addSubGroup(cellPortsItem, (cell_port + " -> " + bel_pin).c_str());
+
+ addProperty(pinGroupItem, QVariant::String, "Cell", cell_port.c_str(), ElementType::CELL);
+ addProperty(pinGroupItem, QVariant::String, "Bel", bel_pin.c_str(), ElementType::BEL);
+ }
+ }
+}
+
+std::vector<DecalXY> DesignWidget::getDecals(ElementType type, IdString value)
+{
+ std::vector<DecalXY> decals;
+ switch (type) {
+ case ElementType::BEL: {
+ BelId bel = ctx->getBelByName(value);
+ if (bel != BelId()) {
+ decals.push_back(ctx->getBelDecal(bel));
+ }
+ } break;
+ case ElementType::WIRE: {
+ WireId wire = ctx->getWireByName(value);
+ if (wire != WireId()) {
+ decals.push_back(ctx->getWireDecal(wire));
+ Q_EMIT selected(decals);
+ }
+ } break;
+ case ElementType::PIP: {
+ PipId pip = ctx->getPipByName(value);
+ if (pip != PipId()) {
+ decals.push_back(ctx->getPipDecal(pip));
+ Q_EMIT selected(decals);
+ }
+ } break;
+ case ElementType::NET: {
+ } break;
+ case ElementType::CELL: {
+ } break;
+ default:
+ break;
+ }
+ return decals;
+}
- QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Cell");
- cellItem->setValue(cell_port.c_str());
- pinGroupItem->addSubProperty(cellItem);
+void DesignWidget::updateHighlightGroup(QTreeWidgetItem *item, int group)
+{
+ if (highlightSelected.contains(item)) {
+ if (highlightSelected[item] == group) {
+ highlightSelected.remove(item);
+ } else
+ highlightSelected[item] = group;
+ } else
+ highlightSelected.insert(item, group);
- QtVariantProperty *belItem = readOnlyManager->addProperty(QVariant::String, "Bel");
- belItem->setValue(bel_pin.c_str());
- pinGroupItem->addSubProperty(belItem);
+ std::vector<DecalXY> decals;
- cellPinsItem->addSubProperty(pinGroupItem);
+ for (auto it : highlightSelected.toStdMap()) {
+ if (it.second == group) {
+ ElementType type = static_cast<ElementTreeItem *>(it.first)->getType();
+ IdString value = static_cast<IdStringTreeItem *>(it.first)->getData();
+ std::vector<DecalXY> d = getDecals(type, value);
+ std::move(d.begin(), d.end(), std::back_inserter(decals));
}
}
+
+ Q_EMIT highlight(decals, group);
}
-void DesignWidget::prepareMenu(const QPoint &pos)
+void DesignWidget::prepareMenuProperty(const QPoint &pos)
{
- QTreeWidget *tree = treeWidget;
+ QTreeWidget *tree = propertyEditor->treeWidget();
itemContextMenu = tree->itemAt(pos);
+ if (itemContextMenu->parent() == nullptr)
+ return;
- QAction *selectAction = new QAction("&Select", this);
- selectAction->setStatusTip("Select item on view");
+ QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu);
+ if (!browserItem)
+ return;
+ QtProperty *selectedProperty = browserItem->property();
+ ElementType type = getElementTypeByName(selectedProperty->propertyId());
+ if (type == ElementType::NONE)
+ return;
+ IdString value = ctx->id(selectedProperty->valueText().toStdString());
- connect(selectAction, SIGNAL(triggered()), this, SLOT(selectObject()));
+ QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx));
QMenu menu(this);
+ QAction *selectAction = new QAction("&Select", this);
+ connect(selectAction, &QAction::triggered, this, [this, type, value] { Q_EMIT selected(getDecals(type, value)); });
menu.addAction(selectAction);
+ QMenu *subMenu = menu.addMenu("Highlight");
+ QActionGroup *group = new QActionGroup(this);
+ group->setExclusive(true);
+ for (int i = 0; i < 8; i++) {
+ QPixmap pixmap(32, 32);
+ pixmap.fill(QColor(highlightColors[i]));
+ QAction *action = new QAction(QIcon(pixmap), ("Group " + std::to_string(i)).c_str(), this);
+ action->setCheckable(true);
+ subMenu->addAction(action);
+ group->addAction(action);
+ if (highlightSelected.contains(item) && highlightSelected[item] == i)
+ action->setChecked(true);
+ connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); });
+ }
+ menu.exec(tree->mapToGlobal(pos));
+}
+
+void DesignWidget::prepareMenuTree(const QPoint &pos)
+{
+ QTreeWidget *tree = treeWidget;
+
+ itemContextMenu = tree->itemAt(pos);
+
+ ElementType type = static_cast<ElementTreeItem *>(itemContextMenu)->getType();
+ IdString value = static_cast<IdStringTreeItem *>(itemContextMenu)->getData();
+
+ if (type == ElementType::NONE)
+ return;
+
+ QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx));
+
+ QMenu menu(this);
+ QMenu *subMenu = menu.addMenu("Highlight");
+ QActionGroup *group = new QActionGroup(this);
+ group->setExclusive(true);
+ for (int i = 0; i < 8; i++) {
+ QPixmap pixmap(32, 32);
+ pixmap.fill(QColor(highlightColors[i]));
+ QAction *action = new QAction(QIcon(pixmap), ("Group " + std::to_string(i)).c_str(), this);
+ action->setCheckable(true);
+ subMenu->addAction(action);
+ group->addAction(action);
+ if (highlightSelected.contains(item) && highlightSelected[item] == i)
+ action->setChecked(true);
+ connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); });
+ }
menu.exec(tree->mapToGlobal(pos));
}
-void DesignWidget::selectObject() { Q_EMIT info("selected " + itemContextMenu->text(0).toStdString() + "\n"); }
+void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column)
+{
+ QtProperty *selectedProperty = propertyEditor->itemToBrowserItem(item)->property();
+ ElementType type = getElementTypeByName(selectedProperty->propertyId());
+ QString value = selectedProperty->valueText();
+ int index = getElementIndex(type);
+ switch (type) {
+ case ElementType::NONE:
+ return;
+ default: {
+ if (nameToItem[index].contains(value))
+ treeWidget->setCurrentItem(nameToItem[index].value(value));
+ } break;
+ }
+}
NEXTPNR_NAMESPACE_END
diff --git a/gui/designwidget.h b/gui/designwidget.h
index 618c7bbf..1afe817d 100644
--- a/gui/designwidget.h
+++ b/gui/designwidget.h
@@ -21,6 +21,7 @@
#define DESIGNWIDGET_H
#include <QTreeWidget>
+#include <QVariant>
#include "nextpnr.h"
#include "qtgroupboxpropertybrowser.h"
#include "qtpropertymanager.h"
@@ -29,6 +30,16 @@
NEXTPNR_NAMESPACE_BEGIN
+enum class ElementType
+{
+ NONE,
+ BEL,
+ WIRE,
+ PIP,
+ NET,
+ CELL
+};
+
class DesignWidget : public QWidget
{
Q_OBJECT
@@ -38,17 +49,30 @@ class DesignWidget : public QWidget
~DesignWidget();
private:
- void addProperty(QtProperty *property, const QString &id);
void clearProperties();
-
+ QtProperty *addTopLevelProperty(const QString &id);
+ QtProperty *addSubGroup(QtProperty *topItem, const QString &name);
+ void addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value,
+ const ElementType &type = ElementType::NONE);
+ QString getElementTypeName(ElementType type);
+ ElementType getElementTypeByName(QString type);
+ int getElementIndex(ElementType type);
+ void updateButtons();
+ void addToHistory(QTreeWidgetItem *item);
+ std::vector<DecalXY> getDecals(ElementType type, IdString value);
+ void updateHighlightGroup(QTreeWidgetItem *item, int group);
Q_SIGNALS:
void info(std::string text);
void selected(std::vector<DecalXY> decal);
+ void highlight(std::vector<DecalXY> decal, int group);
+ void finishContextLoad();
+ void contextLoadStatus(std::string text);
private Q_SLOTS:
- void prepareMenu(const QPoint &pos);
+ void prepareMenuProperty(const QPoint &pos);
+ void prepareMenuTree(const QPoint &pos);
void onItemSelectionChanged();
- void selectObject();
+ void onItemDoubleClicked(QTreeWidgetItem *item, int column);
public Q_SLOTS:
void newContext(Context *ctx);
void updateTree();
@@ -67,6 +91,12 @@ class DesignWidget : public QWidget
QMap<QtProperty *, QString> propertyToId;
QMap<QString, QtProperty *> idToProperty;
+
+ QMap<QString, QTreeWidgetItem *> nameToItem[6];
+ std::vector<QTreeWidgetItem *> history;
+ int history_index;
+ bool history_ignore;
+
QTreeWidgetItem *nets_root;
QTreeWidgetItem *cells_root;
@@ -74,6 +104,9 @@ class DesignWidget : public QWidget
QAction *actionPrev;
QAction *actionNext;
QAction *actionLast;
+
+ QColor highlightColors[8];
+ QMap<QTreeWidgetItem *, int> highlightSelected;
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index 1d0e8b57..2d8d4cef 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -240,7 +240,8 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi
vao_.release();
}
-FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged(false)
+FPGAViewWidget::FPGAViewWidget(QWidget *parent)
+ : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged_(false)
{
backgroundColor_ = QColor("#000000");
gridColor_ = QColor("#333");
@@ -250,6 +251,16 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha
gActiveColor_ = QColor("#f0f0f0");
gSelectedColor_ = QColor("#ff6600");
frameColor_ = QColor("#0066ba");
+ highlightColors[0] = QColor("#6495ed");
+ highlightColors[1] = QColor("#7fffd4");
+ highlightColors[2] = QColor("#98fb98");
+ highlightColors[3] = QColor("#ffd700");
+ highlightColors[4] = QColor("#cd5c5c");
+ highlightColors[5] = QColor("#fa8072");
+ highlightColors[6] = QColor("#ff69b4");
+ highlightColors[7] = QColor("#da70d6");
+ for (int i = 0; i < 8; i++)
+ highlightItemsChanged_[i] = false;
auto fmt = format();
fmt.setMajorVersion(3);
@@ -272,6 +283,7 @@ FPGAViewWidget::~FPGAViewWidget() {}
void FPGAViewWidget::newContext(Context *ctx)
{
ctx_ = ctx;
+ selectedItems_.clear();
update();
}
@@ -411,27 +423,44 @@ void FPGAViewWidget::paintGL()
drawDecal(shaders, ctx_->getGroupDecal(group));
}
- if (selectedItemsChanged)
- {
- selectedItemsChanged = false;
+ if (selectedItemsChanged_) {
+ selectedItemsChanged_ = false;
selectedShader_.clear();
for (auto decal : selectedItems_) {
drawDecal(selectedShader_, decal);
}
}
+ for (int i = 0; i < 8; i++) {
+ if (highlightItemsChanged_[i]) {
+ highlightItemsChanged_[i] = false;
+ highlightShader_[i].clear();
+ for (auto decal : highlightItems_[i]) {
+ drawDecal(highlightShader_[i], decal);
+ }
+ }
+ }
}
lineShader_.draw(shaders[0], gFrameColor_, thick11Px, matrix);
lineShader_.draw(shaders[1], gHiddenColor_, thick11Px, matrix);
lineShader_.draw(shaders[2], gInactiveColor_, thick11Px, matrix);
lineShader_.draw(shaders[3], gActiveColor_, thick11Px, matrix);
+ for (int i = 0; i < 8; i++)
+ lineShader_.draw(highlightShader_[i], highlightColors[i], thick11Px, matrix);
lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix);
}
void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals)
{
selectedItems_ = decals;
- selectedItemsChanged = true;
+ selectedItemsChanged_ = true;
+ update();
+}
+
+void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int group)
+{
+ highlightItems_[group] = decals;
+ highlightItemsChanged_[group] = true;
update();
}
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h
index dd86277e..33eb2800 100644
--- a/gui/fpgaviewwidget.h
+++ b/gui/fpgaviewwidget.h
@@ -245,6 +245,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
public Q_SLOTS:
void newContext(Context *ctx);
void onSelectedArchItem(std::vector<DecalXY> decals);
+ void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
+
private:
QPoint lastPos_;
LineShader lineShader_;
@@ -272,7 +274,12 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
LineShaderData selectedShader_;
std::vector<DecalXY> selectedItems_;
- bool selectedItemsChanged;
+ bool selectedItemsChanged_;
+
+ LineShaderData highlightShader_[8];
+ std::vector<DecalXY> highlightItems_[8];
+ bool highlightItemsChanged_[8];
+ QColor highlightColors[8];
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc
index 772ca6ac..4b1f2c57 100644
--- a/gui/ice40/mainwindow.cc
+++ b/gui/ice40/mainwindow.cc
@@ -71,43 +71,43 @@ void MainWindow::createMenu()
QMenu *menu_Design = new QMenu("&Design", menuBar);
menuBar->addAction(menu_Design->menuAction());
- actionLoadJSON = new QAction("Open JSON", this);
+ actionLoadJSON = new QAction("Open JSON", this);
actionLoadJSON->setIcon(QIcon(":/icons/resources/open_json.png"));
actionLoadJSON->setStatusTip("Open an existing JSON file");
actionLoadJSON->setEnabled(true);
connect(actionLoadJSON, SIGNAL(triggered()), this, SLOT(open_json()));
- actionLoadPCF = new QAction("Open PCF", this);
+ actionLoadPCF = new QAction("Open PCF", this);
actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png"));
actionLoadPCF->setStatusTip("Open PCF file");
actionLoadPCF->setEnabled(false);
connect(actionLoadPCF, SIGNAL(triggered()), this, SLOT(open_pcf()));
- actionPack = new QAction("Pack", this);
+ actionPack = new QAction("Pack", this);
actionPack->setIcon(QIcon(":/icons/resources/pack.png"));
actionPack->setStatusTip("Pack current design");
actionPack->setEnabled(false);
connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack()));
- actionAssignBudget = new QAction("Assign Budget", this);
+ actionAssignBudget = new QAction("Assign Budget", this);
actionAssignBudget->setIcon(QIcon(":/icons/resources/time_add.png"));
actionAssignBudget->setStatusTip("Assign time budget for current design");
actionAssignBudget->setEnabled(false);
connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget()));
- actionPlace = new QAction("Place", this);
+ actionPlace = new QAction("Place", this);
actionPlace->setIcon(QIcon(":/icons/resources/place.png"));
actionPlace->setStatusTip("Place current design");
actionPlace->setEnabled(false);
connect(actionPlace, SIGNAL(triggered()), this, SLOT(place()));
- actionRoute = new QAction("Route", this);
+ actionRoute = new QAction("Route", this);
actionRoute->setIcon(QIcon(":/icons/resources/route.png"));
actionRoute->setStatusTip("Route current design");
actionRoute->setEnabled(false);
connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route()));
- actionSaveAsc = new QAction("Save ASC", this);
+ actionSaveAsc = new QAction("Save ASC", this);
actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png"));
actionSaveAsc->setStatusTip("Save ASC file");
actionSaveAsc->setEnabled(false);
@@ -132,19 +132,19 @@ void MainWindow::createMenu()
menu_Design->addAction(actionRoute);
menu_Design->addAction(actionSaveAsc);
- actionPlay = new QAction("Play", this);
+ actionPlay = new QAction("Play", this);
actionPlay->setIcon(QIcon(":/icons/resources/control_play.png"));
actionPlay->setStatusTip("Continue running task");
actionPlay->setEnabled(false);
connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread()));
- actionPause = new QAction("Pause", this);
+ actionPause = new QAction("Pause", this);
actionPause->setIcon(QIcon(":/icons/resources/control_pause.png"));
actionPause->setStatusTip("Pause running task");
actionPause->setEnabled(false);
connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread()));
- actionStop = new QAction("Stop", this);
+ actionStop = new QAction("Stop", this);
actionStop->setIcon(QIcon(":/icons/resources/control_stop.png"));
actionStop->setStatusTip("Stop running task");
actionStop->setEnabled(false);
@@ -226,6 +226,7 @@ void MainWindow::new_proj()
ctx = std::unique_ptr<Context>(new Context(chipArgs));
actionLoadJSON->setEnabled(true);
+ Q_EMIT displaySplash();
Q_EMIT contextChanged(ctx.get());
}
}
diff --git a/gui/resources/splash.png b/gui/resources/splash.png
new file mode 100644
index 00000000..14d2842b
--- /dev/null
+++ b/gui/resources/splash.png
Binary files differ
diff --git a/ice40/arch.cc b/ice40/arch.cc
index c9cda40d..08e32ae6 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -334,6 +334,7 @@ IdString Arch::getPipName(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
+#if 1
int x = chip_info->pip_data[pip.index].x;
int y = chip_info->pip_data[pip.index].y;
@@ -344,6 +345,9 @@ IdString Arch::getPipName(PipId pip) const
std::replace(dst_name.begin(), dst_name.end(), '/', '.');
return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
+#else
+ return id(chip_info->pip_data[pip.index].name.get());
+#endif
}
// -----------------------------------------------------------------------
@@ -480,9 +484,9 @@ DecalXY Arch::getWireDecal(WireId wire) const
DecalXY Arch::getPipDecal(PipId pip) const
{
DecalXY decalxy;
- decalxy.decal.type = DecalId::TYPE_PIP;
- decalxy.decal.index = pip.index;
- decalxy.decal.active = pip_to_net.at(pip.index) != IdString();
+ // decalxy.decal.type = DecalId::TYPE_PIP;
+ // decalxy.decal.index = pip.index;
+ // decalxy.decal.active = pip_to_net.at(pip.index) != IdString();
return decalxy;
};
@@ -512,11 +516,8 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
}
if (decal.type == DecalId::TYPE_WIRE) {
- WireId wire;
- wire.index = decal.index;
-
- int n = chip_info->wire_data[wire.index].num_segments;
- const WireSegmentPOD *p = chip_info->wire_data[wire.index].segments.get();
+ int n = chip_info->wire_data[decal.index].num_segments;
+ const WireSegmentPOD *p = chip_info->wire_data[decal.index].segments.get();
GraphicElement::style_t style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE;
@@ -524,6 +525,12 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style);
}
+ if (decal.type == DecalId::TYPE_PIP) {
+ const PipInfoPOD &p = chip_info->pip_data[decal.index];
+ GraphicElement::style_t style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_HIDDEN;
+ gfxTilePip(ret, p.x, p.y, GfxTileWireId(p.src_seg), GfxTileWireId(p.dst_seg), style);
+ }
+
if (decal.type == DecalId::TYPE_BEL) {
BelId bel;
bel.index = decal.index;
diff --git a/ice40/arch.h b/ice40/arch.h
index a02e0ced..5dab414b 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -63,9 +63,11 @@ NPNR_PACKED_STRUCT(struct BelPortPOD {
});
NPNR_PACKED_STRUCT(struct PipInfoPOD {
+ // RelPtr<char> name;
int32_t src, dst;
int32_t delay;
int8_t x, y;
+ int16_t src_seg, dst_seg;
int16_t switch_mask;
int32_t switch_index;
});
diff --git a/ice40/chipdb.py b/ice40/chipdb.py
index 51fe169c..698cd173 100644
--- a/ice40/chipdb.py
+++ b/ice40/chipdb.py
@@ -390,9 +390,9 @@ with open(args.filename, "r") as f:
wire_xy[mode[1]] = list()
wire_xy[mode[1]].append((int(line[0]), int(line[1])))
if mode[1] not in wire_segments:
- wire_segments[mode[1]] = set()
+ wire_segments[mode[1]] = dict()
if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids:
- wire_segments[mode[1]].add((wname[0], wname[1], gfx_wire_ids["TILE_WIRE_" + wname[2].upper().replace("/", "_")]))
+ wire_segments[mode[1]][(wname[0], wname[1])] = wname[2]
continue
if mode[0] in ("buffer", "routing"):
@@ -1077,6 +1077,7 @@ for wire, info in enumerate(wireinfo):
bba.r("wire_segments_%d" % wire, "segments")
else:
bba.u32(0, "segments")
+
bba.u8(info["x"], "x")
bba.u8(info["y"], "y")
bba.u8(wiretypes[wire_type(info["name"])], "type")
@@ -1085,18 +1086,35 @@ for wire, info in enumerate(wireinfo):
for wire in range(num_wires):
if len(wire_segments[wire]):
bba.l("wire_segments_%d" % wire, "WireSegmentPOD")
- for seg in sorted(wire_segments[wire]):
- bba.u8(seg[0], "x")
- bba.u8(seg[1], "y")
- bba.u16(seg[2], "index")
+ for xy, seg in sorted(wire_segments[wire].items()):
+ bba.u8(xy[0], "x")
+ bba.u8(xy[1], "y")
+ bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index")
bba.l("pip_data_%s" % dev_name, "PipInfoPOD")
for info in pipinfo:
+ src_seg = -1
+ src_segname = wire_names_r[info["src"]]
+ if (info["x"], info["y"]) in wire_segments[info["src"]]:
+ src_segname = wire_segments[info["src"]][(info["x"], info["y"])]
+ src_seg = gfx_wire_ids["TILE_WIRE_" + src_segname.upper().replace("/", "_")]
+ src_segname = src_segname.replace("/", ".")
+
+ dst_seg = -1
+ dst_segname = wire_names_r[info["dst"]]
+ if (info["x"], info["y"]) in wire_segments[info["dst"]]:
+ dst_segname = wire_segments[info["dst"]][(info["x"], info["y"])]
+ dst_seg = gfx_wire_ids["TILE_WIRE_" + dst_segname.upper().replace("/", "_")]
+ dst_segname = dst_segname.replace("/", ".")
+
+ # bba.s("X%d/Y%d/%s->%s" % (info["x"], info["y"], src_segname, dst_segname), "name")
bba.u32(info["src"], "src")
bba.u32(info["dst"], "dst")
bba.u32(info["delay"], "delay")
bba.u8(info["x"], "x")
bba.u8(info["y"], "y")
+ bba.u16(src_seg, "src_seg")
+ bba.u16(dst_seg, "dst_seg")
bba.u16(info["switch_mask"], "switch_mask")
bba.u32(info["switch_index"], "switch_index")
diff --git a/ice40/gfx.cc b/ice40/gfx.cc
index 19aaed13..aa2fc9ce 100644
--- a/ice40/gfx.cc
+++ b/ice40/gfx.cc
@@ -485,4 +485,223 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
}
}
+static bool getWireXY_main(GfxTileWireId id, float &x, float &y)
+{
+ // Horizontal Span-4 Wires
+
+ if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) {
+ int idx = (id - TILE_WIRE_SP4_H_L_36) + 48;
+ x = main_swbox_x1 + 0.0025 * (idx + 35);
+ y = main_swbox_y2;
+ return true;
+ }
+
+ if (id >= TILE_WIRE_SP4_H_R_0 && id <= TILE_WIRE_SP4_H_R_47) {
+ int idx = id - TILE_WIRE_SP4_H_R_0;
+ x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35);
+ y = main_swbox_y2;
+ return true;
+ }
+
+ // Vertical Span-4 Wires
+
+ if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) {
+ int idx = (id - TILE_WIRE_SP4_V_T_36) + 48;
+ y = 1.0 - (0.03 + 0.0025 * (270 - idx));
+ x = main_swbox_x1;
+ return true;
+ }
+
+ if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) {
+ int idx = id - TILE_WIRE_SP4_V_B_0;
+ y = 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1)));
+ x = main_swbox_x1;
+ return true;
+ }
+
+ // Horizontal Span-12 Wires
+
+ if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) {
+ int idx = (id - TILE_WIRE_SP12_H_L_22) + 24;
+ x = main_swbox_x1 + 0.0025 * (idx + 5);
+ y = main_swbox_y2;
+ return true;
+ }
+
+ if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) {
+ int idx = id - TILE_WIRE_SP12_H_R_0;
+ x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5);
+ y = main_swbox_y2;
+ return true;
+ }
+
+ // Vertical Right Span-4
+
+ if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) {
+ int idx = id - TILE_WIRE_SP4_R_V_B_0;
+ y = 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1)));
+ x = main_swbox_x2;
+ return true;
+ }
+
+ // Vertical Span-12 Wires
+
+ if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) {
+ int idx = (id - TILE_WIRE_SP12_V_T_22) + 24;
+ y = 1.0 - (0.03 + 0.0025 * (300 - idx));
+ x = main_swbox_x1;
+ return true;
+ }
+
+ if (id >= TILE_WIRE_SP12_V_B_0 && id <= TILE_WIRE_SP12_V_B_23) {
+ int idx = id - TILE_WIRE_SP12_V_B_0;
+ y = 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1)));
+ x = main_swbox_x1;
+ return true;
+ }
+
+ // Global2Local
+
+ if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) {
+ int idx = id - TILE_WIRE_GLB2LOCAL_0;
+ x = main_swbox_x1 + 0.005 * (idx + 5);
+ y = main_swbox_y1;
+ return true;
+ }
+
+ // GlobalNets
+
+ if (id >= TILE_WIRE_GLB_NETWK_0 && id <= TILE_WIRE_GLB_NETWK_7) {
+ int idx = id - TILE_WIRE_GLB_NETWK_0;
+ x = main_swbox_x1;
+ y = main_swbox_y1 + 0.005 * (13 - idx);
+ return true;
+ }
+
+ // Neighbours
+
+ if (id >= TILE_WIRE_NEIGH_OP_BNL_0 && id <= TILE_WIRE_NEIGH_OP_TOP_7) {
+ int idx = id - TILE_WIRE_NEIGH_OP_BNL_0;
+ y = main_swbox_y2 - (0.0025 * (idx + 10) + 0.01 * (idx / 8));
+ x = main_swbox_x1;
+ return true;
+ }
+
+ // Local Tracks
+
+ if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) {
+ int idx = id - TILE_WIRE_LOCAL_G0_0;
+ float yoff = (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075;
+ x = main_swbox_x2;
+ y = yoff + 0.005 * idx + 0.05 * (idx / 8);
+ return true;
+ }
+
+ // LC Outputs
+
+ if (id >= TILE_WIRE_LUTFF_0_OUT && id <= TILE_WIRE_LUTFF_7_OUT) {
+ int idx = id - TILE_WIRE_LUTFF_0_OUT;
+ y = 1.0 - (0.03 + 0.0025 * (152 + idx));
+ x = main_swbox_x2;
+ return true;
+ }
+
+ // LC Control
+
+ if (id >= TILE_WIRE_LUTFF_GLOBAL_CEN && id <= TILE_WIRE_LUTFF_GLOBAL_S_R) {
+ int idx = id - TILE_WIRE_LUTFF_GLOBAL_CEN;
+ x = main_swbox_x2 - 0.005 * (idx + 5);
+ y = main_swbox_y1;
+ return true;
+ }
+
+ return false;
+}
+
+static bool getWireXY_local(GfxTileWireId id, float &x, float &y)
+{
+ if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) {
+ int idx = id - TILE_WIRE_LOCAL_G0_0;
+ float yoff = (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075;
+ x = local_swbox_x1;
+ y = yoff + 0.005 * idx + 0.05 * (idx / 8);
+ return true;
+ }
+
+ if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) {
+ int idx = id - TILE_WIRE_LUTFF_0_IN_0;
+ int z = idx / 4;
+ int input = idx % 4;
+ x = local_swbox_x2;
+ y = (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch;
+ return true;
+ }
+
+ return false;
+}
+
+void pipGfx(std::vector<GraphicElement> &g, int x, int y,
+ float x1, float y1, float x2, float y2,
+ float swx1, float swy1, float swx2, float swy2,
+ GraphicElement::style_t style)
+{
+ float tx = 0.5 * (x1 + x2);
+ float ty = 0.5 * (y1 + y2);
+
+ GraphicElement el;
+ el.type = GraphicElement::G_LINE;
+ el.style = style;
+
+ if (fabsf(x1 - swx1) < 0.001 && fabsf(x2 - swx1) < 0.001) {
+ tx = x1 + 0.25 * fabsf(y1 - y2);
+ goto edge_pip;
+ }
+
+ if (fabsf(x1 - swx2) < 0.001 && fabsf(x2 - swx2) < 0.001) {
+ tx = x1 - 0.25 * fabsf(y1 - y2);
+ goto edge_pip;
+ }
+
+ if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) {
+ ty = y1 + 0.25 * fabsf(x1 - x2);
+ goto edge_pip;
+ }
+
+ if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) {
+ ty = y1 + 0.25 * fabsf(x1 - x2);
+ goto edge_pip;
+ }
+
+ el.x1 = x + x1;
+ el.y1 = y + y1;
+ el.x2 = x + x2;
+ el.y2 = y + y2;
+ g.push_back(el);
+ return;
+
+edge_pip:
+ el.x1 = x + x1;
+ el.y1 = y + y1;
+ el.x2 = x + tx;
+ el.y2 = y + ty;
+ g.push_back(el);
+
+ el.x1 = x + tx;
+ el.y1 = y + ty;
+ el.x2 = x + x2;
+ el.y2 = y + y2;
+ g.push_back(el);
+}
+
+void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, GraphicElement::style_t style)
+{
+ float x1, y1, x2, y2;
+
+ if (getWireXY_main(src, x1, y1) && getWireXY_main(dst, x2, y2))
+ pipGfx(g, x, y, x1, y1, x2, y2, main_swbox_x1, main_swbox_y1, main_swbox_x2, main_swbox_y2, style);
+
+ if (getWireXY_local(src, x1, y1) && getWireXY_local(dst, x2, y2))
+ pipGfx(g, x, y, x1, y1, x2, y2, local_swbox_x1, local_swbox_y1, local_swbox_x2, local_swbox_y2, style);
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/ice40/gfx.h b/ice40/gfx.h
index a65f7683..a1cbd65b 100644
--- a/ice40/gfx.h
+++ b/ice40/gfx.h
@@ -468,6 +468,7 @@ enum GfxTileWireId
};
void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style);
+void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, GraphicElement::style_t style);
NEXTPNR_NAMESPACE_END