diff options
-rw-r--r-- | common/nextpnr.h | 194 | ||||
-rw-r--r-- | common/placer1.cc | 15 | ||||
-rw-r--r-- | common/router1.cc | 17 | ||||
-rw-r--r-- | gui/fpgaviewwidget.cc | 202 | ||||
-rw-r--r-- | gui/fpgaviewwidget.h | 114 | ||||
-rw-r--r-- | ice40/arch.cc | 8 | ||||
-rw-r--r-- | ice40/arch.h | 8 |
7 files changed, 397 insertions, 161 deletions
diff --git a/common/nextpnr.h b/common/nextpnr.h index 40fd3d13..1f3e1d08 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 @@ -19,7 +20,10 @@ #include <algorithm> #include <assert.h> +#include <condition_variable> #include <memory> +#include <mutex> +#include <pthread.h> #include <stdexcept> #include <stdint.h> #include <string> @@ -267,19 +271,87 @@ struct CellInfo : ArchCellInfo std::unordered_map<IdString, IdString> pins; }; -struct BaseCtx +struct DeterministicRNG { - // -------------------------------------------------------------- + uint64_t rngstate; - mutable std::unordered_map<std::string, int> *idstring_str_to_idx; - mutable std::vector<const std::string *> *idstring_idx_to_str; + DeterministicRNG() : rngstate(0x3141592653589793) {} - IdString id(const std::string &s) const { return IdString(this, s); } + uint64_t rng64() + { + // xorshift64star + // https://arxiv.org/abs/1402.6246 - IdString id(const char *s) const { return IdString(this, s); } + uint64_t retval = rngstate * 0x2545F4914F6CDD1D; - // -------------------------------------------------------------- + rngstate ^= rngstate >> 12; + rngstate ^= rngstate << 25; + rngstate ^= rngstate >> 27; + + return retval; + } + + int rng() { return rng64() & 0x3fffffff; } + + int rng(int n) + { + assert(n > 0); + + // round up to power of 2 + int m = n - 1; + m |= (m >> 1); + m |= (m >> 2); + m |= (m >> 4); + m |= (m >> 8); + m |= (m >> 16); + m += 1; + + while (1) { + int x = rng64() & (m - 1); + if (x < n) + return x; + } + } + + void rngseed(uint64_t seed) + { + rngstate = seed ? seed : 0x3141592653589793; + for (int i = 0; i < 5; i++) + rng64(); + } + + template <typename T> void shuffle(std::vector<T> &a) + { + for (size_t i = 0; i != a.size(); i++) { + size_t j = i + rng(a.size() - i); + if (j > i) + std::swap(a[i], a[j]); + } + } + template <typename T> void sorted_shuffle(std::vector<T> &a) + { + std::sort(a.begin(), a.end()); + shuffle(a); + } +}; + +struct BaseCtx +{ + // Lock to perform mutating actions on the Context. + std::mutex mutex; + pthread_t mutex_owner; + + // Lock to be taken by UI when wanting to access context - the yield() + // method will lock/unlock it when its' released the main mutex to make + // sure the UI is not starved. + std::mutex ui_mutex; + + // ID String database. + mutable std::unordered_map<std::string, int> *idstring_str_to_idx; + mutable std::vector<const std::string *> *idstring_idx_to_str; + + // Placed nets and cells. std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets; std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells; @@ -297,13 +369,57 @@ struct BaseCtx delete idstring_idx_to_str; } + // Must be called before performing any mutating changes on the Ctx/Arch. + void lock(void) + { + mutex.lock(); + mutex_owner = pthread_self(); + } + + void unlock(void) + { + NPNR_ASSERT(pthread_equal(pthread_self(), mutex_owner) != 0); + mutex.unlock(); + } + + // Must be called by the UI before rendering data. This lock will be + // prioritized when processing code calls yield(). + void lock_ui(void) + { + ui_mutex.lock(); + mutex.lock(); + } + + void unlock_ui(void) + { + mutex.unlock(); + ui_mutex.unlock(); + } + + // Yield to UI by unlocking the main mutex, flashing the UI mutex and + // relocking the main mutex. Call this when you're performing a + // long-standing action while holding a lock to let the UI show + // visualization updates. + // Must be called with the main lock taken. + void yield(void) + { + unlock(); + ui_mutex.lock(); + ui_mutex.unlock(); + lock(); + } + + IdString id(const std::string &s) const { return IdString(this, s); } + + IdString id(const char *s) const { return IdString(this, s); } + Context *getCtx() { return reinterpret_cast<Context *>(this); } const Context *getCtx() const { return reinterpret_cast<const Context *>(this); } // -------------------------------------------------------------- - bool allUiReload = false; + bool allUiReload = true; bool frameUiReload = false; std::unordered_set<BelId> belUiReload; std::unordered_set<WireId> wireUiReload; @@ -329,7 +445,7 @@ NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_BEGIN -struct Context : Arch +struct Context : Arch, DeterministicRNG { bool verbose = false; bool debug = false; @@ -346,66 +462,6 @@ struct Context : Arch // -------------------------------------------------------------- - uint64_t rngstate = 0x3141592653589793; - - uint64_t rng64() - { - // xorshift64star - // https://arxiv.org/abs/1402.6246 - - uint64_t retval = rngstate * 0x2545F4914F6CDD1D; - - rngstate ^= rngstate >> 12; - rngstate ^= rngstate << 25; - rngstate ^= rngstate >> 27; - - return retval; - } - - int rng() { return rng64() & 0x3fffffff; } - - int rng(int n) - { - assert(n > 0); - - // round up to power of 2 - int m = n - 1; - m |= (m >> 1); - m |= (m >> 2); - m |= (m >> 4); - m |= (m >> 8); - m |= (m >> 16); - m += 1; - - while (1) { - int x = rng64() & (m - 1); - if (x < n) - return x; - } - } - - void rngseed(uint64_t seed) - { - rngstate = seed ? seed : 0x3141592653589793; - for (int i = 0; i < 5; i++) - rng64(); - } - - template <typename T> void shuffle(std::vector<T> &a) - { - for (size_t i = 0; i != a.size(); i++) { - size_t j = i + rng(a.size() - i); - if (j > i) - std::swap(a[i], a[j]); - } - } - - template <typename T> void sorted_shuffle(std::vector<T> &a) - { - std::sort(a.begin(), a.end()); - shuffle(a); - } - uint32_t checksum() const; void check() const; diff --git a/common/placer1.cc b/common/placer1.cc index 74a11040..025c7c15 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -80,6 +80,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 +119,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 +140,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 +148,7 @@ class SAPlacer metrics[net.first] = wl; curr_metric += wl; } + ctx->unlock(); int n_no_progress = 0; double avg_metric = curr_metric; @@ -169,6 +175,7 @@ class SAPlacer try_swap_position(cell, try_bel); } } + // Heuristic to improve placement on the 8k if (improved) n_no_progress = 0; @@ -178,6 +185,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 +240,12 @@ class SAPlacer metrics[net.first] = wl; curr_metric += wl; } + + // Let the UI show visualization updates. + ctx->yield(); } // Final post-pacement validitiy check + ctx->lock(); for (auto bel : ctx->getBels()) { IdString cell = ctx->getBoundBelCell(bel); if (!ctx->isBelLocationValid(bel)) { @@ -251,6 +263,7 @@ class SAPlacer } } } + ctx->unlock(); return true; } @@ -436,7 +449,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 1ea50448..a171374f 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -695,6 +695,7 @@ bool router1(Context *ctx) log_break(); log_info("Routing..\n"); + ctx->lock(); std::unordered_map<IdString, std::vector<bool>> jobCache; std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> jobQueue; @@ -766,15 +767,19 @@ bool router1(Context *ctx) normalRouteNets.insert(net_name); } - if ((ctx->verbose || iterCnt == 1) && !printNets && (jobCnt % 100 == 0)) + if ((ctx->verbose || iterCnt == 1) && !printNets && (jobCnt % 100 == 0)) { log_info(" processed %d jobs. (%d routed, %d failed)\n", jobCnt, jobCnt - failedCnt, failedCnt); + ctx->yield(); + } } NPNR_ASSERT(jobQueue.empty()); jobCache.clear(); - if ((ctx->verbose || iterCnt == 1) && (jobCnt % 100 != 0)) + if ((ctx->verbose || iterCnt == 1) && (jobCnt % 100 != 0)) { log_info(" processed %d jobs. (%d routed, %d failed)\n", jobCnt, jobCnt - failedCnt, failedCnt); + ctx->yield(); + } if (ctx->verbose) log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime " @@ -828,8 +833,10 @@ bool router1(Context *ctx) ripCnt += router.rippedNets.size(); - if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) + if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) { log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); + ctx->yield(); + } } if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) @@ -857,6 +864,8 @@ bool router1(Context *ctx) if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || iterCnt == 128) ripup_penalty += ctx->getRipupDelayPenalty(); + + ctx->yield(); } log_info("routing complete after %d iterations.\n", iterCnt); @@ -888,11 +897,13 @@ bool router1(Context *ctx) log_info("Checksum: 0x%08x\n", ctx->checksum()); #ifndef NDEBUG ctx->check(); + ctx->unlock(); #endif return true; } catch (log_execution_error_exception) { #ifndef NDEBUG ctx->check(); + ctx->unlock(); #endif return false; } diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index c926e5fa..86aae25d 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -241,26 +241,26 @@ 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 +268,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 +275,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 +289,7 @@ FPGAViewWidget::~FPGAViewWidget() {} void FPGAViewWidget::newContext(Context *ctx) { ctx_ = ctx; - selectedItems_.clear(); - update(); + pokeRenderer(); } QSize FPGAViewWidget::minimumSizeHint() const { return QSize(640, 480); } @@ -297,7 +302,8 @@ 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 +404,143 @@ 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_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. + 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_ui(); - 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..0d0ef89c 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 <QThread> +#include <QTimer> +#include <QWaitCondition> #include "nextpnr.h" @@ -206,17 +210,58 @@ 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 +291,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 +310,40 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions const float zoomLvl2_ = 50.0f; Context *ctx_; + QTimer paintTimer_; + + std::unique_ptr<PeriodicRunner> renderRunner_; - 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]; + 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 e9a7d2b6..7c183f6c 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -19,13 +19,13 @@ #include <algorithm> #include <cmath> +#include "cells.h" #include "gfx.h" #include "log.h" #include "nextpnr.h" #include "placer1.h" #include "router1.h" #include "util.h" -#include "cells.h" NEXTPNR_NAMESPACE_BEGIN // ----------------------------------------------------------------------- @@ -525,9 +525,9 @@ DecalXY Arch::getWireDecal(WireId wire) const DecalXY Arch::getPipDecal(PipId pip) const { DecalXY decalxy; - // decalxy.decal.type = DecalId::TYPE_PIP; - // decalxy.decal.index = pip.index; - // decalxy.decal.active = pip_to_net.at(pip.index) != IdString(); + decalxy.decal.type = DecalId::TYPE_PIP; + decalxy.decal.index = pip.index; + decalxy.decal.active = pip_to_net.at(pip.index) != IdString(); return decalxy; }; diff --git a/ice40/arch.h b/ice40/arch.h index 21169298..b7e66414 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -390,6 +390,7 @@ struct Arch : BaseCtx bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; + refreshUiBel(bel); } void unbindBel(BelId bel) @@ -399,6 +400,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 @@ -509,6 +511,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) @@ -528,6 +531,7 @@ struct Arch : BaseCtx net_wires.erase(it); wire_to_net[wire.index] = IdString(); + refreshUiWire(wire); } bool checkWireAvail(WireId wire) const @@ -581,6 +585,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) @@ -597,6 +603,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 |