From c9b9d9b22754778beaa1a922f0df3dac42dd8867 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 26 Jul 2018 11:42:05 +0200 Subject: [PATCH 01/21] highlight operation on multiple items --- gui/designwidget.cc | 104 ++++++++++++++++++++++---------------------- gui/designwidget.h | 3 +- 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index c17990a5..f9d231c1 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -775,54 +775,55 @@ std::vector DesignWidget::getDecals(ElementType type, IdString value) return decals; } -void DesignWidget::updateHighlightGroup(QTreeWidgetItem *item, int group) +void DesignWidget::updateHighlightGroup(QList items, int group) { - if (highlightSelected.contains(item)) { - if (highlightSelected[item] == group) { - highlightSelected.remove(item); - } else - highlightSelected[item] = group; - } else - highlightSelected.insert(item, group); - - std::vector decals; + const bool shouldClear = items.size() == 1; + for (auto item : items) { + if (highlightSelected.contains(item)) { + if (shouldClear && highlightSelected[item] == group) { + highlightSelected.remove(item); + } + else + highlightSelected[item] = group; + } + else + highlightSelected.insert(item, group); + } + std::vector decals[8]; for (auto it : highlightSelected.toStdMap()) { - if (it.second == group) { - ElementType type = static_cast(it.first)->getType(); - IdString value = static_cast(it.first)->getData(); - std::vector d = getDecals(type, value); - std::move(d.begin(), d.end(), std::back_inserter(decals)); - } + ElementType type = static_cast(it.first)->getType(); + IdString value = static_cast(it.first)->getData(); + std::vector d = getDecals(type, value); + std::move(d.begin(), d.end(), std::back_inserter(decals[it.second])); } - - Q_EMIT highlight(decals, group); + for (int i=0;i<8;i++) + Q_EMIT highlight(decals[i], i); } void DesignWidget::prepareMenuProperty(const QPoint &pos) { QTreeWidget *tree = propertyEditor->treeWidget(); - - itemContextMenu = tree->itemAt(pos); - if (itemContextMenu->parent() == nullptr) - return; - - 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()); - - QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx)); + QList items; + for (auto itemContextMenu : tree->selectedItems()) { + QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu); + if (!browserItem) + continue; + QtProperty *selectedProperty = browserItem->property(); + ElementType type = getElementTypeByName(selectedProperty->propertyId()); + if (type == ElementType::NONE) + continue; + IdString value = ctx->id(selectedProperty->valueText().toStdString()); + items.append(nameToItem[getElementIndex(type)].value(value.c_str(ctx))); + } + int selectedIndex = -1; + if (items.size() == 1) { + QTreeWidgetItem *item = items.at(0); + if (highlightSelected.contains(item)) + selectedIndex = highlightSelected[item]; + } 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); @@ -833,27 +834,24 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos) action->setCheckable(true); subMenu->addAction(action); group->addAction(action); - if (highlightSelected.contains(item) && highlightSelected[item] == i) + if (selectedIndex == i) action->setChecked(true); - connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); }); + connect(action, &QAction::triggered, this, [this, i, items] { updateHighlightGroup(items, i); }); } menu.exec(tree->mapToGlobal(pos)); } void DesignWidget::prepareMenuTree(const QPoint &pos) { - QTreeWidget *tree = treeWidget; - - itemContextMenu = tree->itemAt(pos); - - ElementType type = static_cast(itemContextMenu)->getType(); - IdString value = static_cast(itemContextMenu)->getData(); - - if (type == ElementType::NONE) + if (treeWidget->selectedItems().size() == 0) return; - - QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx)); - + int selectedIndex = -1; + QList items = treeWidget->selectedItems(); + if (treeWidget->selectedItems().size() == 1) { + QTreeWidgetItem *item = treeWidget->selectedItems().at(0); + if (highlightSelected.contains(item)) + selectedIndex = highlightSelected[item]; + } QMenu menu(this); QMenu *subMenu = menu.addMenu("Highlight"); QActionGroup *group = new QActionGroup(this); @@ -865,11 +863,11 @@ void DesignWidget::prepareMenuTree(const QPoint &pos) action->setCheckable(true); subMenu->addAction(action); group->addAction(action); - if (highlightSelected.contains(item) && highlightSelected[item] == i) + if (selectedIndex == i) action->setChecked(true); - connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); }); + connect(action, &QAction::triggered, this, [this, i, items] { updateHighlightGroup(items, i); }); } - menu.exec(tree->mapToGlobal(pos)); + menu.exec(treeWidget->mapToGlobal(pos)); } void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column) diff --git a/gui/designwidget.h b/gui/designwidget.h index b5877f60..fe340237 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -60,7 +60,7 @@ class DesignWidget : public QWidget void updateButtons(); void addToHistory(QTreeWidgetItem *item); std::vector getDecals(ElementType type, IdString value); - void updateHighlightGroup(QTreeWidgetItem *item, int group); + void updateHighlightGroup(QList item, int group); Q_SIGNALS: void info(std::string text); void selected(std::vector decal); @@ -85,7 +85,6 @@ class DesignWidget : public QWidget QtGroupPropertyManager *groupManager; QtVariantEditorFactory *variantFactory; QtTreePropertyBrowser *propertyEditor; - QTreeWidgetItem *itemContextMenu; QMap propertyToId; QMap idToProperty; From 4587b8c0001d853ab2fb6f820627f1508e28e316 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 26 Jul 2018 13:21:46 +0200 Subject: [PATCH 02/21] added buttons for new zoom operations --- gui/base.qrc | 4 ++++ gui/basewindow.cc | 29 ++++++++++++++++++++-- gui/basewindow.h | 4 ++++ gui/fpgaviewwidget.cc | 41 ++++++++++++++++++++------------ gui/fpgaviewwidget.h | 6 ++++- gui/ice40/mainwindow.cc | 2 ++ gui/resources/shape_handles.png | Bin 0 -> 538 bytes gui/resources/shape_square.png | Bin 0 -> 353 bytes gui/resources/zoom_in.png | Bin 0 -> 725 bytes gui/resources/zoom_out.png | Bin 0 -> 708 bytes 10 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 gui/resources/shape_handles.png create mode 100644 gui/resources/shape_square.png create mode 100644 gui/resources/zoom_in.png create mode 100644 gui/resources/zoom_out.png diff --git a/gui/base.qrc b/gui/base.qrc index 1a848f54..7b3fa55c 100644 --- a/gui/base.qrc +++ b/gui/base.qrc @@ -10,5 +10,9 @@ resources/resultset_next.png resources/resultset_last.png resources/cross.png + resources/zoom_in.png + resources/zoom_out.png + resources/shape_handles.png + resources/shape_square.png diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 78c2fe3a..11a7fe8d 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -25,7 +25,6 @@ #include #include "designwidget.h" #include "fpgaviewwidget.h" -#include "jsonparse.h" #include "log.h" #include "mainwindow.h" #include "pythontab.h" @@ -76,7 +75,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent centralTabWidget->setTabsClosable(true); connect(centralTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); - FPGAViewWidget *fpgaView = new FPGAViewWidget(); + fpgaView = new FPGAViewWidget(); centralTabWidget->addTab(fpgaView, "Graphics"); centralTabWidget->tabBar()->tabButton(0, QTabBar::RightSide)->resize(0, 0); @@ -163,4 +162,30 @@ void BaseMainWindow::createMenusAndBars() mainToolBar->addAction(actionSave); } +void BaseMainWindow::createGraphicsBar() +{ + QAction *actionZoomIn = new QAction("Zoom In", this); + actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png")); + connect(actionZoomIn, SIGNAL(triggered()), fpgaView, SLOT(zoom_in())); + + QAction *actionZoomOut = new QAction("Zoom Out", this); + actionZoomOut->setIcon(QIcon(":/icons/resources/zoom_out.png")); + connect(actionZoomOut, SIGNAL(triggered()), fpgaView, SLOT(zoom_out())); + + QAction *actionZoomSelected = new QAction("Zoom Selected", this); + actionZoomSelected->setIcon(QIcon(":/icons/resources/shape_handles.png")); + connect(actionZoomSelected, SIGNAL(triggered()), fpgaView, SLOT(zoom_selected())); + + QAction *actionZoomOutbound = new QAction("Zoom Outbound", this); + actionZoomOutbound->setIcon(QIcon(":/icons/resources/shape_square.png")); + connect(actionZoomOutbound, SIGNAL(triggered()), fpgaView, SLOT(zoom_outbound())); + + graphicsToolBar = new QToolBar(); + addToolBar(Qt::TopToolBarArea, graphicsToolBar); + graphicsToolBar->addAction(actionZoomIn); + graphicsToolBar->addAction(actionZoomOut); + graphicsToolBar->addAction(actionZoomSelected); + graphicsToolBar->addAction(actionZoomOutbound); +} + NEXTPNR_NAMESPACE_END diff --git a/gui/basewindow.h b/gui/basewindow.h index 1184fa80..a25a2854 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -37,6 +37,7 @@ NEXTPNR_NAMESPACE_BEGIN class PythonTab; class DesignWidget; +class FPGAViewWidget; class BaseMainWindow : public QMainWindow { @@ -49,6 +50,7 @@ class BaseMainWindow : public QMainWindow protected: void createMenusAndBars(); + void createGraphicsBar(); protected Q_SLOTS: void writeInfo(std::string text); @@ -70,12 +72,14 @@ class BaseMainWindow : public QMainWindow QMenuBar *menuBar; QToolBar *mainToolBar; + QToolBar *graphicsToolBar; QStatusBar *statusBar; QAction *actionNew; QAction *actionOpen; QAction *actionSave; QProgressBar *progressBar; DesignWidget *designview; + FPGAViewWidget *fpgaView; }; NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 15f37ce0..e08667f6 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -580,21 +580,32 @@ void FPGAViewWidget::wheelEvent(QWheelEvent *event) { QPoint degree = event->angleDelta() / 8; - if (!degree.isNull()) { - - if (zoom_ < zoomNear_) { - zoom_ = zoomNear_; - } else if (zoom_ < zoomLvl1_) { - zoom_ -= degree.y() / 10.0; - } else if (zoom_ < zoomLvl2_) { - zoom_ -= degree.y() / 5.0; - } else if (zoom_ < zoomFar_) { - zoom_ -= degree.y(); - } else { - zoom_ = zoomFar_; - } - update(); - } + if (!degree.isNull()) + zoom(degree.y()); } +void FPGAViewWidget::zoom(int level) +{ + if (zoom_ < zoomNear_) { + zoom_ = zoomNear_; + } else if (zoom_ < zoomLvl1_) { + zoom_ -= level / 10.0; + } else if (zoom_ < zoomLvl2_) { + zoom_ -= level / 5.0; + } else if (zoom_ < zoomFar_) { + zoom_ -= level; + } else { + zoom_ = zoomFar_; + } + update(); +} + +void FPGAViewWidget::zoom_in() { zoom(10); } + +void FPGAViewWidget::zoom_out() { zoom(-10); } + +void FPGAViewWidget::zoom_selected() {} + +void FPGAViewWidget::zoom_outbound() {} + NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index b87c5d0a..636d5672 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -292,9 +292,13 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void onSelectedArchItem(std::vector decals); void onHighlightGroupChanged(std::vector decals, int group); void pokeRenderer(void); - + void zoom_in(); + void zoom_out(); + void zoom_selected(); + void zoom_outbound(); private: void renderLines(void); + void zoom(int level); QPoint lastPos_; LineShader lineShader_; diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 810a98ae..f06971b6 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -159,6 +159,8 @@ void MainWindow::createMenu() taskToolBar->addAction(actionPlay); taskToolBar->addAction(actionPause); taskToolBar->addAction(actionStop); + + createGraphicsBar(); } #if defined(_MSC_VER) diff --git a/gui/resources/shape_handles.png b/gui/resources/shape_handles.png new file mode 100644 index 0000000000000000000000000000000000000000..ce27fe3a0345e03e919b54ca3b6a8498743b2ee9 GIT binary patch literal 538 zcmV+#0_FXQP)Tm(Vb6n04%0-0d~Z?N5N>2x}bMx$D(zp$faLbcIm6))=iDcNsK{XO_NUIz9_#=Hl90fplE_S$iRDekpz|Us6%gcl z10>7>u(;bXN$%}9L;!i)H44lO83AA=upo5q1c5U!FDx|env1*bl?cq~cLH;UH^p~Rgca1Ok;(*H5ZUXcXOPFe6C@8ghq04j{~AV5iYe^SBjqm*l4!TaGj6|yQS zl0>W3O7lFgJbe6&SDlNa#1ExQ;_~7(-;>XH?~^Rc>h}P$EUWbUeQtj&SzNDKTyL1C zYZj|t%+odV)rMrXCP_Cezg;mNk8#e`cJr5LHk)4>jfPdL)hmSs`qPQy_Y4;U;qFB literal 0 HcmV?d00001 diff --git a/gui/resources/shape_square.png b/gui/resources/shape_square.png new file mode 100644 index 0000000000000000000000000000000000000000..33af046098e0c48e5dce566fd6c134b066a496e2 GIT binary patch literal 353 zcmV-n0iOPeP)@H!pQI5+Ti_L0YJ|=5)wx zkF=1qGlSNkDr^3|$ws8mau%VAs!N}G7ur`j3{a)&lwiJCaRceu$939gbwXgD!G7W+ z`tnW&{YVf#zprcNBv=w4wLNbW#_u=%`)~XMSM_D9ZJ#Vp00000NkvXXu0mjfl(La4 literal 0 HcmV?d00001 diff --git a/gui/resources/zoom_in.png b/gui/resources/zoom_in.png new file mode 100644 index 0000000000000000000000000000000000000000..cdf0a52fe03715dcdf399e59c8071c4572dc51f7 GIT binary patch literal 725 zcmV;`0xJE9P)m%7v+TE=2L@ zAc44q=tejYU5HLZGooZ=NXsV%)bU*sTokj@jZSo^9&w{ke7#VNQ*1zG!rIRk_@ zCqOr;g6B6CM1oPv1(~U4k@Gd+5tN0(j@GA*K*busv3Lb0UyXuowiRkTRZ#85JN!eC z_8ZVW>+upx5C#N|BTv2dK_EW@%(@F6yu1sZv>T3gm&*mIkvej1R4=RyYw#mS zx}c)#2z<)=VQ1|=ux>5PwjVE+J!Q84EQyG-j9SFYV*6AQj$Gb(7!KJE!k5iQ@O3K$ z@0NQZ)>b7&TaFd~Ciolk*Q(7cL+9cB`Y;G@rr`tk5Hdjv+))zSdlF#gI!>6`zB<@i zaKYP!9!Pl&5VMjydlq1x&}37{RQY+SSBXX-w?kCLKK%bXFYU6{?d+nH00000NkvXX Hu0mjfTSP*+ literal 0 HcmV?d00001 diff --git a/gui/resources/zoom_out.png b/gui/resources/zoom_out.png new file mode 100644 index 0000000000000000000000000000000000000000..07bf98a79cfea526e250703356dbefdb6b80d166 GIT binary patch literal 708 zcmV;#0z3VQP)TNkCP1&*^7LC~A?iZQEu_hKZoQoXI zA7tfTv}|~Fb8b^XuP>qvDk=)P)vYKtT12;}bKn-mwHWl`1Bb)&{XXC4IY$Nnvj5@N zfekg1Y}gcI!)Cq|u?lR+A{2&=d~S$}&0ei1|7pO6jkZ$6%&{R8TNpk>=dV#j&aWqO zgE~4pNU_-giktFkY-J5_XDlv`7+j?n3mXtxgadILp+c<9cr~t!x1LM6m69Z~V#pLL z22Cs~BoIdtZHTjo7Q|_U0a2OmSF=gCGFB$RVZIP(pixmBqE!^15yd!#9Z{Wh)zB%o zikBFa!WJPvMB(noe(U;k1e~Y|r$}@wh*Ymykd6>E3t69z5DT&Jq-fSG-dPdU{SG;i zbSb3<`RfKgJD|lQC`6(Cdut1PbDV&$M=Y?U)x)A(0iQN+gAeOBg2Z6fr$_Is!%M70 z=n*z7{*s%3rO7yazIO)}qa&~o@WZ=R>!b#mOSR zlCR8M*iRy2j7!PmWiiegA>Og~W1?FLk0*NI^}`$RW Date: Thu, 26 Jul 2018 12:33:46 +0000 Subject: [PATCH 03/21] Update README.md --- bba/README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/bba/README.md b/bba/README.md index 7e64b582..db620d52 100644 --- a/bba/README.md +++ b/bba/README.md @@ -12,20 +12,20 @@ independent. Valid commands for the input are as follows. -pre ------------- +pre \ +-------------- When a C file is generated as output, all the "pre" strings will be included before the binary blob. -post -------------- +post \ +--------------- When a C file is generated as output, all the "post" strings will be included after the binary blob. -push ------------ +push \ +------------- All following commands up until the matching "pop" will be writen to stream . Everything written to the same stream will end up in a continous @@ -36,35 +36,35 @@ pop End of a push..pop block. -label [] ------------------------- +label \ \[\\] +------------------------------ Add a label for the current position. -ref [] ----------------------- +ref \ \[\\] +---------------------------- Add a 32-bit reference to the specified label. The reference will be a byte offset relative to the memory location of the reference itself. -u8 [] ----------------------- +u8 \ \[\\] +---------------------------- Add a 8-bit value to the binary blob. -u16 [] ------------------------ +u16 \ \[\\] +----------------------------- Add a 16-bit value to the binary blob. Note that the input must be structured in a way that ensures that all u16 are aligned to 2-byte addresses. -u32 [] ----------------------- +u32 \ \[\\] +----------------------------- Add a 32-bit value to the binary blob. Note that the input must be structured in a way that ensures that all u32 are aligned to 4-byte addresses. -str ------------- +str \ +-------------- Add a reference to a zero-terminated copy of the specified string. From a86c4f2f5db2cefb4cb937b8bb9e02c9cb776167 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 15:22:52 +0200 Subject: [PATCH 04/21] Improvements in bbasm Signed-off-by: Clifford Wolf --- bba/main.cc | 89 ++++++++++++++++++++++++++++++++++++++++++++----- ice40/chipdb.py | 3 +- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/bba/main.cc b/bba/main.cc index 9f7da8d2..d236dd01 100644 --- a/bba/main.cc +++ b/bba/main.cc @@ -52,6 +52,7 @@ std::map streamIndex; std::vector streamStack; std::vector labels; +std::vector labelNames; std::map labelIndex; std::vector preText, postText; @@ -67,6 +68,7 @@ const char *skipWhitespace(const char *p) int main(int argc, char **argv) { + bool debug = false; bool verbose = false; bool bigEndian = false; bool writeC = false; @@ -76,6 +78,7 @@ int main(int argc, char **argv) po::positional_options_description pos; po::options_description options("Allowed options"); options.add_options()("v", "verbose output"); + options.add_options()("d", "debug output"); options.add_options()("b", "big endian"); options.add_options()("c", "write c strings"); options.add_options()("files", po::value>(), "file parameters"); @@ -94,6 +97,8 @@ int main(int argc, char **argv) } if (vm.count("v")) verbose = true; + if (vm.count("d")) + debug = true; if (vm.count("b")) bigEndian = true; if (vm.count("c")) @@ -152,11 +157,13 @@ int main(int argc, char **argv) Stream &s = streams.at(streamStack.back()); if (labelIndex.count(label) == 0) { labelIndex[label] = labels.size(); + if (debug) + labelNames.push_back(label); labels.push_back(-1); } s.tokenTypes.push_back(cmd == "label" ? TOK_LABEL : TOK_REF); s.tokenValues.push_back(labelIndex.at(label)); - if (verbose) + if (debug) s.tokenComments.push_back(comment); continue; } @@ -167,28 +174,41 @@ int main(int argc, char **argv) Stream &s = streams.at(streamStack.back()); s.tokenTypes.push_back(cmd == "u8" ? TOK_U8 : cmd == "u16" ? TOK_U16 : TOK_U32); s.tokenValues.push_back(atoll(value)); - if (verbose) + if (debug) s.tokenComments.push_back(comment); continue; } if (cmd == "str") { const char *value = skipWhitespace(strtok(nullptr, "\r\n")); + char terminator[2] = {*value, 0}; + assert(terminator[0] != 0); + value = strtok((char*)value+1, terminator); + const char *comment = skipWhitespace(strtok(nullptr, "\r\n")); std::string label = std::string("str:") + value; Stream &s = streams.at(streamStack.back()); if (labelIndex.count(label) == 0) { labelIndex[label] = labels.size(); + if (debug) + labelNames.push_back(label); labels.push_back(-1); } s.tokenTypes.push_back(TOK_REF); s.tokenValues.push_back(labelIndex.at(label)); - if (verbose) - s.tokenComments.push_back(value); + if (debug) + s.tokenComments.push_back(comment); stringStream.tokenTypes.push_back(TOK_LABEL); stringStream.tokenValues.push_back(labelIndex.at(label)); + stringStream.tokenComments.push_back(""); while (1) { stringStream.tokenTypes.push_back(TOK_U8); stringStream.tokenValues.push_back(*value); + if (debug) { + char char_comment[4] = {'\'', *value, '\'', 0}; + if (*value < 32 || *value >= 127) + char_comment[0] = 0; + stringStream.tokenComments.push_back(char_comment); + } if (*value == 0) break; value++; @@ -208,8 +228,10 @@ int main(int argc, char **argv) assert(!streams.empty()); assert(streamStack.empty()); streams.push_back(Stream()); + streams.back().name = "strings"; streams.back().tokenTypes.swap(stringStream.tokenTypes); streams.back().tokenValues.swap(stringStream.tokenValues); + streams.back().tokenComments.swap(stringStream.tokenComments); int cursor = 0; for (auto &s : streams) { @@ -247,6 +269,9 @@ int main(int argc, char **argv) cursor = 0; for (auto &s : streams) { + if (debug) + printf("-- %s --\n", s.name.c_str()); + for (int i = 0; i < int(s.tokenTypes.size()); i++) { uint32_t value = s.tokenValues[i]; int numBytes = 0; @@ -307,6 +332,51 @@ int main(int argc, char **argv) } cursor += numBytes; } + + if (debug) { + printf("%08x ", cursor - numBytes); + for (int k = cursor - numBytes; k < cursor; k++) + printf("%02x ", data[k]); + for (int k = numBytes; k < 4; k++) + printf(" "); + + unsigned long long v = s.tokenValues[i]; + + switch (s.tokenTypes[i]) { + case TOK_LABEL: + if (s.tokenComments[i].empty()) + printf("label %s\n", labelNames[v].c_str()); + else + printf("label %-24s %s\n", labelNames[v].c_str(), s.tokenComments[i].c_str()); + break; + case TOK_REF: + if (s.tokenComments[i].empty()) + printf("ref %s %s\n", labelNames[v].c_str()); + else + printf("ref %-26s %s\n", labelNames[v].c_str(), s.tokenComments[i].c_str()); + break; + case TOK_U8: + if (s.tokenComments[i].empty()) + printf("u8 %llu\n", v); + else + printf("u8 %-27llu %s\n", v, s.tokenComments[i].c_str()); + break; + case TOK_U16: + if (s.tokenComments[i].empty()) + printf("u16 %-26llu\n", v); + else + printf("u16 %-26llu %s\n", v, s.tokenComments[i].c_str()); + break; + case TOK_U32: + if (s.tokenComments[i].empty()) + printf("u32 %-26llu\n", v); + else + printf("u32 %-26llu %s\n", v, s.tokenComments[i].c_str()); + break; + default: + assert(0); + } + } } } @@ -319,7 +389,8 @@ int main(int argc, char **argv) fprintf(fileOut, "const char %s[%d] =\n\"", streams[0].name.c_str(), int(data.size()) + 1); cursor = 1; - for (auto d : data) { + for (int i = 0; i < int(data.size()); i++) { + auto d = data[i]; if (cursor > 70) { fputc('\"', fileOut); fputc('\n', fileOut); @@ -329,9 +400,11 @@ int main(int argc, char **argv) fputc('\"', fileOut); cursor = 1; } - if (d < 32 || d >= 128) { - fprintf(fileOut, "\\%03o", int(d)); - cursor += 4; + if (d < 32 || d >= 127) { + if (i+1 < int(data.size()) && (data[i+1] < '0' || '9' < data[i+1])) + cursor += fprintf(fileOut, "\\%o", int(d)); + else + cursor += fprintf(fileOut, "\\%03o", int(d)); } else if (d == '\"' || d == '\'' || d == '\\') { fputc('\\', fileOut); fputc(d, fileOut); diff --git a/ice40/chipdb.py b/ice40/chipdb.py index b5fee359..b6af8fcf 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -675,7 +675,8 @@ class BinaryBlobAssembler: print("ref %s %s" % (name, comment)) def s(self, s, comment): - print("str %s" % s) + assert "|" not in s + print("str |%s| %s" % (s, comment)) def u8(self, v, comment): if comment is None: From 10305db43faed2a42c10728b61fd751783940a77 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 13:30:33 +0000 Subject: [PATCH 05/21] Update README.md --- bba/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bba/README.md b/bba/README.md index db620d52..d51088c2 100644 --- a/bba/README.md +++ b/bba/README.md @@ -64,7 +64,8 @@ u32 \ \[\\] Add a 32-bit value to the binary blob. Note that the input must be structured in a way that ensures that all u32 are aligned to 4-byte addresses. -str \ --------------- +str "\" \[\\] +-------------------------------- -Add a reference to a zero-terminated copy of the specified string. +Add a reference to a zero-terminated copy of that string. Any character may be +used to quote the string, but the most common choices are `"` and `|`. From 7f1075cb887a65dfbc23539db4c43ae57fcdbdbb Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 13:33:48 +0000 Subject: [PATCH 06/21] Update README.md --- bba/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bba/README.md b/bba/README.md index d51088c2..166ff7ff 100644 --- a/bba/README.md +++ b/bba/README.md @@ -28,8 +28,11 @@ push \ ------------- All following commands up until the matching "pop" will be writen to stream -. Everything written to the same stream will end up in a continous -region of the output. +\. Everything written to the same stream will end up in a continous +region of the output. The statements `pop`, `label`, `ref`, `u8`, `u16`, +`u32`, and `str` are only valid within such a block. The name used in the +first push statement also determines the name of the variable in the generated +C output (when C is selected as output file format). pop --- From 7152ae1e3ddb540cafbfab38e0b69ea94d1ec3c2 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 15:42:32 +0200 Subject: [PATCH 07/21] Add iCE40 pip gfx for carry_in mux Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 1b01cbd8..0a583e8e 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -701,6 +701,17 @@ void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, 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); + + if (src == TILE_WIRE_CARRY_IN && dst == TILE_WIRE_CARRY_IN_MUX) { + GraphicElement el; + el.type = GraphicElement::G_ARROW; + el.style = style; + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y + 0.01; + el.y2 = y + 0.02; + g.push_back(el); + } } NEXTPNR_NAMESPACE_END From 6a59b8522cd13f4d4c4e0c0ac43a374da2d95615 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 16:21:01 +0200 Subject: [PATCH 08/21] Move iCE40 switchbox gfx to UI groups Signed-off-by: Clifford Wolf --- ice40/arch.cc | 255 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 162 insertions(+), 93 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index dedc59bc..55252f2c 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -440,11 +440,103 @@ GroupId Arch::getGroupByName(IdString name) const return GroupId(); } -IdString Arch::getGroupName(GroupId group) const { return IdString(); } +IdString Arch::getGroupName(GroupId group) const +{ + std::string suffix; + + switch (group.type) { + case GroupId::TYPE_FRAME: + suffix = "tile"; + break; + case GroupId::TYPE_MAIN_SW: + suffix = "main_sw"; + break; + case GroupId::TYPE_LOCAL_SW: + suffix = "local_sw"; + break; + case GroupId::TYPE_LC0_SW: + suffix = "lc0_sw"; + break; + case GroupId::TYPE_LC1_SW: + suffix = "lc1_sw"; + break; + case GroupId::TYPE_LC2_SW: + suffix = "lc2_sw"; + break; + case GroupId::TYPE_LC3_SW: + suffix = "lc3_sw"; + break; + case GroupId::TYPE_LC4_SW: + suffix = "lc4_sw"; + break; + case GroupId::TYPE_LC5_SW: + suffix = "lc5_sw"; + break; + case GroupId::TYPE_LC6_SW: + suffix = "lc6_sw"; + break; + case GroupId::TYPE_LC7_SW: + suffix = "lc7_sw"; + break; + default: + return IdString(); + } + + return id("X" + std::to_string(group.x) + "/Y" + std::to_string(group.y) + "/" + suffix); +} std::vector Arch::getGroups() const { std::vector ret; + + for (int y = 0; y < chip_info->height; y++) { + for (int x = 0; x < chip_info->width; x++) { + TileType type = chip_info->tile_grid[y * chip_info->width + x]; + if (type == TILE_NONE) + continue; + + GroupId group; + group.type = GroupId::TYPE_FRAME; + group.x = x; + group.y = y; + // ret.push_back(group); + + group.type = GroupId::TYPE_MAIN_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LOCAL_SW; + ret.push_back(group); + +#if 0 + if (type == TILE_LOGIC) + { + group.type = GroupId::TYPE_LC0_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC1_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC2_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC3_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC4_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC5_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC6_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC7_SW; + ret.push_back(group); + } +#endif + } + } return ret; } @@ -552,15 +644,63 @@ std::vector Arch::getDecalGraphics(DecalId decal) const std::vector ret; if (decal.type == DecalId::TYPE_FRAME) { - for (int x = 0; x <= chip_info->width; x++) - for (int y = 0; y <= chip_info->height; y++) { - GraphicElement el; - el.type = GraphicElement::G_LINE; - el.x1 = x - 0.05, el.x2 = x + 0.05, el.y1 = y, el.y2 = y, el.z = 0; - ret.push_back(el); - el.x1 = x, el.x2 = x, el.y1 = y - 0.05, el.y2 = y + 0.05, el.z = 0; - ret.push_back(el); - } + /* nothing */ + } + + if (decal.type == DecalId::TYPE_GROUP) { + int type = (decal.index >> 16) & 255; + int x = (decal.index >> 8) & 255; + int y = decal.index & 255; + + if (type == GroupId::TYPE_FRAME) { + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.style = GraphicElement::G_FRAME; + + el.x1 = x + 0.01, el.x2 = x + 0.02, el.y1 = y + 0.01, el.y2 = y + 0.01; + ret.push_back(el); + el.x1 = x + 0.01, el.x2 = x + 0.01, el.y1 = y + 0.01, el.y2 = y + 0.02; + ret.push_back(el); + + el.x1 = x + 0.99, el.x2 = x + 0.98, el.y1 = y + 0.01, el.y2 = y + 0.01; + ret.push_back(el); + el.x1 = x + 0.99, el.x2 = x + 0.99, el.y1 = y + 0.01, el.y2 = y + 0.02; + ret.push_back(el); + + el.x1 = x + 0.99, el.x2 = x + 0.98, el.y1 = y + 0.99, el.y2 = y + 0.99; + ret.push_back(el); + el.x1 = x + 0.99, el.x2 = x + 0.99, el.y1 = y + 0.99, el.y2 = y + 0.98; + ret.push_back(el); + + el.x1 = x + 0.01, el.x2 = x + 0.02, el.y1 = y + 0.99, el.y2 = y + 0.99; + ret.push_back(el); + el.x1 = x + 0.01, el.x2 = x + 0.01, el.y1 = y + 0.99, el.y2 = y + 0.98; + ret.push_back(el); + } + + if (type == GroupId::TYPE_MAIN_SW) { + GraphicElement el; + el.type = GraphicElement::G_BOX; + el.style = GraphicElement::G_FRAME; + + el.x1 = x + main_swbox_x1; + el.x2 = x + main_swbox_x2; + el.y1 = y + main_swbox_y1; + el.y2 = y + main_swbox_y2; + ret.push_back(el); + } + + if (type == GroupId::TYPE_LOCAL_SW) { + GraphicElement el; + el.type = GraphicElement::G_BOX; + el.style = GraphicElement::G_FRAME; + + el.x1 = x + local_swbox_x1; + el.x2 = x + local_swbox_x2; + el.y1 = y + local_swbox_y1; + el.y2 = y + local_swbox_y2; + ret.push_back(el); + } } if (decal.type == DecalId::TYPE_WIRE) { @@ -595,103 +735,32 @@ std::vector Arch::getDecalGraphics(DecalId decal) const (chip_info->bel_data[bel.index].z) * logic_cell_pitch; el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; - el.z = 0; ret.push_back(el); - - if (chip_info->bel_data[bel.index].z == 0) { - int tx = chip_info->bel_data[bel.index].x; - int ty = chip_info->bel_data[bel.index].y; - - // Main switchbox - GraphicElement main_sw; - main_sw.type = GraphicElement::G_BOX; - main_sw.style = GraphicElement::G_FRAME; - main_sw.x1 = tx + main_swbox_x1; - main_sw.x2 = tx + main_swbox_x2; - main_sw.y1 = ty + main_swbox_y1; - main_sw.y2 = ty + main_swbox_y2; - ret.push_back(main_sw); - - // Local tracks to LUT input switchbox - GraphicElement local_sw; - local_sw.type = GraphicElement::G_BOX; - local_sw.style = GraphicElement::G_FRAME; - local_sw.x1 = tx + local_swbox_x1; - local_sw.x2 = tx + local_swbox_x2; - local_sw.y1 = ty + local_swbox_y1; - local_sw.y2 = ty + local_swbox_y2; - local_sw.z = 0; - ret.push_back(local_sw); - } } if (bel_type == TYPE_SB_IO) { - if (chip_info->bel_data[bel.index].x == 0 || chip_info->bel_data[bel.index].x == chip_info->width - 1) { - GraphicElement el; - el.type = GraphicElement::G_BOX; - el.x1 = chip_info->bel_data[bel.index].x + 0.1; - el.x2 = chip_info->bel_data[bel.index].x + 0.9; - if (chip_info->bel_data[bel.index].z == 0) { - el.y1 = chip_info->bel_data[bel.index].y + 0.10; - el.y2 = chip_info->bel_data[bel.index].y + 0.45; - } else { - el.y1 = chip_info->bel_data[bel.index].y + 0.55; - el.y2 = chip_info->bel_data[bel.index].y + 0.90; - } - el.z = 0; - ret.push_back(el); - } else { - GraphicElement el; - el.type = GraphicElement::G_BOX; - if (chip_info->bel_data[bel.index].z == 0) { - el.x1 = chip_info->bel_data[bel.index].x + 0.10; - el.x2 = chip_info->bel_data[bel.index].x + 0.45; - } else { - el.x1 = chip_info->bel_data[bel.index].x + 0.55; - el.x2 = chip_info->bel_data[bel.index].x + 0.90; - } - el.y1 = chip_info->bel_data[bel.index].y + 0.1; - el.y2 = chip_info->bel_data[bel.index].y + 0.9; - el.z = 0; - ret.push_back(el); - } + GraphicElement el; + el.type = GraphicElement::G_BOX; + el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; + el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + + (4*chip_info->bel_data[bel.index].z) * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + + (4*chip_info->bel_data[bel.index].z + 3) * logic_cell_pitch; + ret.push_back(el); } if (bel_type == TYPE_ICESTORM_RAM) { for (int i = 0; i < 2; i++) { - int tx = chip_info->bel_data[bel.index].x; - int ty = chip_info->bel_data[bel.index].y + i; - GraphicElement el; el.type = GraphicElement::G_BOX; el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; - el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7 * logic_cell_pitch; - el.z = 0; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + i; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + i + 7 * logic_cell_pitch; ret.push_back(el); - - // Main switchbox - GraphicElement main_sw; - main_sw.type = GraphicElement::G_BOX; - main_sw.style = GraphicElement::G_FRAME; - main_sw.x1 = tx + main_swbox_x1; - main_sw.x2 = tx + main_swbox_x2; - main_sw.y1 = ty + main_swbox_y1; - main_sw.y2 = ty + main_swbox_y2; - ret.push_back(main_sw); - - // Local tracks to LUT input switchbox - GraphicElement local_sw; - local_sw.type = GraphicElement::G_BOX; - local_sw.style = GraphicElement::G_FRAME; - local_sw.x1 = tx + local_swbox_x1; - local_sw.x2 = tx + local_swbox_x2; - local_sw.y1 = ty + local_swbox_y1; - local_sw.y2 = ty + local_swbox_y2; - local_sw.z = 0; - ret.push_back(local_sw); } } } From 467e0926f920f23b7cb2241cf52dbcfe84646fed Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 16:38:11 +0200 Subject: [PATCH 09/21] Add getWireType()/getPipType() API Signed-off-by: Clifford Wolf --- ecp5/arch.h | 4 ++++ generic/arch.cc | 13 ++++++++++--- generic/arch.h | 12 +++++++----- gui/designwidget.cc | 2 ++ ice40/arch.h | 4 ++++ 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/ecp5/arch.h b/ecp5/arch.h index b5f3d817..d9d29c76 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -538,6 +538,8 @@ struct Arch : BaseCtx return id(name.str()); } + IdString getWireType(WireId wire) const { return IdString(); } + uint32_t getWireChecksum(WireId wire) const { return wire.index; } void bindWire(WireId wire, IdString net, PlaceStrength strength) @@ -616,6 +618,8 @@ struct Arch : BaseCtx PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; + IdString getPipType(PipId pip) const { return IdString(); } + uint32_t getPipChecksum(PipId pip) const { return pip.index; } void bindPip(PipId pip, IdString net, PlaceStrength strength) diff --git a/generic/arch.cc b/generic/arch.cc index d7401356..580fae43 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -24,22 +24,24 @@ NEXTPNR_NAMESPACE_BEGIN -void Arch::addWire(IdString name, int x, int y) +void Arch::addWire(IdString name, IdString type, int x, int y) { NPNR_ASSERT(wires.count(name) == 0); WireInfo &wi = wires[name]; wi.name = name; + wi.type = type; wi.x = x; wi.y = y; wire_ids.push_back(name); } -void Arch::addPip(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay) +void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay) { NPNR_ASSERT(pips.count(name) == 0); PipInfo &pi = pips[name]; pi.name = name; + wi.type = type; pi.srcWire = srcWire; pi.dstWire = dstWire; pi.delay = delay; @@ -49,11 +51,12 @@ void Arch::addPip(IdString name, IdString srcWire, IdString dstWire, DelayInfo d pip_ids.push_back(name); } -void Arch::addAlias(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay) +void Arch::addAlias(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay) { NPNR_ASSERT(pips.count(name) == 0); PipInfo &pi = pips[name]; pi.name = name; + wi.type = type; pi.srcWire = srcWire; pi.dstWire = dstWire; pi.delay = delay; @@ -266,6 +269,8 @@ WireId Arch::getWireByName(IdString name) const IdString Arch::getWireName(WireId wire) const { return wire; } +IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; } + uint32_t Arch::getWireChecksum(WireId wire) const { // FIXME @@ -316,6 +321,8 @@ PipId Arch::getPipByName(IdString name) const IdString Arch::getPipName(PipId pip) const { return pip; } +IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; } + uint32_t Arch::getPipChecksum(PipId wire) const { // FIXME diff --git a/generic/arch.h b/generic/arch.h index 97ed1ac2..01a90ee1 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -31,7 +31,7 @@ struct WireInfo; struct PipInfo { - IdString name, bound_net; + IdString name, type, bound_net; WireId srcWire, dstWire; DelayInfo delay; DecalXY decalxy; @@ -39,7 +39,7 @@ struct PipInfo struct WireInfo { - IdString name, bound_net; + IdString name, type, bound_net; std::vector downhill, uphill, aliases; BelPin uphill_bel_pin; std::vector downhill_bel_pins; @@ -96,9 +96,9 @@ struct Arch : BaseCtx float grid_distance_to_delay; - void addWire(IdString name, int x, int y); - void addPip(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay); - void addAlias(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay); + void addWire(IdString name, IdString type, int x, int y); + void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay); + void addAlias(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay); void addBel(IdString name, IdString type, Loc loc, bool gb); void addBelInput(IdString bel, IdString name, IdString wire); @@ -157,6 +157,7 @@ struct Arch : BaseCtx WireId getWireByName(IdString name) const; IdString getWireName(WireId wire) const; + IdString getWireType(WireId wire) const; uint32_t getWireChecksum(WireId wire) const; void bindWire(WireId wire, IdString net, PlaceStrength strength); void unbindWire(WireId wire); @@ -169,6 +170,7 @@ struct Arch : BaseCtx PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; + IdString getPipType(PipId pip) const; uint32_t getPipChecksum(PipId pip) const; void bindPip(PipId pip, IdString net, PlaceStrength strength); void unbindPip(PipId pip); diff --git a/gui/designwidget.cc b/gui/designwidget.cc index f9d231c1..4086fd63 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -567,6 +567,7 @@ void DesignWidget::onItemSelectionChanged() QtProperty *topItem = addTopLevelProperty("Wire"); addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); + 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->getBoundWireNet(wire).c_str(ctx), ElementType::NET); addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingWireNet(wire).c_str(ctx), @@ -618,6 +619,7 @@ void DesignWidget::onItemSelectionChanged() QtProperty *topItem = addTopLevelProperty("Pip"); addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); + 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->getBoundPipNet(pip).c_str(ctx), ElementType::NET); addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingPipNet(pip).c_str(ctx), diff --git a/ice40/arch.h b/ice40/arch.h index 123b408c..51cbe725 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -469,6 +469,8 @@ struct Arch : BaseCtx return id(chip_info->wire_data[wire.index].name.get()); } + IdString getWireType(WireId wire) const { return IdString(); } + uint32_t getWireChecksum(WireId wire) const { return wire.index; } void bindWire(WireId wire, IdString net, PlaceStrength strength) @@ -611,6 +613,8 @@ struct Arch : BaseCtx IdString getPipName(PipId pip) const; + IdString getPipType(PipId pip) const { return IdString(); } + uint32_t getPipChecksum(PipId pip) const { return pip.index; } WireId getPipSrcWire(PipId pip) const From f4a7478a406c841d7938985ee5611fbf73aa7b02 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 16:45:57 +0200 Subject: [PATCH 10/21] Fix router1 locking in NDEBUG builds Signed-off-by: Clifford Wolf --- common/router1.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index fbf3c467..8a05236f 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -810,14 +810,14 @@ bool router1(Context *ctx) log_info("Checksum: 0x%08x\n", ctx->checksum()); #ifndef NDEBUG ctx->check(); - ctx->unlock(); #endif + ctx->unlock(); return true; } catch (log_execution_error_exception) { #ifndef NDEBUG ctx->check(); - ctx->unlock(); #endif + ctx->unlock(); return false; } } From 7ddcdbfed03abbb92d726b95d24e825041ff8617 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 26 Jul 2018 16:47:09 +0200 Subject: [PATCH 11/21] generic: Fixing build Signed-off-by: David Shah --- generic/arch.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/arch.cc b/generic/arch.cc index 580fae43..5c9864ab 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -41,7 +41,7 @@ void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWi NPNR_ASSERT(pips.count(name) == 0); PipInfo &pi = pips[name]; pi.name = name; - wi.type = type; + pi.type = type; pi.srcWire = srcWire; pi.dstWire = dstWire; pi.delay = delay; @@ -56,7 +56,7 @@ void Arch::addAlias(IdString name, IdString type, IdString srcWire, IdString dst NPNR_ASSERT(pips.count(name) == 0); PipInfo &pi = pips[name]; pi.name = name; - wi.type = type; + pi.type = type; pi.srcWire = srcWire; pi.dstWire = dstWire; pi.delay = delay; From 03f92948d1504c32049da065c0e73e01f96d8033 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 17:14:56 +0200 Subject: [PATCH 12/21] clangformat and GraphicElement::style comments Signed-off-by: Clifford Wolf --- bba/main.cc | 4 ++-- common/nextpnr.h | 8 ++++---- gui/designwidget.cc | 14 ++++++-------- gui/designwidget.h | 2 +- gui/fpgaviewwidget.h | 1 + ice40/arch.cc | 4 ++-- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/bba/main.cc b/bba/main.cc index d236dd01..dd0caf1a 100644 --- a/bba/main.cc +++ b/bba/main.cc @@ -183,7 +183,7 @@ int main(int argc, char **argv) const char *value = skipWhitespace(strtok(nullptr, "\r\n")); char terminator[2] = {*value, 0}; assert(terminator[0] != 0); - value = strtok((char*)value+1, terminator); + value = strtok((char *)value + 1, terminator); const char *comment = skipWhitespace(strtok(nullptr, "\r\n")); std::string label = std::string("str:") + value; Stream &s = streams.at(streamStack.back()); @@ -401,7 +401,7 @@ int main(int argc, char **argv) cursor = 1; } if (d < 32 || d >= 127) { - if (i+1 < int(data.size()) && (data[i+1] < '0' || '9' < data[i+1])) + if (i + 1 < int(data.size()) && (data[i + 1] < '0' || '9' < data[i + 1])) cursor += fprintf(fileOut, "\\%o", int(d)); else cursor += fprintf(fileOut, "\\%03o", int(d)); diff --git a/common/nextpnr.h b/common/nextpnr.h index 1cce21c0..e9e491f4 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -155,10 +155,10 @@ struct GraphicElement enum style_t { - G_FRAME, - G_HIDDEN, - G_INACTIVE, - G_ACTIVE, + G_FRAME, // Static "frame". Contrast between G_INACTIVE and G_ACTIVE + G_HIDDEN, // Only display when object is selected or highlighted + G_INACTIVE, // Render using low-contrast color + G_ACTIVE, // Render using high-contast color } style = G_FRAME; float x1 = 0, y1 = 0, x2 = 0, y2 = 0, z = 0; diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 4086fd63..2bba8532 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -777,18 +777,16 @@ std::vector DesignWidget::getDecals(ElementType type, IdString value) return decals; } -void DesignWidget::updateHighlightGroup(QList items, int group) +void DesignWidget::updateHighlightGroup(QList items, int group) { const bool shouldClear = items.size() == 1; for (auto item : items) { if (highlightSelected.contains(item)) { if (shouldClear && highlightSelected[item] == group) { highlightSelected.remove(item); - } - else + } else highlightSelected[item] = group; - } - else + } else highlightSelected.insert(item, group); } std::vector decals[8]; @@ -799,14 +797,14 @@ void DesignWidget::updateHighlightGroup(QList items, int group std::vector d = getDecals(type, value); std::move(d.begin(), d.end(), std::back_inserter(decals[it.second])); } - for (int i=0;i<8;i++) + for (int i = 0; i < 8; i++) Q_EMIT highlight(decals[i], i); } void DesignWidget::prepareMenuProperty(const QPoint &pos) { QTreeWidget *tree = propertyEditor->treeWidget(); - QList items; + QList items; for (auto itemContextMenu : tree->selectedItems()) { QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu); if (!browserItem) @@ -848,7 +846,7 @@ void DesignWidget::prepareMenuTree(const QPoint &pos) if (treeWidget->selectedItems().size() == 0) return; int selectedIndex = -1; - QList items = treeWidget->selectedItems(); + QList items = treeWidget->selectedItems(); if (treeWidget->selectedItems().size() == 1) { QTreeWidgetItem *item = treeWidget->selectedItems().at(0); if (highlightSelected.contains(item)) diff --git a/gui/designwidget.h b/gui/designwidget.h index fe340237..6d4b7fe1 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -60,7 +60,7 @@ class DesignWidget : public QWidget void updateButtons(); void addToHistory(QTreeWidgetItem *item); std::vector getDecals(ElementType type, IdString value); - void updateHighlightGroup(QList item, int group); + void updateHighlightGroup(QList item, int group); Q_SIGNALS: void info(std::string text); void selected(std::vector decal); diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 636d5672..36d4a3f2 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -296,6 +296,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void zoom_out(); void zoom_selected(); void zoom_outbound(); + private: void renderLines(void); void zoom(int level); diff --git a/ice40/arch.cc b/ice40/arch.cc index 55252f2c..d08463d2 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -745,9 +745,9 @@ std::vector Arch::getDecalGraphics(DecalId decal) const el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + - (4*chip_info->bel_data[bel.index].z) * logic_cell_pitch; + (4 * chip_info->bel_data[bel.index].z) * logic_cell_pitch; el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + - (4*chip_info->bel_data[bel.index].z + 3) * logic_cell_pitch; + (4 * chip_info->bel_data[bel.index].z + 3) * logic_cell_pitch; ret.push_back(el); } From f1b84fbdc5b1377cc88e56b5e0f95b62a7531a35 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 26 Jul 2018 16:26:05 +0100 Subject: [PATCH 13/21] gui: style fixes --- gui/basewindow.cc | 8 ++++---- gui/fpgaviewwidget.cc | 8 ++++---- gui/fpgaviewwidget.h | 17 +++++------------ 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 11a7fe8d..e07200de 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -166,19 +166,19 @@ void BaseMainWindow::createGraphicsBar() { QAction *actionZoomIn = new QAction("Zoom In", this); actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png")); - connect(actionZoomIn, SIGNAL(triggered()), fpgaView, SLOT(zoom_in())); + connect(actionZoomIn, SIGNAL(triggered()), fpgaView, SLOT(zoomIn())); QAction *actionZoomOut = new QAction("Zoom Out", this); actionZoomOut->setIcon(QIcon(":/icons/resources/zoom_out.png")); - connect(actionZoomOut, SIGNAL(triggered()), fpgaView, SLOT(zoom_out())); + connect(actionZoomOut, SIGNAL(triggered()), fpgaView, SLOT(zoomOut())); QAction *actionZoomSelected = new QAction("Zoom Selected", this); actionZoomSelected->setIcon(QIcon(":/icons/resources/shape_handles.png")); - connect(actionZoomSelected, SIGNAL(triggered()), fpgaView, SLOT(zoom_selected())); + connect(actionZoomSelected, SIGNAL(triggered()), fpgaView, SLOT(zoomSelected())); QAction *actionZoomOutbound = new QAction("Zoom Outbound", this); actionZoomOutbound->setIcon(QIcon(":/icons/resources/shape_square.png")); - connect(actionZoomOutbound, SIGNAL(triggered()), fpgaView, SLOT(zoom_outbound())); + connect(actionZoomOutbound, SIGNAL(triggered()), fpgaView, SLOT(zoomOutbound())); graphicsToolBar = new QToolBar(); addToolBar(Qt::TopToolBarArea, graphicsToolBar); diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index e08667f6..6637f2b7 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -600,12 +600,12 @@ void FPGAViewWidget::zoom(int level) update(); } -void FPGAViewWidget::zoom_in() { zoom(10); } +void FPGAViewWidget::zoomIn() { zoom(10); } -void FPGAViewWidget::zoom_out() { zoom(-10); } +void FPGAViewWidget::zoomOut() { zoom(-10); } -void FPGAViewWidget::zoom_selected() {} +void FPGAViewWidget::zoomSelected() {} -void FPGAViewWidget::zoom_outbound() {} +void FPGAViewWidget::zoomOutbound() {} NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 36d4a3f2..46231b16 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -270,14 +270,6 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QSize minimumSizeHint() const override; QSize sizeHint() const override; - void setXTranslation(float t_x); - void setYTranslation(float t_y); - void setZoom(float t_z); - - void xRotationChanged(int angle); - void yRotationChanged(int angle); - void zRotationChanged(int angle); - protected: void initializeGL() Q_DECL_OVERRIDE; void paintGL() Q_DECL_OVERRIDE; @@ -287,15 +279,16 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; void drawDecal(LineShaderData &data, const DecalXY &decal); void drawDecal(LineShaderData out[], const DecalXY &decal); + public Q_SLOTS: void newContext(Context *ctx); void onSelectedArchItem(std::vector decals); void onHighlightGroupChanged(std::vector decals, int group); void pokeRenderer(void); - void zoom_in(); - void zoom_out(); - void zoom_selected(); - void zoom_outbound(); + void zoomIn(); + void zoomOut(); + void zoomSelected(); + void zoomOutbound(); private: void renderLines(void); From c37d2baaf647fec35c28a8e639b0d4a74643537d Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 26 Jul 2018 16:39:19 +0100 Subject: [PATCH 14/21] common: rename GraphicElement::{style,type} enums, add _MAX members --- common/nextpnr.h | 28 ++++++++++++++++------------ gui/fpgaviewwidget.cc | 20 ++++++++++---------- ice40/arch.cc | 28 ++++++++++++++-------------- ice40/gfx.cc | 6 +++--- ice40/main.cc | 4 ++-- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index e9e491f4..5e32d5b6 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -145,21 +145,25 @@ struct GraphicElement { enum type_t { - G_NONE, - G_LINE, - G_ARROW, - G_BOX, - G_CIRCLE, - G_LABEL - } type = G_NONE; + TYPE_NONE, + TYPE_LINE, + TYPE_ARROW, + TYPE_BOX, + TYPE_CIRCLE, + TYPE_LABEL, + + TYPE_MAX + } type = TYPE_NONE; enum style_t { - G_FRAME, // Static "frame". Contrast between G_INACTIVE and G_ACTIVE - G_HIDDEN, // Only display when object is selected or highlighted - G_INACTIVE, // Render using low-contrast color - G_ACTIVE, // Render using high-contast color - } style = G_FRAME; + STYLE_FRAME, // Static "frame". Contrast between STYLE_INACTIVE and STYLE_ACTIVE + STYLE_HIDDEN, // Only display when object is selected or highlighted + STYLE_INACTIVE, // Render using low-contrast color + STYLE_ACTIVE, // Render using high-contast color + + STYLE_MAX + } style = STYLE_FRAME; float x1 = 0, y1 = 0, x2 = 0, y2 = 0, z = 0; std::string text; diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 6637f2b7..e9096bf4 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -320,7 +320,7 @@ void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) offsetX = decal.x; offsetY = decal.y; - if (el.type == GraphicElement::G_BOX) { + if (el.type == GraphicElement::TYPE_BOX) { auto line = PolyLine(true); line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); @@ -329,7 +329,7 @@ void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) line.build(out); } - if (el.type == GraphicElement::G_LINE || el.type == GraphicElement::G_ARROW) { + if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) .build(out); } @@ -345,16 +345,16 @@ void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) offsetX = decal.x; offsetY = decal.y; - if (el.type == GraphicElement::G_BOX) { + if (el.type == GraphicElement::TYPE_BOX) { auto line = PolyLine(true); line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: + case GraphicElement::STYLE_FRAME: + case GraphicElement::STYLE_INACTIVE: + case GraphicElement::STYLE_ACTIVE: line.build(out[el.style]); break; default: @@ -362,13 +362,13 @@ void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) } } - if (el.type == GraphicElement::G_LINE || el.type == GraphicElement::G_ARROW) { + if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2); switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: + case GraphicElement::STYLE_FRAME: + case GraphicElement::STYLE_INACTIVE: + case GraphicElement::STYLE_ACTIVE: line.build(out[el.style]); break; default: diff --git a/ice40/arch.cc b/ice40/arch.cc index d08463d2..3803f842 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -654,8 +654,8 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (type == GroupId::TYPE_FRAME) { GraphicElement el; - el.type = GraphicElement::G_LINE; - el.style = GraphicElement::G_FRAME; + el.type = GraphicElement::TYPE_LINE; + el.style = GraphicElement::STYLE_FRAME; el.x1 = x + 0.01, el.x2 = x + 0.02, el.y1 = y + 0.01, el.y2 = y + 0.01; ret.push_back(el); @@ -680,8 +680,8 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (type == GroupId::TYPE_MAIN_SW) { GraphicElement el; - el.type = GraphicElement::G_BOX; - el.style = GraphicElement::G_FRAME; + el.type = GraphicElement::TYPE_BOX; + el.style = GraphicElement::STYLE_FRAME; el.x1 = x + main_swbox_x1; el.x2 = x + main_swbox_x2; @@ -692,8 +692,8 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (type == GroupId::TYPE_LOCAL_SW) { GraphicElement el; - el.type = GraphicElement::G_BOX; - el.style = GraphicElement::G_FRAME; + el.type = GraphicElement::TYPE_BOX; + el.style = GraphicElement::STYLE_FRAME; el.x1 = x + local_swbox_x1; el.x2 = x + local_swbox_x2; @@ -707,7 +707,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const 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; + GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; for (int i = 0; i < n; i++) gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style); @@ -715,7 +715,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const 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; + GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_HIDDEN; gfxTilePip(ret, p.x, p.y, GfxTileWireId(p.src_seg), GfxTileWireId(p.dst_seg), style); } @@ -727,8 +727,8 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; - el.type = GraphicElement::G_BOX; - el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + @@ -740,8 +740,8 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (bel_type == TYPE_SB_IO) { GraphicElement el; - el.type = GraphicElement::G_BOX; - el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + @@ -754,8 +754,8 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (bel_type == TYPE_ICESTORM_RAM) { for (int i = 0; i < 2; i++) { GraphicElement el; - el.type = GraphicElement::G_BOX; - el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + i; diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 0a583e8e..0798862a 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -24,7 +24,7 @@ NEXTPNR_NAMESPACE_BEGIN void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style) { GraphicElement el; - el.type = GraphicElement::G_LINE; + el.type = GraphicElement::TYPE_LINE; el.style = style; // Horizontal Span-4 Wires @@ -647,7 +647,7 @@ void pipGfx(std::vector &g, int x, int y, float x1, float y1, fl float ty = 0.5 * (y1 + y2); GraphicElement el; - el.type = GraphicElement::G_ARROW; + el.type = GraphicElement::TYPE_ARROW; el.style = style; if (fabsf(x1 - swx1) < 0.001 && fabsf(x2 - swx1) < 0.001) { @@ -704,7 +704,7 @@ void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, if (src == TILE_WIRE_CARRY_IN && dst == TILE_WIRE_CARRY_IN_MUX) { GraphicElement el; - el.type = GraphicElement::G_ARROW; + el.type = GraphicElement::TYPE_ARROW; el.style = style; el.x1 = x + logic_cell_x1 + 0.005 * 3; el.x2 = el.x1; diff --git a/ice40/main.cc b/ice40/main.cc index 6201831a..32815b26 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -52,13 +52,13 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal) const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; for (auto &el : ctx->getDecalGraphics(decal.decal)) { - if (el.type == GraphicElement::G_BOX) { + if (el.type == GraphicElement::TYPE_BOX) { std::cout << "\n"; } - if (el.type == GraphicElement::G_LINE) { + if (el.type == GraphicElement::TYPE_LINE) { std::cout << "\n"; From 863432d35020061d447c0ffa44104ac8368a6f4c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 26 Jul 2018 18:02:50 +0200 Subject: [PATCH 15/21] Fix bba typo Signed-off-by: Clifford Wolf --- bba/main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bba/main.cc b/bba/main.cc index dd0caf1a..263cf39e 100644 --- a/bba/main.cc +++ b/bba/main.cc @@ -351,7 +351,7 @@ int main(int argc, char **argv) break; case TOK_REF: if (s.tokenComments[i].empty()) - printf("ref %s %s\n", labelNames[v].c_str()); + printf("ref %s\n", labelNames[v].c_str()); else printf("ref %-26s %s\n", labelNames[v].c_str(), s.tokenComments[i].c_str()); break; From 706fe2f3655210467d329c9a8c98f5821fb02c60 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 26 Jul 2018 17:26:26 +0100 Subject: [PATCH 16/21] gui: refactor FPGAViewWidget slightly --- gui/fpgaviewwidget.cc | 270 ++++++++++++++++++++++-------------------- gui/fpgaviewwidget.h | 15 +-- 2 files changed, 149 insertions(+), 136 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index e9096bf4..2211c93b 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -311,69 +311,49 @@ void FPGAViewWidget::initializeGL() 0.0); } -void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) +void FPGAViewWidget::drawGraphicElement(LineShaderData &out, const GraphicElement &el, float x, float y) { const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; - for (auto &el : ctx_->getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; + if (el.type == GraphicElement::TYPE_BOX) { + auto line = PolyLine(true); + line.point(x + scale * el.x1, y + scale * el.y1); + line.point(x + scale * el.x2, y + scale * el.y1); + line.point(x + scale * el.x2, y + scale * el.y2); + line.point(x + scale * el.x1, y + scale * el.y2); + line.build(out); + } - if (el.type == GraphicElement::TYPE_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - line.build(out); - } - - if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { - PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) - .build(out); - } + if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { + PolyLine(x + scale * el.x1, y + scale * el.y1, x + scale * el.x2, y + scale * el.y2) + .build(out); } } -void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) +void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) { - const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; + float offsetX = decal.x; + float offsetY = decal.y; for (auto &el : ctx_->getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; + drawGraphicElement(out, el, offsetX, offsetY); + } +} - if (el.type == GraphicElement::TYPE_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::STYLE_FRAME: - case GraphicElement::STYLE_INACTIVE: - case GraphicElement::STYLE_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } - } +void FPGAViewWidget::drawArchDecal(LineShaderData out[GraphicElement::STYLE_MAX], const DecalXY &decal) +{ + float offsetX = decal.x; + float offsetY = decal.y; - if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { - auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, - offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::STYLE_FRAME: - case GraphicElement::STYLE_INACTIVE: - case GraphicElement::STYLE_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } + for (auto &el : ctx_->getDecalGraphics(decal.decal)) { + switch (el.style) { + case GraphicElement::STYLE_FRAME: + case GraphicElement::STYLE_INACTIVE: + case GraphicElement::STYLE_ACTIVE: + drawGraphicElement(out[el.style], el, offsetX, offsetY); + break; + default: + break; } } } @@ -403,24 +383,28 @@ void FPGAViewWidget::paintGL() float thick1Px = mouseToWorldCoordinates(1, 0).x(); float thick11Px = mouseToWorldCoordinates(1.1, 0).x(); - // Draw grid. + // Render grid. auto grid = LineShaderData(); for (float i = -100.0f; i < 100.0f; i += 1.0f) { PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); } + // Draw grid. lineShader_.draw(grid, colors_.grid, thick1Px, matrix); rendererDataLock_.lock(); - lineShader_.draw(rendererData_->decals[0], colors_.frame, thick11Px, matrix); - lineShader_.draw(rendererData_->decals[1], colors_.hidden, thick11Px, matrix); - lineShader_.draw(rendererData_->decals[2], colors_.inactive, thick11Px, matrix); - lineShader_.draw(rendererData_->decals[3], colors_.active, thick11Px, matrix); + // Render Arch graphics. + lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_FRAME], colors_.frame, thick11Px, matrix); + lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_HIDDEN], colors_.hidden, thick11Px, matrix); + lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_INACTIVE], colors_.inactive, thick11Px, matrix); + lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_ACTIVE], colors_.active, thick11Px, matrix); + + // Draw highlighted items. for (int i = 0; i < 8; i++) - lineShader_.draw(rendererData_->highlighted[i], colors_.highlight[i], thick11Px, matrix); + lineShader_.draw(rendererData_->gfxHighlighted[i], colors_.highlight[i], thick11Px, matrix); - lineShader_.draw(rendererData_->selected, colors_.selected, thick11Px, matrix); + lineShader_.draw(rendererData_->gfxSelected, colors_.selected, thick11Px, matrix); rendererDataLock_.unlock(); } @@ -431,120 +415,148 @@ void FPGAViewWidget::renderLines(void) if (ctx_ == nullptr) return; - ctx_->lock_ui(); - - // For now, collapse any decal changes into change of all decals. - // TODO(q3k): fix this - bool decalsChanged = false; - if (ctx_->allUiReload) { - ctx_->allUiReload = false; - decalsChanged = true; - } - if (ctx_->frameUiReload) { - ctx_->frameUiReload = false; - decalsChanged = true; - } - if (ctx_->belUiReload.size() > 0) { - ctx_->belUiReload.clear(); - decalsChanged = true; - } - if (ctx_->wireUiReload.size() > 0) { - ctx_->wireUiReload.clear(); - decalsChanged = true; - } - if (ctx_->pipUiReload.size() > 0) { - ctx_->pipUiReload.clear(); - decalsChanged = true; - } - if (ctx_->groupUiReload.size() > 0) { - ctx_->groupUiReload.clear(); - decalsChanged = true; - } - - // Local copy of decals, taken as fast as possible to not block the P&R. + // Data from Context needed to render all decals. std::vector belDecals; std::vector wireDecals; std::vector pipDecals; std::vector groupDecals; - if (decalsChanged) { - for (auto bel : ctx_->getBels()) { - belDecals.push_back(ctx_->getBelDecal(bel)); + bool decalsChanged = false; + { + // Take the UI/Normal mutex on the Context, copy over all we need as + // fast as we can. + std::lock_guard lock_ui(ctx_->ui_mutex); + std::lock_guard lock(ctx_->mutex); + + // For now, collapse any decal changes into change of all decals. + // TODO(q3k): fix this + if (ctx_->allUiReload) { + ctx_->allUiReload = false; + decalsChanged = true; } - for (auto wire : ctx_->getWires()) { - wireDecals.push_back(ctx_->getWireDecal(wire)); + if (ctx_->frameUiReload) { + ctx_->frameUiReload = false; + decalsChanged = true; } - for (auto pip : ctx_->getPips()) { - pipDecals.push_back(ctx_->getPipDecal(pip)); + if (ctx_->belUiReload.size() > 0) { + ctx_->belUiReload.clear(); + decalsChanged = true; } - for (auto group : ctx_->getGroups()) { - groupDecals.push_back(ctx_->getGroupDecal(group)); + if (ctx_->wireUiReload.size() > 0) { + ctx_->wireUiReload.clear(); + decalsChanged = true; + } + if (ctx_->pipUiReload.size() > 0) { + ctx_->pipUiReload.clear(); + decalsChanged = true; + } + if (ctx_->groupUiReload.size() > 0) { + ctx_->groupUiReload.clear(); + decalsChanged = true; + } + + // Local copy of decals, taken as fast as possible to not block the P&R. + if (decalsChanged) { + for (auto bel : ctx_->getBels()) { + belDecals.push_back(ctx_->getBelDecal(bel)); + } + for (auto wire : ctx_->getWires()) { + wireDecals.push_back(ctx_->getWireDecal(wire)); + } + for (auto pip : ctx_->getPips()) { + pipDecals.push_back(ctx_->getPipDecal(pip)); + } + for (auto group : ctx_->getGroups()) { + groupDecals.push_back(ctx_->getGroupDecal(group)); + } } } - ctx_->unlock_ui(); - rendererArgsLock_.lock(); - auto selectedItems = rendererArgs_->selectedItems; - auto highlightedItems = rendererArgs_->highlightedItems; - auto highlightedOrSelectedChanged = rendererArgs_->highlightedOrSelectedChanged; - rendererArgs_->highlightedOrSelectedChanged = false; - rendererArgsLock_.unlock(); + // Arguments from the main UI thread on what we should render. + std::vector selectedDecals; + std::vector highlightedDecals[8]; + bool highlightedOrSelectedChanged; + { + // Take the renderer arguments lock, copy over all we need. + QMutexLocker lock(&rendererArgsLock_); + selectedDecals = rendererArgs_->selectedDecals; + for (int i = 0; i < 8; i++) + highlightedDecals[i] = rendererArgs_->highlightedDecals[i]; + highlightedOrSelectedChanged = rendererArgs_->highlightedOrSelectedChanged; + rendererArgs_->highlightedOrSelectedChanged = false; + } + // Render decals if necessary. if (decalsChanged) { auto data = std::unique_ptr(new FPGAViewWidget::RendererData); // Draw Bels. for (auto const &decal : belDecals) { - drawDecal(data->decals, decal); + drawArchDecal(data->gfxByStyle, decal); } // Draw Wires. for (auto const &decal : wireDecals) { - drawDecal(data->decals, decal); + drawArchDecal(data->gfxByStyle, decal); } // Draw Pips. for (auto const &decal : pipDecals) { - drawDecal(data->decals, decal); + drawArchDecal(data->gfxByStyle, decal); } // Draw Groups. for (auto const &decal : groupDecals) { - drawDecal(data->decals, decal); + drawArchDecal(data->gfxByStyle, decal); } // Swap over. - rendererDataLock_.lock(); - rendererData_ = std::move(data); - rendererDataLock_.unlock(); + { + QMutexLocker lock(&rendererDataLock_); + + // If we're not re-rendering any highlights/selections, let's + // copy them over from teh current object. + if (!highlightedOrSelectedChanged) { + data->gfxSelected = rendererData_->gfxSelected; + for (int i = 0; i < 8; i++) + data->gfxHighlighted[i] = rendererData_->gfxHighlighted[i]; + } + + rendererData_ = std::move(data); + } } - rendererDataLock_.lock(); - if (decalsChanged || highlightedOrSelectedChanged) { - rendererData_->selected.clear(); - for (auto &decal : selectedItems) { - drawDecal(rendererData_->selected, decal); + if (highlightedOrSelectedChanged) { + QMutexLocker locker(&rendererDataLock_); + + // Render selected. + rendererData_->gfxSelected.clear(); + for (auto &decal : selectedDecals) { + drawDecal(rendererData_->gfxSelected, decal); } + + // Render highlighted. for (int i = 0; i < 8; i++) { - rendererData_->highlighted[i].clear(); - for (auto &decal : highlightedItems[i]) { - drawDecal(rendererData_->highlighted[i], decal); + rendererData_->gfxHighlighted[i].clear(); + for (auto &decal : highlightedDecals[i]) { + drawDecal(rendererData_->gfxHighlighted[i], decal); } } } - rendererDataLock_.unlock(); } void FPGAViewWidget::onSelectedArchItem(std::vector decals) { - rendererArgsLock_.lock(); - rendererArgs_->selectedItems = decals; - rendererArgs_->highlightedOrSelectedChanged = true; - rendererArgsLock_.unlock(); + { + QMutexLocker locker(&rendererArgsLock_); + rendererArgs_->selectedDecals = decals; + rendererArgs_->highlightedOrSelectedChanged = true; + } pokeRenderer(); } void FPGAViewWidget::onHighlightGroupChanged(std::vector decals, int group) { - rendererArgsLock_.lock(); - rendererArgs_->highlightedItems[group] = decals; - rendererArgs_->highlightedOrSelectedChanged = true; - rendererArgsLock_.unlock(); + { + QMutexLocker locker(&rendererArgsLock_); + rendererArgs_->highlightedDecals[group] = decals; + rendererArgs_->highlightedOrSelectedChanged = true; + } pokeRenderer(); } diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 46231b16..69e947cf 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -277,8 +277,6 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; - void drawDecal(LineShaderData &data, const DecalXY &decal); - void drawDecal(LineShaderData out[], const DecalXY &decal); public Q_SLOTS: void newContext(Context *ctx); @@ -291,6 +289,9 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void zoomOutbound(); private: + void drawGraphicElement(LineShaderData &out, const GraphicElement &el, float x, float y); + void drawArchDecal(LineShaderData out[GraphicElement::STYLE_MAX], const DecalXY &decal); + void drawDecal(LineShaderData &out, const DecalXY &decal); void renderLines(void); void zoom(int level); @@ -326,15 +327,15 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions struct RendererData { - LineShaderData decals[4]; - LineShaderData selected; - LineShaderData highlighted[8]; + LineShaderData gfxByStyle[GraphicElement::STYLE_MAX]; + LineShaderData gfxSelected; + LineShaderData gfxHighlighted[8]; }; struct RendererArgs { - std::vector selectedItems; - std::vector highlightedItems[8]; + std::vector selectedDecals; + std::vector highlightedDecals[8]; bool highlightedOrSelectedChanged; }; From ba5395d89fea3a0a646d9bf3df643dac8c8bdec4 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 26 Jul 2018 17:33:19 +0100 Subject: [PATCH 17/21] gui: refactor FPGAViewWidget even more slightly --- gui/fpgaviewwidget.cc | 16 +++++++++------- gui/fpgaviewwidget.h | 40 +++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 2211c93b..d87c26a3 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -242,9 +242,11 @@ 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), paintTimer_(this), - rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs) +FPGAViewWidget::FPGAViewWidget(QWidget *parent) : + QOpenGLWidget(parent), ctx_(nullptr), paintTimer_(this), + lineShader_(this), zoom_(500.0f), + rendererData_(new FPGAViewWidget::RendererData), + rendererArgs_(new FPGAViewWidget::RendererArgs) { colors_.background = QColor("#000000"); colors_.grid = QColor("#333"); @@ -562,7 +564,7 @@ void FPGAViewWidget::onHighlightGroupChanged(std::vector decals, int gr void FPGAViewWidget::resizeGL(int width, int height) {} -void FPGAViewWidget::mousePressEvent(QMouseEvent *event) { lastPos_ = event->pos(); } +void FPGAViewWidget::mousePressEvent(QMouseEvent *event) { lastDragPos_ = event->pos(); } // Invert the projection matrix to calculate screen/mouse to world/grid // coordinates. @@ -578,9 +580,9 @@ QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y) void FPGAViewWidget::mouseMoveEvent(QMouseEvent *event) { - const int dx = event->x() - lastPos_.x(); - const int dy = event->y() - lastPos_.y(); - lastPos_ = event->pos(); + const int dx = event->x() - lastDragPos_.x(); + const int dy = event->y() - lastDragPos_.y(); + lastDragPos_ = event->pos(); auto world = mouseToWorldCoordinates(dx, dy); viewMove_.translate(world.x(), -world.y()); diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 69e947cf..6505c555 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -267,16 +267,17 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions FPGAViewWidget(QWidget *parent = 0); ~FPGAViewWidget(); - QSize minimumSizeHint() const override; - QSize sizeHint() const override; - protected: + // Qt callbacks. void initializeGL() Q_DECL_OVERRIDE; void paintGL() Q_DECL_OVERRIDE; void resizeGL(int width, int height) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + public Q_SLOTS: void newContext(Context *ctx); @@ -289,30 +290,20 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void zoomOutbound(); private: - void drawGraphicElement(LineShaderData &out, const GraphicElement &el, float x, float y); - void drawArchDecal(LineShaderData out[GraphicElement::STYLE_MAX], const DecalXY &decal); - void drawDecal(LineShaderData &out, const DecalXY &decal); - void renderLines(void); - void zoom(int level); - - QPoint lastPos_; - LineShader lineShader_; - QMatrix4x4 viewMove_; - float zoom_; - QMatrix4x4 getProjection(void); - QVector4D mouseToWorldCoordinates(int x, int y); - const float zoomNear_ = 1.0f; // do not zoom closer than this const float zoomFar_ = 10000.0f; // do not zoom further than this - const float zoomLvl1_ = 100.0f; const float zoomLvl2_ = 50.0f; Context *ctx_; QTimer paintTimer_; - std::unique_ptr renderRunner_; + QPoint lastDragPos_; + LineShader lineShader_; + QMatrix4x4 viewMove_; + float zoom_; + struct { QColor background; @@ -331,6 +322,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions LineShaderData gfxSelected; LineShaderData gfxHighlighted[8]; }; + std::unique_ptr rendererData_; + QMutex rendererDataLock_; struct RendererArgs { @@ -338,11 +331,16 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions std::vector highlightedDecals[8]; bool highlightedOrSelectedChanged; }; - - std::unique_ptr rendererData_; - QMutex rendererDataLock_; std::unique_ptr rendererArgs_; QMutex rendererArgsLock_; + + void zoom(int level); + void renderLines(void); + void drawGraphicElement(LineShaderData &out, const GraphicElement &el, float x, float y); + void drawDecal(LineShaderData &out, const DecalXY &decal); + void drawArchDecal(LineShaderData out[GraphicElement::STYLE_MAX], const DecalXY &decal); + QVector4D mouseToWorldCoordinates(int x, int y); + QMatrix4x4 getProjection(void); }; NEXTPNR_NAMESPACE_END From 16acc6ea43f4c45dfb0e9550d731a2fba3f32618 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 26 Jul 2018 17:37:24 +0100 Subject: [PATCH 18/21] gui: move polyline/lineshader to gui/lineshader.{h,cc} --- gui/fpgaviewwidget.cc | 211 ------------------------------------------ gui/fpgaviewwidget.h | 175 +---------------------------------- 2 files changed, 1 insertion(+), 385 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index d87c26a3..de73e27b 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -31,217 +31,6 @@ NEXTPNR_NAMESPACE_BEGIN -void PolyLine::buildPoint(LineShaderData *building, const QVector2D *prev, const QVector2D *cur, - const QVector2D *next) const -{ - // buildPoint emits two vertices per line point, along with normals to move - // them the right directio when rendering and miter to compensate for - // bends. - - if (cur == nullptr) { - // BUG - return; - } - - if (prev == nullptr && next == nullptr) { - // BUG - return; - } - - // TODO(q3k): fast path for vertical/horizontal lines? - - // TODO(q3k): consider moving some of the linear algebra to the GPU, - // they're better at this than poor old CPUs. - - // Build two unit vectors pointing in the direction of the two segments - // defined by (prev, cur) and (cur, next) - QVector2D dprev, dnext; - if (prev == nullptr) { - dnext = *next - *cur; - dprev = dnext; - } else if (next == nullptr) { - dprev = *cur - *prev; - dnext = dprev; - } else { - dprev = *cur - *prev; - dnext = *next - *cur; - } - dprev.normalize(); - dnext.normalize(); - - // Calculate tangent unit vector. - QVector2D tangent(dprev + dnext); - tangent.normalize(); - - // Calculate normal to tangent - this is the line on which the vectors need - // to be pushed to build a thickened line. - const QVector2D tangent_normal = QVector2D(-tangent.y(), tangent.x()); - - // Calculate normal to one of the lines. - const QVector2D dprev_normal = QVector2D(-dprev.y(), dprev.x()); - // https://people.eecs.berkeley.edu/~sequin/CS184/IMGS/Sweep_PolyLine.jpg - // (the ^-1 is performed in the shader) - const float miter = QVector2D::dotProduct(tangent_normal, dprev_normal); - - const float x = cur->x(); - const float y = cur->y(); - const float mx = tangent_normal.x(); - const float my = tangent_normal.y(); - - // Push back 'left' vertex. - building->vertices.push_back(Vertex2DPOD(x, y)); - building->normals.push_back(Vertex2DPOD(mx, my)); - building->miters.push_back(miter); - - // Push back 'right' vertex. - building->vertices.push_back(Vertex2DPOD(x, y)); - building->normals.push_back(Vertex2DPOD(mx, my)); - building->miters.push_back(-miter); -} - -void PolyLine::build(LineShaderData &target) const -{ - if (points_.size() < 2) { - return; - } - const QVector2D *first = &points_.front(); - const QVector2D *last = &points_.back(); - - // Index number of vertices, used to build the index buffer. - unsigned int startIndex = target.vertices.size(); - unsigned int index = startIndex; - - // For every point on the line, call buildPoint with (prev, point, next). - // If we're building a closed line, prev/next wrap around. Otherwise - // they are passed as nullptr and buildPoint interprets that accordinglu. - const QVector2D *prev = nullptr; - - // Loop iterator used to ensure next is valid. - unsigned int i = 0; - for (const QVector2D &point : points_) { - const QVector2D *next = nullptr; - if (++i < points_.size()) { - next = (&point + 1); - } - - // If the line is closed, wrap around. Otherwise, pass nullptr. - if (prev == nullptr && closed_) { - buildPoint(&target, last, &point, next); - } else if (next == nullptr && closed_) { - buildPoint(&target, prev, &point, first); - } else { - buildPoint(&target, prev, &point, next); - } - - // If we have a prev point relative to cur, build a pair of triangles - // to render vertices into lines. - if (prev != nullptr) { - target.indices.push_back(index); - target.indices.push_back(index + 1); - target.indices.push_back(index + 2); - - target.indices.push_back(index + 2); - target.indices.push_back(index + 1); - target.indices.push_back(index + 3); - - index += 2; - } - prev = &point; - } - - // If we're closed, build two more vertices that loop the line around. - if (closed_) { - target.indices.push_back(index); - target.indices.push_back(index + 1); - target.indices.push_back(startIndex); - - target.indices.push_back(startIndex); - target.indices.push_back(index + 1); - target.indices.push_back(startIndex + 1); - } -} - -bool LineShader::compile(void) -{ - program_ = new QOpenGLShaderProgram(parent_); - program_->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource_); - program_->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource_); - if (!program_->link()) { - printf("could not link program: %s\n", program_->log().toStdString().c_str()); - return false; - } - - if (!vao_.create()) - log_abort(); - vao_.bind(); - - if (!buffers_.position.create()) - log_abort(); - if (!buffers_.normal.create()) - log_abort(); - if (!buffers_.miter.create()) - log_abort(); - if (!buffers_.index.create()) - log_abort(); - - attributes_.position = program_->attributeLocation("position"); - attributes_.normal = program_->attributeLocation("normal"); - attributes_.miter = program_->attributeLocation("miter"); - uniforms_.thickness = program_->uniformLocation("thickness"); - uniforms_.projection = program_->uniformLocation("projection"); - uniforms_.color = program_->uniformLocation("color"); - - vao_.release(); - return true; -} - -void LineShader::draw(const LineShaderData &line, const QColor &color, float thickness, const QMatrix4x4 &projection) -{ - auto gl = QOpenGLContext::currentContext()->functions(); - if (line.vertices.size() == 0) - return; - vao_.bind(); - program_->bind(); - - buffers_.position.bind(); - buffers_.position.allocate(&line.vertices[0], sizeof(Vertex2DPOD) * line.vertices.size()); - - buffers_.normal.bind(); - buffers_.normal.allocate(&line.normals[0], sizeof(Vertex2DPOD) * line.normals.size()); - - buffers_.miter.bind(); - buffers_.miter.allocate(&line.miters[0], sizeof(GLfloat) * line.miters.size()); - - buffers_.index.bind(); - buffers_.index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size()); - - program_->setUniformValue(uniforms_.projection, projection); - program_->setUniformValue(uniforms_.thickness, thickness); - program_->setUniformValue(uniforms_.color, color.redF(), color.greenF(), color.blueF(), color.alphaF()); - - buffers_.position.bind(); - program_->enableAttributeArray("position"); - gl->glVertexAttribPointer(attributes_.position, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); - - buffers_.normal.bind(); - program_->enableAttributeArray("normal"); - gl->glVertexAttribPointer(attributes_.normal, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); - - buffers_.miter.bind(); - program_->enableAttributeArray("miter"); - gl->glVertexAttribPointer(attributes_.miter, 1, GL_FLOAT, GL_FALSE, 0, (void *)0); - - buffers_.index.bind(); - gl->glDrawElements(GL_TRIANGLES, line.indices.size(), GL_UNSIGNED_INT, (void *)0); - - program_->disableAttributeArray("miter"); - program_->disableAttributeArray("normal"); - program_->disableAttributeArray("position"); - - program_->release(); - vao_.release(); -} - FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), ctx_(nullptr), paintTimer_(this), lineShader_(this), zoom_(500.0f), diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 6505c555..260ebf05 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -33,183 +33,10 @@ #include #include "nextpnr.h" +#include "lineshader.h" NEXTPNR_NAMESPACE_BEGIN -// Vertex2DPOD is a structure of X, Y coordinates that can be passed to OpenGL -// directly. -NPNR_PACKED_STRUCT(struct Vertex2DPOD { - GLfloat x; - GLfloat y; - - Vertex2DPOD(GLfloat X, GLfloat Y) : x(X), y(Y) {} -}); - -// LineShaderData is a built set of vertices that can be rendered by the -// LineShader. -// Each LineShaderData can have its' own color and thickness. -struct LineShaderData -{ - std::vector vertices; - std::vector normals; - std::vector miters; - std::vector indices; - - LineShaderData(void) {} - - void clear(void) - { - vertices.clear(); - normals.clear(); - miters.clear(); - indices.clear(); - } -}; - -// PolyLine is a set of segments defined by points, that can be built to a -// ShaderLine for GPU rendering. -class PolyLine -{ - private: - std::vector points_; - bool closed_; - - void buildPoint(LineShaderData *building, const QVector2D *prev, const QVector2D *cur, const QVector2D *next) const; - - public: - // Create an empty PolyLine. - PolyLine(bool closed = false) : closed_(closed) {} - - // Create a non-closed polyline consisting of one segment. - PolyLine(float x0, float y0, float x1, float y1) : closed_(false) - { - point(x0, y0); - point(x1, y1); - } - - // Add a point to the PolyLine. - void point(float x, float y) { points_.push_back(QVector2D(x, y)); } - - // Built PolyLine to shader data. - void build(LineShaderData &target) const; - - // Set whether line is closed (ie. a loop). - void setClosed(bool closed) { closed_ = closed; } -}; - -// LineShader is an OpenGL shader program that renders LineShaderData on the -// GPU. -// The LineShader expects two vertices per line point. It will push those -// vertices along the given normal * miter. This is used to 'stretch' the line -// to be as wide as the given thickness. The normal and miter are calculated -// by the PolyLine build method in order to construct a constant thickness line -// with miter edge joints. -// -// +------+------+ -// -// | -// PolyLine.build() -// | -// V -// -// ^ ^ ^ -// | | | <--- normal vectors (x2, pointing in the same -// +/+----+/+----+/+ direction) -// -// | -// vertex shader -// | -// V -// -// +------+------+ ^ by normal * miter * thickness/2 -// | | | -// +------+------+ V by normal * miter * thickness/2 -// -// (miter is flipped for every second vertex generated) -class LineShader -{ - private: - QObject *parent_; - QOpenGLShaderProgram *program_; - - // GL attribute locations. - struct - { - // original position of line vertex - GLuint position; - // normal by which vertex should be translated - GLuint normal; - // scalar defining: - // - how stretched the normal vector should be to - // compensate for bends - // - which way the normal should be applied (+1 for one vertex, -1 - // for the other) - GLuint miter; - } attributes_; - - // GL buffers - struct - { - QOpenGLBuffer position; - QOpenGLBuffer normal; - QOpenGLBuffer miter; - QOpenGLBuffer index; - } buffers_; - - // GL uniform locations. - struct - { - // combines m/v/p matrix to apply - GLuint projection; - // desired thickness of line - GLuint thickness; - // color of line - GLuint color; - } uniforms_; - - QOpenGLVertexArrayObject vao_; - - public: - LineShader(QObject *parent) : parent_(parent), program_(nullptr) - { - buffers_.position = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); - buffers_.position.setUsagePattern(QOpenGLBuffer::StaticDraw); - - buffers_.normal = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); - buffers_.normal.setUsagePattern(QOpenGLBuffer::StaticDraw); - - buffers_.miter = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); - buffers_.miter.setUsagePattern(QOpenGLBuffer::StaticDraw); - - buffers_.index = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); - buffers_.index.setUsagePattern(QOpenGLBuffer::StaticDraw); - } - - static constexpr const char *vertexShaderSource_ = - "#version 110\n" - "attribute highp vec2 position;\n" - "attribute highp vec2 normal;\n" - "attribute highp float miter;\n" - "uniform highp float thickness;\n" - "uniform highp mat4 projection;\n" - "void main() {\n" - " vec2 p = position.xy + vec2(normal * thickness/2.0 / miter);\n" - " gl_Position = projection * vec4(p, 0.0, 1.0);\n" - "}\n"; - - static constexpr const char *fragmentShaderSource_ = "#version 110\n" - "uniform lowp vec4 color;\n" - "void main() {\n" - " gl_FragColor = color;\n" - "}\n"; - - // Must be called on initialization. - bool compile(void); - - // Render a LineShaderData with a given M/V/P transformation. - void draw(const LineShaderData &data, const QColor &color, float thickness, const QMatrix4x4 &projection); -}; - class PeriodicRunner : public QThread { Q_OBJECT From ae6eeb9d810c647ca1684459627b8dd20870f993 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 26 Jul 2018 17:39:22 +0100 Subject: [PATCH 19/21] gui: include linshader.{cc,h} --- gui/lineshader.cc | 236 ++++++++++++++++++++++++++++++++++++++++++++++ gui/lineshader.h | 209 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 gui/lineshader.cc create mode 100644 gui/lineshader.h diff --git a/gui/lineshader.cc b/gui/lineshader.cc new file mode 100644 index 00000000..94a7a010 --- /dev/null +++ b/gui/lineshader.cc @@ -0,0 +1,236 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Serge Bazanski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "log.h" +#include "lineshader.h" + +NEXTPNR_NAMESPACE_BEGIN + +void PolyLine::buildPoint(LineShaderData *building, const QVector2D *prev, const QVector2D *cur, + const QVector2D *next) const +{ + // buildPoint emits two vertices per line point, along with normals to move + // them the right directio when rendering and miter to compensate for + // bends. + + if (cur == nullptr) { + // BUG + return; + } + + if (prev == nullptr && next == nullptr) { + // BUG + return; + } + + // TODO(q3k): fast path for vertical/horizontal lines? + + // TODO(q3k): consider moving some of the linear algebra to the GPU, + // they're better at this than poor old CPUs. + + // Build two unit vectors pointing in the direction of the two segments + // defined by (prev, cur) and (cur, next) + QVector2D dprev, dnext; + if (prev == nullptr) { + dnext = *next - *cur; + dprev = dnext; + } else if (next == nullptr) { + dprev = *cur - *prev; + dnext = dprev; + } else { + dprev = *cur - *prev; + dnext = *next - *cur; + } + dprev.normalize(); + dnext.normalize(); + + // Calculate tangent unit vector. + QVector2D tangent(dprev + dnext); + tangent.normalize(); + + // Calculate normal to tangent - this is the line on which the vectors need + // to be pushed to build a thickened line. + const QVector2D tangent_normal = QVector2D(-tangent.y(), tangent.x()); + + // Calculate normal to one of the lines. + const QVector2D dprev_normal = QVector2D(-dprev.y(), dprev.x()); + // https://people.eecs.berkeley.edu/~sequin/CS184/IMGS/Sweep_PolyLine.jpg + // (the ^-1 is performed in the shader) + const float miter = QVector2D::dotProduct(tangent_normal, dprev_normal); + + const float x = cur->x(); + const float y = cur->y(); + const float mx = tangent_normal.x(); + const float my = tangent_normal.y(); + + // Push back 'left' vertex. + building->vertices.push_back(Vertex2DPOD(x, y)); + building->normals.push_back(Vertex2DPOD(mx, my)); + building->miters.push_back(miter); + + // Push back 'right' vertex. + building->vertices.push_back(Vertex2DPOD(x, y)); + building->normals.push_back(Vertex2DPOD(mx, my)); + building->miters.push_back(-miter); +} + +void PolyLine::build(LineShaderData &target) const +{ + if (points_.size() < 2) { + return; + } + const QVector2D *first = &points_.front(); + const QVector2D *last = &points_.back(); + + // Index number of vertices, used to build the index buffer. + unsigned int startIndex = target.vertices.size(); + unsigned int index = startIndex; + + // For every point on the line, call buildPoint with (prev, point, next). + // If we're building a closed line, prev/next wrap around. Otherwise + // they are passed as nullptr and buildPoint interprets that accordinglu. + const QVector2D *prev = nullptr; + + // Loop iterator used to ensure next is valid. + unsigned int i = 0; + for (const QVector2D &point : points_) { + const QVector2D *next = nullptr; + if (++i < points_.size()) { + next = (&point + 1); + } + + // If the line is closed, wrap around. Otherwise, pass nullptr. + if (prev == nullptr && closed_) { + buildPoint(&target, last, &point, next); + } else if (next == nullptr && closed_) { + buildPoint(&target, prev, &point, first); + } else { + buildPoint(&target, prev, &point, next); + } + + // If we have a prev point relative to cur, build a pair of triangles + // to render vertices into lines. + if (prev != nullptr) { + target.indices.push_back(index); + target.indices.push_back(index + 1); + target.indices.push_back(index + 2); + + target.indices.push_back(index + 2); + target.indices.push_back(index + 1); + target.indices.push_back(index + 3); + + index += 2; + } + prev = &point; + } + + // If we're closed, build two more vertices that loop the line around. + if (closed_) { + target.indices.push_back(index); + target.indices.push_back(index + 1); + target.indices.push_back(startIndex); + + target.indices.push_back(startIndex); + target.indices.push_back(index + 1); + target.indices.push_back(startIndex + 1); + } +} + +bool LineShader::compile(void) +{ + program_ = new QOpenGLShaderProgram(parent_); + program_->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource_); + program_->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource_); + if (!program_->link()) { + printf("could not link program: %s\n", program_->log().toStdString().c_str()); + return false; + } + + if (!vao_.create()) + log_abort(); + vao_.bind(); + + if (!buffers_.position.create()) + log_abort(); + if (!buffers_.normal.create()) + log_abort(); + if (!buffers_.miter.create()) + log_abort(); + if (!buffers_.index.create()) + log_abort(); + + attributes_.position = program_->attributeLocation("position"); + attributes_.normal = program_->attributeLocation("normal"); + attributes_.miter = program_->attributeLocation("miter"); + uniforms_.thickness = program_->uniformLocation("thickness"); + uniforms_.projection = program_->uniformLocation("projection"); + uniforms_.color = program_->uniformLocation("color"); + + vao_.release(); + return true; +} + +void LineShader::draw(const LineShaderData &line, const QColor &color, float thickness, const QMatrix4x4 &projection) +{ + auto gl = QOpenGLContext::currentContext()->functions(); + if (line.vertices.size() == 0) + return; + vao_.bind(); + program_->bind(); + + buffers_.position.bind(); + buffers_.position.allocate(&line.vertices[0], sizeof(Vertex2DPOD) * line.vertices.size()); + + buffers_.normal.bind(); + buffers_.normal.allocate(&line.normals[0], sizeof(Vertex2DPOD) * line.normals.size()); + + buffers_.miter.bind(); + buffers_.miter.allocate(&line.miters[0], sizeof(GLfloat) * line.miters.size()); + + buffers_.index.bind(); + buffers_.index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size()); + + program_->setUniformValue(uniforms_.projection, projection); + program_->setUniformValue(uniforms_.thickness, thickness); + program_->setUniformValue(uniforms_.color, color.redF(), color.greenF(), color.blueF(), color.alphaF()); + + buffers_.position.bind(); + program_->enableAttributeArray("position"); + gl->glVertexAttribPointer(attributes_.position, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); + + buffers_.normal.bind(); + program_->enableAttributeArray("normal"); + gl->glVertexAttribPointer(attributes_.normal, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); + + buffers_.miter.bind(); + program_->enableAttributeArray("miter"); + gl->glVertexAttribPointer(attributes_.miter, 1, GL_FLOAT, GL_FALSE, 0, (void *)0); + + buffers_.index.bind(); + gl->glDrawElements(GL_TRIANGLES, line.indices.size(), GL_UNSIGNED_INT, (void *)0); + + program_->disableAttributeArray("miter"); + program_->disableAttributeArray("normal"); + program_->disableAttributeArray("position"); + + program_->release(); + vao_.release(); +} + +NEXTPNR_NAMESPACE_END diff --git a/gui/lineshader.h b/gui/lineshader.h new file mode 100644 index 00000000..3f4c4057 --- /dev/null +++ b/gui/lineshader.h @@ -0,0 +1,209 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Serge Bazanski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef LINESHADER_H +#define LINESHADER_H + +#include +#include +#include +#include +#include + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +// Vertex2DPOD is a structure of X, Y coordinates that can be passed to OpenGL +// directly. +NPNR_PACKED_STRUCT(struct Vertex2DPOD { + GLfloat x; + GLfloat y; + + Vertex2DPOD(GLfloat X, GLfloat Y) : x(X), y(Y) {} +}); + +// LineShaderData is a built set of vertices that can be rendered by the +// LineShader. +// Each LineShaderData can have its' own color and thickness. +struct LineShaderData +{ + std::vector vertices; + std::vector normals; + std::vector miters; + std::vector indices; + + LineShaderData(void) {} + + void clear(void) + { + vertices.clear(); + normals.clear(); + miters.clear(); + indices.clear(); + } +}; + +// PolyLine is a set of segments defined by points, that can be built to a +// ShaderLine for GPU rendering. +class PolyLine +{ + private: + std::vector points_; + bool closed_; + + void buildPoint(LineShaderData *building, const QVector2D *prev, const QVector2D *cur, const QVector2D *next) const; + + public: + // Create an empty PolyLine. + PolyLine(bool closed = false) : closed_(closed) {} + + // Create a non-closed polyline consisting of one segment. + PolyLine(float x0, float y0, float x1, float y1) : closed_(false) + { + point(x0, y0); + point(x1, y1); + } + + // Add a point to the PolyLine. + void point(float x, float y) { points_.push_back(QVector2D(x, y)); } + + // Built PolyLine to shader data. + void build(LineShaderData &target) const; + + // Set whether line is closed (ie. a loop). + void setClosed(bool closed) { closed_ = closed; } +}; + +// LineShader is an OpenGL shader program that renders LineShaderData on the +// GPU. +// The LineShader expects two vertices per line point. It will push those +// vertices along the given normal * miter. This is used to 'stretch' the line +// to be as wide as the given thickness. The normal and miter are calculated +// by the PolyLine build method in order to construct a constant thickness line +// with miter edge joints. +// +// +------+------+ +// +// | +// PolyLine.build() +// | +// V +// +// ^ ^ ^ +// | | | <--- normal vectors (x2, pointing in the same +// +/+----+/+----+/+ direction) +// +// | +// vertex shader +// | +// V +// +// +------+------+ ^ by normal * miter * thickness/2 +// | | | +// +------+------+ V by normal * miter * thickness/2 +// +// (miter is flipped for every second vertex generated) +class LineShader +{ + private: + QObject *parent_; + QOpenGLShaderProgram *program_; + + // GL attribute locations. + struct + { + // original position of line vertex + GLuint position; + // normal by which vertex should be translated + GLuint normal; + // scalar defining: + // - how stretched the normal vector should be to + // compensate for bends + // - which way the normal should be applied (+1 for one vertex, -1 + // for the other) + GLuint miter; + } attributes_; + + // GL buffers + struct + { + QOpenGLBuffer position; + QOpenGLBuffer normal; + QOpenGLBuffer miter; + QOpenGLBuffer index; + } buffers_; + + // GL uniform locations. + struct + { + // combines m/v/p matrix to apply + GLuint projection; + // desired thickness of line + GLuint thickness; + // color of line + GLuint color; + } uniforms_; + + QOpenGLVertexArrayObject vao_; + + public: + LineShader(QObject *parent) : parent_(parent), program_(nullptr) + { + buffers_.position = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + buffers_.position.setUsagePattern(QOpenGLBuffer::StaticDraw); + + buffers_.normal = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + buffers_.normal.setUsagePattern(QOpenGLBuffer::StaticDraw); + + buffers_.miter = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + buffers_.miter.setUsagePattern(QOpenGLBuffer::StaticDraw); + + buffers_.index = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); + buffers_.index.setUsagePattern(QOpenGLBuffer::StaticDraw); + } + + static constexpr const char *vertexShaderSource_ = + "#version 110\n" + "attribute highp vec2 position;\n" + "attribute highp vec2 normal;\n" + "attribute highp float miter;\n" + "uniform highp float thickness;\n" + "uniform highp mat4 projection;\n" + "void main() {\n" + " vec2 p = position.xy + vec2(normal * thickness/2.0 / miter);\n" + " gl_Position = projection * vec4(p, 0.0, 1.0);\n" + "}\n"; + + static constexpr const char *fragmentShaderSource_ = "#version 110\n" + "uniform lowp vec4 color;\n" + "void main() {\n" + " gl_FragColor = color;\n" + "}\n"; + + // Must be called on initialization. + bool compile(void); + + // Render a LineShaderData with a given M/V/P transformation. + void draw(const LineShaderData &data, const QColor &color, float thickness, const QMatrix4x4 &projection); +}; + +NEXTPNR_NAMESPACE_END + +#endif From 8db19778a09954e7c0b4803bdfc40509de0403fd Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 26 Jul 2018 18:48:07 +0200 Subject: [PATCH 20/21] Fix name clash for ecp5 --- ecp5/arch.h | 2 +- ecp5/bitstream.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ecp5/arch.h b/ecp5/arch.h index d9d29c76..b6aac9cf 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -752,7 +752,7 @@ struct Arch : BaseCtx return chip_info->tiletype_names[locInfo(pip)->pip_data[pip.index].tile_type].get(); } - int8_t getPipType(PipId pip) const { return locInfo(pip)->pip_data[pip.index].pip_type; } + int8_t getPipClass(PipId pip) const { return locInfo(pip)->pip_data[pip.index].pip_type; } BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index f87b7038..df9b12d5 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -174,7 +174,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex // Add all set, configurable pips to the config for (auto pip : ctx->getPips()) { if (ctx->getBoundPipNet(pip) != IdString()) { - if (ctx->getPipType(pip) == 0) { // ignore fixed pips + if (ctx->getPipClass(pip) == 0) { // ignore fixed pips std::string tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx->getPipTiletype(pip)); std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip)); From e5acd80247264fed41dfc1e7e07efa8a10a67fae Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 26 Jul 2018 19:32:21 +0200 Subject: [PATCH 21/21] Added back select on property list --- gui/designwidget.cc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 2bba8532..43964edf 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -824,6 +824,19 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos) } QMenu menu(this); + QAction *selectAction = new QAction("&Select", this); + connect(selectAction, &QAction::triggered, this, [this, items] { + std::vector decals; + for (auto clickItem : items) { + IdString value = static_cast(clickItem)->getData(); + ElementType type = static_cast(clickItem)->getType(); + std::vector d = getDecals(type, value); + std::move(d.begin(), d.end(), std::back_inserter(decals)); + } + Q_EMIT selected(decals); + }); + menu.addAction(selectAction); + QMenu *subMenu = menu.addMenu("Highlight"); QActionGroup *group = new QActionGroup(this); group->setExclusive(true); @@ -876,14 +889,8 @@ void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column) 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; - } + if (type != ElementType::NONE && nameToItem[index].contains(value)) + treeWidget->setCurrentItem(nameToItem[index].value(value)); } NEXTPNR_NAMESPACE_END