aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/nextpnr.cc8
-rw-r--r--common/nextpnr.h169
-rw-r--r--common/placer1.cc23
-rw-r--r--common/router1.cc9
-rw-r--r--ecp5/arch.cc2
-rw-r--r--generic/arch.cc2
-rw-r--r--gui/application.cc20
-rw-r--r--gui/fpgaviewwidget.cc203
-rw-r--r--gui/fpgaviewwidget.h118
-rw-r--r--ice40/arch.cc2
-rw-r--r--ice40/arch.h8
11 files changed, 394 insertions, 170 deletions
diff --git a/common/nextpnr.cc b/common/nextpnr.cc
index 3861e5fe..c60d0e86 100644
--- a/common/nextpnr.cc
+++ b/common/nextpnr.cc
@@ -27,7 +27,7 @@ assertion_failure::assertion_failure(std::string msg, std::string expr_str, std:
{
}
-void IdString::set(const BaseCtx *ctx, const std::string &s)
+void IdString::set(const IdStringDB *ctx, const std::string &s)
{
auto it = ctx->idstring_str_to_idx->find(s);
if (it == ctx->idstring_str_to_idx->end()) {
@@ -39,11 +39,11 @@ void IdString::set(const BaseCtx *ctx, const std::string &s)
}
}
-const std::string &IdString::str(const BaseCtx *ctx) const { return *ctx->idstring_idx_to_str->at(index); }
+const std::string &IdString::str(const IdStringDB *ctx) const { return *ctx->idstring_idx_to_str->at(index); }
-const char *IdString::c_str(const BaseCtx *ctx) const { return str(ctx).c_str(); }
+const char *IdString::c_str(const IdStringDB *ctx) const { return str(ctx).c_str(); }
-void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx)
+void IdString::initialize_add(const IdStringDB *ctx, const char *s, int idx)
{
NPNR_ASSERT(ctx->idstring_str_to_idx->count(s) == 0);
NPNR_ASSERT(int(ctx->idstring_idx_to_str->size()) == idx);
diff --git a/common/nextpnr.h b/common/nextpnr.h
index bc64adb5..2a416a05 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
+ * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,6 +21,8 @@
#include <algorithm>
#include <assert.h>
#include <memory>
+#include <mutex>
+#include <pthread.h>
#include <stdexcept>
#include <stdint.h>
#include <string>
@@ -89,28 +92,28 @@ inline bool assert_fail_impl_str(std::string message, const char *expr_str, cons
#define NPNR_ASSERT_FALSE(msg) (assert_fail_impl(msg, "false", __FILE__, __LINE__))
#define NPNR_ASSERT_FALSE_STR(msg) (assert_fail_impl_str(msg, "false", __FILE__, __LINE__))
-struct BaseCtx;
+struct IdStringDB;
struct Context;
struct IdString
{
int index = 0;
- static void initialize_arch(const BaseCtx *ctx);
+ static void initialize_arch(const IdStringDB *ctx);
- static void initialize_add(const BaseCtx *ctx, const char *s, int idx);
+ static void initialize_add(const IdStringDB *ctx, const char *s, int idx);
IdString() {}
- void set(const BaseCtx *ctx, const std::string &s);
+ void set(const IdStringDB *ctx, const std::string &s);
- IdString(const BaseCtx *ctx, const std::string &s) { set(ctx, s); }
+ IdString(const IdStringDB *ctx, const std::string &s) { set(ctx, s); }
- IdString(const BaseCtx *ctx, const char *s) { set(ctx, s); }
+ IdString(const IdStringDB *ctx, const char *s) { set(ctx, s); }
- const std::string &str(const BaseCtx *ctx) const;
+ const std::string &str(const IdStringDB *ctx) const;
- const char *c_str(const BaseCtx *ctx) const;
+ const char *c_str(const IdStringDB *ctx) const;
bool operator<(const IdString &other) const { return index < other.index; }
@@ -243,23 +246,18 @@ struct CellInfo : ArchCellInfo
std::unordered_map<IdString, IdString> pins;
};
-struct BaseCtx
+class IdStringDB
{
- // --------------------------------------------------------------
-
+ friend class IdString;
+ private:
mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
mutable std::vector<const std::string *> *idstring_idx_to_str;
-
+
+ public:
IdString id(const std::string &s) const { return IdString(this, s); }
-
IdString id(const char *s) const { return IdString(this, s); }
- // --------------------------------------------------------------
-
- std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets;
- std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells;
-
- BaseCtx()
+ IdStringDB()
{
idstring_str_to_idx = new std::unordered_map<std::string, int>;
idstring_idx_to_str = new std::vector<const std::string *>;
@@ -267,62 +265,22 @@ struct BaseCtx
IdString::initialize_arch(this);
}
- ~BaseCtx()
+ ~IdStringDB()
{
delete idstring_str_to_idx;
delete idstring_idx_to_str;
}
-
- Context *getCtx() { return reinterpret_cast<Context *>(this); }
-
- const Context *getCtx() const { return reinterpret_cast<const Context *>(this); }
-
- // --------------------------------------------------------------
-
- bool allUiReload = false;
- bool frameUiReload = false;
- std::unordered_set<BelId> belUiReload;
- std::unordered_set<WireId> wireUiReload;
- std::unordered_set<PipId> pipUiReload;
- std::unordered_set<GroupId> groupUiReload;
-
- void refreshUi() { allUiReload = true; }
-
- void refreshUiFrame() { frameUiReload = true; }
-
- void refreshUiBel(BelId bel) { belUiReload.insert(bel); }
-
- void refreshUiWire(WireId wire) { wireUiReload.insert(wire); }
-
- void refreshUiPip(PipId pip) { pipUiReload.insert(pip); }
-
- void refreshUiGroup(GroupId group) { groupUiReload.insert(group); }
};
-NEXTPNR_NAMESPACE_END
-
-#include "arch.h"
-
-NEXTPNR_NAMESPACE_BEGIN
-
-struct Context : Arch
+class DeterministicRNG
{
- bool verbose = false;
- bool debug = false;
- bool force = false;
- bool timing_driven = true;
- float target_freq = 12e6;
+ private:
+ uint64_t rngstate;
- Context(ArchArgs args) : Arch(args) {}
-
- // --------------------------------------------------------------
-
- // provided by router1.cc
- bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay);
-
- // --------------------------------------------------------------
-
- uint64_t rngstate = 0x3141592653589793;
+ public:
+ DeterministicRNG() : rngstate(0x3141592653589793)
+ {
+ }
uint64_t rng64()
{
@@ -382,6 +340,83 @@ struct Context : Arch
shuffle(a);
}
+};
+
+class BaseCtx : public IdStringDB, public DeterministicRNG
+{
+ private:
+ std::mutex mutex;
+ bool mutex_owned;
+ pthread_t mutex_owner;
+
+ public:
+ std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets;
+ std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells;
+
+ BaseCtx() {}
+ ~BaseCtx() {}
+
+ void lock(void)
+ {
+ mutex.lock();
+ mutex_owner = pthread_self();
+ }
+
+ void unlock(void)
+ {
+ NPNR_ASSERT(pthread_equal(pthread_self(), mutex_owner) != 0);
+ mutex.unlock();
+ }
+
+ Context *getCtx() { return reinterpret_cast<Context *>(this); }
+
+ const Context *getCtx() const { return reinterpret_cast<const Context *>(this); }
+
+ // --------------------------------------------------------------
+
+ bool allUiReload = true;
+ bool frameUiReload = false;
+ std::unordered_set<BelId> belUiReload;
+ std::unordered_set<WireId> wireUiReload;
+ std::unordered_set<PipId> pipUiReload;
+ std::unordered_set<GroupId> groupUiReload;
+
+ void refreshUi() { allUiReload = true; }
+
+ void refreshUiFrame() { frameUiReload = true; }
+
+ void refreshUiBel(BelId bel) { belUiReload.insert(bel); }
+
+ void refreshUiWire(WireId wire) { wireUiReload.insert(wire); }
+
+ void refreshUiPip(PipId pip) { pipUiReload.insert(pip); }
+
+ void refreshUiGroup(GroupId group) { groupUiReload.insert(group); }
+};
+
+NEXTPNR_NAMESPACE_END
+
+#include "arch.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+struct Context : Arch
+{
+ bool verbose = false;
+ bool debug = false;
+ bool force = false;
+ bool timing_driven = true;
+ float target_freq = 12e6;
+
+ Context(ArchArgs args) : Arch(args) {}
+
+ // --------------------------------------------------------------
+
+ // provided by router1.cc
+ bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay);
+
+ // --------------------------------------------------------------
+
uint32_t checksum() const;
void check() const;
diff --git a/common/placer1.cc b/common/placer1.cc
index 74a11040..b58893ce 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -29,6 +29,7 @@
#include <list>
#include <map>
#include <ostream>
+#include <pthread.h>
#include <queue>
#include <set>
#include <stdarg.h>
@@ -80,6 +81,7 @@ class SAPlacer
size_t placed_cells = 0;
// Initial constraints placer
+ ctx->lock();
for (auto &cell_entry : ctx->cells) {
CellInfo *cell = cell_entry.second.get();
auto loc = cell->attrs.find(ctx->id("BEL"));
@@ -118,16 +120,19 @@ class SAPlacer
}
std::sort(autoplaced.begin(), autoplaced.end(), [](CellInfo *a, CellInfo *b) { return a->name < b->name; });
ctx->shuffle(autoplaced);
+ ctx->unlock();
// Place cells randomly initially
log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size()));
for (auto cell : autoplaced) {
+ ctx->lock();
place_initial(cell);
placed_cells++;
if ((placed_cells - constr_placed_cells) % 500 == 0)
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
int(autoplaced.size()));
+ ctx->unlock();
}
if ((placed_cells - constr_placed_cells) % 500 != 0)
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
@@ -136,6 +141,7 @@ class SAPlacer
log_info("Running simulated annealing placer.\n");
// Calculate metric after initial placement
+ ctx->lock();
curr_metric = 0;
curr_tns = 0;
for (auto &net : ctx->nets) {
@@ -143,6 +149,7 @@ class SAPlacer
metrics[net.first] = wl;
curr_metric += wl;
}
+ ctx->unlock();
int n_no_progress = 0;
double avg_metric = curr_metric;
@@ -150,6 +157,15 @@ class SAPlacer
// Main simulated annealing loop
for (int iter = 1;; iter++) {
+ // TODO(q3k): unwat
+ pthread_yield();
+ pthread_yield();
+ pthread_yield();
+ pthread_yield();
+ pthread_yield();
+ pthread_yield();
+ pthread_yield();
+ ctx->lock();
n_move = n_accept = 0;
improved = false;
@@ -169,6 +185,7 @@ class SAPlacer
try_swap_position(cell, try_bel);
}
}
+
// Heuristic to improve placement on the 8k
if (improved)
n_no_progress = 0;
@@ -178,6 +195,7 @@ class SAPlacer
if (temp <= 1e-3 && n_no_progress >= 5) {
if (iter % 5 != 0)
log_info(" at iteration #%d: temp = %f, cost = %f\n", iter, temp, double(curr_metric));
+ ctx->unlock();
break;
}
@@ -232,8 +250,10 @@ class SAPlacer
metrics[net.first] = wl;
curr_metric += wl;
}
+ ctx->unlock();
}
// Final post-pacement validitiy check
+ ctx->lock();
for (auto bel : ctx->getBels()) {
IdString cell = ctx->getBoundBelCell(bel);
if (!ctx->isBelLocationValid(bel)) {
@@ -251,6 +271,7 @@ class SAPlacer
}
}
}
+ ctx->unlock();
return true;
}
@@ -436,7 +457,9 @@ bool placer1(Context *ctx)
placer.place();
log_info("Checksum: 0x%08x\n", ctx->checksum());
#ifndef NDEBUG
+ ctx->lock();
ctx->check();
+ ctx->unlock();
#endif
return true;
} catch (log_execution_error_exception) {
diff --git a/common/router1.cc b/common/router1.cc
index 94c7070e..bde3be31 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -414,6 +414,7 @@ bool router1(Context *ctx)
std::unordered_set<IdString> netsQueue;
+ ctx->lock();
for (auto &net_it : ctx->nets) {
auto net_name = net_it.first;
auto net_info = net_it.second.get();
@@ -478,6 +479,7 @@ bool router1(Context *ctx)
estimatedTotalDelayCnt++;
}
}
+ ctx->unlock();
log_info("estimated total wire delay: %.2f (avg %.2f)\n", float(estimatedTotalDelay),
float(estimatedTotalDelay) / estimatedTotalDelayCnt);
@@ -493,6 +495,7 @@ bool router1(Context *ctx)
#endif
return false;
}
+ ctx->lock();
iterCnt++;
if (ctx->verbose)
@@ -621,6 +624,8 @@ bool router1(Context *ctx)
if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || iterCnt == 128)
ripup_penalty += ctx->getRipupDelayPenalty();
+
+ ctx->unlock();
}
log_info("routing complete after %d iterations.\n", iterCnt);
@@ -632,12 +637,16 @@ bool router1(Context *ctx)
log_info("Checksum: 0x%08x\n", ctx->checksum());
#ifndef NDEBUG
+ ctx->lock();
ctx->check();
+ ctx->unlock();
#endif
return true;
} catch (log_execution_error_exception) {
#ifndef NDEBUG
+ ctx->lock();
ctx->check();
+ ctx->unlock();
#endif
return false;
}
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 1510a27f..fb37aa84 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -62,7 +62,7 @@ BelType Arch::belTypeFromId(IdString type) const
// -----------------------------------------------------------------------
-void IdString::initialize_arch(const BaseCtx *ctx)
+void IdString::initialize_arch(const IdStringDB *ctx)
{
#define X(t) initialize_add(ctx, #t, PIN_##t);
diff --git a/generic/arch.cc b/generic/arch.cc
index 390830aa..edc2ef26 100644
--- a/generic/arch.cc
+++ b/generic/arch.cc
@@ -157,7 +157,7 @@ void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
Arch::Arch(ArchArgs) {}
-void IdString::initialize_arch(const BaseCtx *ctx) {}
+void IdString::initialize_arch(const IdStringDB *ctx) {}
// ---------------------------------------------------------------
diff --git a/gui/application.cc b/gui/application.cc
index 58dc23eb..12453b57 100644
--- a/gui/application.cc
+++ b/gui/application.cc
@@ -37,17 +37,17 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
bool Application::notify(QObject *receiver, QEvent *event)
{
bool retVal = true;
- try {
+ //try {
retVal = QApplication::notify(receiver, event);
- } catch (assertion_failure ex) {
- QString msg;
- QTextStream out(&msg);
- out << ex.filename.c_str() << " at " << ex.line << "\n";
- out << ex.msg.c_str();
- QMessageBox::critical(0, "Error", msg);
- } catch (...) {
- QMessageBox::critical(0, "Error", "Fatal error !!!");
- }
+ //} catch (assertion_failure ex) {
+ // QString msg;
+ // QTextStream out(&msg);
+ // out << ex.filename.c_str() << " at " << ex.line << "\n";
+ // out << ex.msg.c_str();
+ // QMessageBox::critical(0, "Error", msg);
+ //} catch (...) {
+ // QMessageBox::critical(0, "Error", "Fatal error !!!");
+ //}
return retVal;
}
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index c926e5fa..9a03b2a5 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -241,26 +241,25 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi
}
FPGAViewWidget::FPGAViewWidget(QWidget *parent)
- : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged_(false)
+ : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), paintTimer_(this), rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs)
{
- backgroundColor_ = QColor("#000000");
- gridColor_ = QColor("#333");
- gFrameColor_ = QColor("#d0d0d0");
- gHiddenColor_ = QColor("#606060");
- gInactiveColor_ = QColor("#303030");
- gActiveColor_ = QColor("#f0f0f0");
- gSelectedColor_ = QColor("#ff6600");
- frameColor_ = QColor("#0066ba");
- highlightColors[0] = QColor("#6495ed");
- highlightColors[1] = QColor("#7fffd4");
- highlightColors[2] = QColor("#98fb98");
- highlightColors[3] = QColor("#ffd700");
- highlightColors[4] = QColor("#cd5c5c");
- highlightColors[5] = QColor("#fa8072");
- highlightColors[6] = QColor("#ff69b4");
- highlightColors[7] = QColor("#da70d6");
- for (int i = 0; i < 8; i++)
- highlightItemsChanged_[i] = false;
+ colors_.background = QColor("#000000");
+ colors_.grid = QColor("#333");
+ colors_.frame = QColor("#d0d0d0");
+ colors_.hidden = QColor("#606060");
+ colors_.inactive = QColor("#303030");
+ colors_.active = QColor("#f0f0f0");
+ colors_.selected = QColor("#ff6600");
+ colors_.highlight[0] = QColor("#6495ed");
+ colors_.highlight[1] = QColor("#7fffd4");
+ colors_.highlight[2] = QColor("#98fb98");
+ colors_.highlight[3] = QColor("#ffd700");
+ colors_.highlight[4] = QColor("#cd5c5c");
+ colors_.highlight[5] = QColor("#fa8072");
+ colors_.highlight[6] = QColor("#ff69b4");
+ colors_.highlight[7] = QColor("#da70d6");
+
+ rendererArgs_->highlightedOrSelectedChanged = false;
auto fmt = format();
fmt.setMajorVersion(3);
@@ -268,7 +267,6 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent)
setFormat(fmt);
fmt = format();
- // printf("FPGAViewWidget running on OpenGL %d.%d\n", fmt.majorVersion(), fmt.minorVersion());
if (fmt.majorVersion() < 3) {
printf("Could not get OpenGL 3.0 context. Aborting.\n");
log_abort();
@@ -276,6 +274,13 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent)
if (fmt.minorVersion() < 1) {
printf("Could not get OpenGL 3.1 context - trying anyway...\n ");
}
+
+ connect(&paintTimer_, SIGNAL(timeout()), this, SLOT(update()));
+ paintTimer_.start(std::chrono::duration<int, std::milli>(1000/20)); // paint GL 20 times per second
+
+ renderRunner_ = std::unique_ptr<PeriodicRunner>(new PeriodicRunner(this, [this] { renderLines(); }));
+ renderRunner_->start();
+ renderRunner_->startTimer(std::chrono::duration<int, std::milli>(1000/2)); // render line 2 times per second
}
FPGAViewWidget::~FPGAViewWidget() {}
@@ -283,8 +288,7 @@ FPGAViewWidget::~FPGAViewWidget() {}
void FPGAViewWidget::newContext(Context *ctx)
{
ctx_ = ctx;
- selectedItems_.clear();
- update();
+ pokeRenderer();
}
QSize FPGAViewWidget::minimumSizeHint() const { return QSize(640, 480); }
@@ -297,7 +301,7 @@ void FPGAViewWidget::initializeGL()
log_error("Could not compile shader.\n");
}
initializeOpenGLFunctions();
- glClearColor(backgroundColor_.red() / 255, backgroundColor_.green() / 255, backgroundColor_.blue() / 255, 0.0);
+ glClearColor(colors_.background.red() / 255, colors_.background.green() / 255, colors_.background.blue() / 255, 0.0);
}
void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal)
@@ -398,67 +402,146 @@ void FPGAViewWidget::paintGL()
PolyLine(-100.0f, i, 100.0f, i).build(grid);
PolyLine(i, -100.0f, i, 100.0f).build(grid);
}
- lineShader_.draw(grid, gridColor_, thick1Px, matrix);
+ lineShader_.draw(grid, colors_.grid, thick1Px, matrix);
- LineShaderData shaders[4] = {LineShaderData(), LineShaderData(), LineShaderData(), LineShaderData()};
+ 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);
- if (ctx_) {
- // Draw Bels.
+ for (int i = 0; i < 8; i++)
+ lineShader_.draw(rendererData_->highlighted[i], colors_.highlight[i], thick11Px, matrix);
+
+ lineShader_.draw(rendererData_->selected, colors_.selected, thick11Px, matrix);
+ rendererDataLock_.unlock();
+}
+
+void FPGAViewWidget::pokeRenderer(void) {
+ renderRunner_->poke();
+}
+
+void FPGAViewWidget::renderLines(void)
+{
+ if (ctx_ == nullptr)
+ return;
+
+ ctx_->lock();
+
+ // 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.
+ std::vector<DecalXY> belDecals;
+ std::vector<DecalXY> wireDecals;
+ std::vector<DecalXY> pipDecals;
+ std::vector<DecalXY> groupDecals;
+ if (decalsChanged) {
for (auto bel : ctx_->getBels()) {
- drawDecal(shaders, ctx_->getBelDecal(bel));
+ belDecals.push_back(ctx_->getBelDecal(bel));
}
- // Draw Wires.
for (auto wire : ctx_->getWires()) {
- drawDecal(shaders, ctx_->getWireDecal(wire));
+ wireDecals.push_back(ctx_->getWireDecal(wire));
}
- // Draw Pips.
for (auto pip : ctx_->getPips()) {
- drawDecal(shaders, ctx_->getPipDecal(pip));
+ pipDecals.push_back(ctx_->getPipDecal(pip));
}
- // Draw Groups.
for (auto group : ctx_->getGroups()) {
- drawDecal(shaders, ctx_->getGroupDecal(group));
+ groupDecals.push_back(ctx_->getGroupDecal(group));
}
+ }
+ ctx_->unlock();
- if (selectedItemsChanged_) {
- selectedItemsChanged_ = false;
- selectedShader_.clear();
- for (auto decal : selectedItems_) {
- drawDecal(selectedShader_, decal);
- }
+ rendererArgsLock_.lock();
+ auto selectedItems = rendererArgs_->selectedItems;
+ auto highlightedItems = rendererArgs_->highlightedItems;
+ auto highlightedOrSelectedChanged = rendererArgs_->highlightedOrSelectedChanged;
+ rendererArgs_->highlightedOrSelectedChanged = false;
+ rendererArgsLock_.unlock();
+
+ if (decalsChanged) {
+ auto data = std::unique_ptr<FPGAViewWidget::RendererData>(new FPGAViewWidget::RendererData);
+ // Draw Bels.
+ for (auto const &decal : belDecals) {
+ drawDecal(data->decals, decal);
+ }
+ // Draw Wires.
+ for (auto const &decal : wireDecals) {
+ drawDecal(data->decals, decal);
+ }
+ // Draw Pips.
+ for (auto const &decal : pipDecals) {
+ drawDecal(data->decals, decal);
+ }
+ // Draw Groups.
+ for (auto const &decal : groupDecals) {
+ drawDecal(data->decals, decal);
+ }
+
+ // Swap over.
+ rendererDataLock_.lock();
+ rendererData_ = std::move(data);
+ rendererDataLock_.unlock();
+ }
+
+ rendererDataLock_.lock();
+ if (decalsChanged || highlightedOrSelectedChanged) {
+ rendererData_->selected.clear();
+ for (auto &decal : selectedItems) {
+ drawDecal(rendererData_->selected, decal);
}
for (int i = 0; i < 8; i++) {
- if (highlightItemsChanged_[i]) {
- highlightItemsChanged_[i] = false;
- highlightShader_[i].clear();
- for (auto decal : highlightItems_[i]) {
- drawDecal(highlightShader_[i], decal);
- }
+ rendererData_->highlighted[i].clear();
+ for (auto &decal : highlightedItems[i]) {
+ drawDecal(rendererData_->highlighted[i], decal);
}
}
}
-
- lineShader_.draw(shaders[0], gFrameColor_, thick11Px, matrix);
- lineShader_.draw(shaders[1], gHiddenColor_, thick11Px, matrix);
- lineShader_.draw(shaders[2], gInactiveColor_, thick11Px, matrix);
- lineShader_.draw(shaders[3], gActiveColor_, thick11Px, matrix);
- for (int i = 0; i < 8; i++)
- lineShader_.draw(highlightShader_[i], highlightColors[i], thick11Px, matrix);
- lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix);
+ rendererDataLock_.unlock();
}
+
void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals)
{
- selectedItems_ = decals;
- selectedItemsChanged_ = true;
- update();
+ rendererArgsLock_.lock();
+ rendererArgs_->selectedItems = decals;
+ rendererArgs_->highlightedOrSelectedChanged = true;
+ rendererArgsLock_.unlock();
+ pokeRenderer();
}
void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int group)
{
- highlightItems_[group] = decals;
- highlightItemsChanged_[group] = true;
- update();
+ rendererArgsLock_.lock();
+ rendererArgs_->highlightedItems[group] = decals;
+ rendererArgs_->highlightedOrSelectedChanged = true;
+ rendererArgsLock_.unlock();
+ pokeRenderer();
}
void FPGAViewWidget::resizeGL(int width, int height) {}
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h
index 33eb2800..f846abca 100644
--- a/gui/fpgaviewwidget.h
+++ b/gui/fpgaviewwidget.h
@@ -21,12 +21,16 @@
#define MAPGLWIDGET_H
#include <QMainWindow>
+#include <QMutex>
#include <QOpenGLBuffer>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLWidget>
#include <QPainter>
+#include <QTimer>
+#include <QThread>
+#include <QWaitCondition>
#include "nextpnr.h"
@@ -206,17 +210,63 @@ class LineShader
void draw(const LineShaderData &data, const QColor &color, float thickness, const QMatrix4x4 &projection);
};
+class PeriodicRunner : public QThread
+{
+ Q_OBJECT
+private:
+ QMutex mutex_;
+ QWaitCondition condition_;
+ bool abort_;
+ std::function<void()> target_;
+ QTimer timer_;
+public:
+ explicit PeriodicRunner(QObject *parent, std::function<void()> target) :
+ QThread(parent), abort_(false), target_(target), timer_(this)
+ {
+ connect(&timer_, &QTimer::timeout, this, &PeriodicRunner::poke);
+ }
+
+ void run(void) override
+ {
+ for (;;) {
+ mutex_.lock();
+ condition_.wait(&mutex_);
+
+ if (abort_) {
+ mutex_.unlock();
+ return;
+ }
+
+ target_();
+
+ mutex_.unlock();
+ }
+ }
+
+ void startTimer(std::chrono::milliseconds value)
+ {
+ timer_.start(value);
+ }
+
+ ~PeriodicRunner()
+ {
+ mutex_.lock();
+ abort_ = true;
+ condition_.wakeOne();
+ mutex_.unlock();
+
+ wait();
+ }
+
+ void poke(void)
+ {
+ condition_.wakeOne();
+ }
+};
+
class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
- Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor_ DESIGNABLE true)
- Q_PROPERTY(QColor gridColor MEMBER gridColor_ DESIGNABLE true)
- Q_PROPERTY(QColor gFrameColor MEMBER gFrameColor_ DESIGNABLE true)
- Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor_ DESIGNABLE true)
- Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor_ DESIGNABLE true)
- Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor_ DESIGNABLE true)
- Q_PROPERTY(QColor gSelectedColor MEMBER gSelectedColor_ DESIGNABLE true)
- Q_PROPERTY(QColor frameColor MEMBER frameColor_ DESIGNABLE true)
public:
FPGAViewWidget(QWidget *parent = 0);
@@ -246,8 +296,11 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
void newContext(Context *ctx);
void onSelectedArchItem(std::vector<DecalXY> decals);
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
+ void pokeRenderer(void);
private:
+ void renderLines(void);
+
QPoint lastPos_;
LineShader lineShader_;
QMatrix4x4 viewMove_;
@@ -262,24 +315,37 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
const float zoomLvl2_ = 50.0f;
Context *ctx_;
-
- QColor backgroundColor_;
- QColor gridColor_;
- QColor gFrameColor_;
- QColor gHiddenColor_;
- QColor gInactiveColor_;
- QColor gActiveColor_;
- QColor gSelectedColor_;
- QColor frameColor_;
-
- LineShaderData selectedShader_;
- std::vector<DecalXY> selectedItems_;
- bool selectedItemsChanged_;
-
- LineShaderData highlightShader_[8];
- std::vector<DecalXY> highlightItems_[8];
- bool highlightItemsChanged_[8];
- QColor highlightColors[8];
+ QTimer paintTimer_;
+
+ std::unique_ptr<PeriodicRunner> renderRunner_;
+
+ struct {
+ QColor background;
+ QColor grid;
+ QColor frame;
+ QColor hidden;
+ QColor inactive;
+ QColor active;
+ QColor selected;
+ QColor highlight[8];
+ } colors_;
+
+ struct RendererData {
+ LineShaderData decals[4];
+ LineShaderData selected;
+ LineShaderData highlighted[8];
+ };
+
+ struct RendererArgs {
+ std::vector<DecalXY> selectedItems;
+ std::vector<DecalXY> highlightedItems[8];
+ bool highlightedOrSelectedChanged;
+ };
+
+ std::unique_ptr<RendererData> rendererData_;
+ QMutex rendererDataLock_;
+ std::unique_ptr<RendererArgs> rendererArgs_;
+ QMutex rendererArgsLock_;
};
NEXTPNR_NAMESPACE_END
diff --git a/ice40/arch.cc b/ice40/arch.cc
index 786d8ba1..d1400a63 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -102,7 +102,7 @@ BelType Arch::belTypeFromId(IdString type) const
// -----------------------------------------------------------------------
-void IdString::initialize_arch(const BaseCtx *ctx)
+void IdString::initialize_arch(const IdStringDB *ctx)
{
#define X(t) initialize_add(ctx, #t, PIN_##t);
#include "portpins.inc"
diff --git a/ice40/arch.h b/ice40/arch.h
index 3b6d23dc..f00d7f8a 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -389,6 +389,7 @@ struct Arch : BaseCtx
bel_to_cell[bel.index] = cell;
cells[cell]->bel = bel;
cells[cell]->belStrength = strength;
+ refreshUiBel(bel);
}
void unbindBel(BelId bel)
@@ -398,6 +399,7 @@ struct Arch : BaseCtx
cells[bel_to_cell[bel.index]]->bel = BelId();
cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
bel_to_cell[bel.index] = IdString();
+ refreshUiBel(bel);
}
bool checkBelAvail(BelId bel) const
@@ -491,6 +493,7 @@ struct Arch : BaseCtx
wire_to_net[wire.index] = net;
nets[net]->wires[wire].pip = PipId();
nets[net]->wires[wire].strength = strength;
+ refreshUiWire(wire);
}
void unbindWire(WireId wire)
@@ -510,6 +513,7 @@ struct Arch : BaseCtx
net_wires.erase(it);
wire_to_net[wire.index] = IdString();
+ refreshUiWire(wire);
}
bool checkWireAvail(WireId wire) const
@@ -557,6 +561,8 @@ struct Arch : BaseCtx
wire_to_net[dst.index] = net;
nets[net]->wires[dst].pip = pip;
nets[net]->wires[dst].strength = strength;
+ refreshUiPip(pip);
+ refreshUiWire(dst);
}
void unbindPip(PipId pip)
@@ -573,6 +579,8 @@ struct Arch : BaseCtx
pip_to_net[pip.index] = IdString();
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
+ refreshUiPip(pip);
+ refreshUiWire(dst);
}
bool checkPipAvail(PipId pip) const