From 59a790cd00421d14120927fbb1718da8cd77e3c4 Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Sat, 14 Jul 2018 20:24:20 +0100 Subject: Refactor IdString functionality into IdStringDB This lets us more precisely control the lifetime of IdString databases in contexts/arches. --- common/nextpnr.cc | 8 ++++---- common/nextpnr.h | 46 ++++++++++++++++++++++++++-------------------- ecp5/arch.cc | 2 +- generic/arch.cc | 2 +- ice40/arch.cc | 2 +- 5 files changed, 33 insertions(+), 27 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 50465869..87c50fe3 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * 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 @@ -88,28 +89,28 @@ inline void assert_false_impl(std::string message, std::string filename, int lin #define NPNR_ASSERT_MSG(cond, msg) except_assert_impl((cond), msg, #cond, __FILE__, __LINE__) #define NPNR_ASSERT_FALSE(msg) assert_false_impl(msg, __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; } @@ -238,23 +239,18 @@ struct CellInfo std::unordered_map pins; }; -struct BaseCtx +class IdStringDB { - // -------------------------------------------------------------- - + friend class IdString; + private: mutable std::unordered_map *idstring_str_to_idx; mutable std::vector *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> nets; - std::unordered_map> cells; - - BaseCtx() + IdStringDB() { idstring_str_to_idx = new std::unordered_map; idstring_idx_to_str = new std::vector; @@ -262,11 +258,21 @@ struct BaseCtx IdString::initialize_arch(this); } - ~BaseCtx() + ~IdStringDB() { delete idstring_str_to_idx; delete idstring_idx_to_str; } +}; + +class BaseCtx : public IdStringDB +{ + public: + std::unordered_map> nets; + std::unordered_map> cells; + + BaseCtx() {} + ~BaseCtx() {} Context *getCtx() { return reinterpret_cast(this); } diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 51f4db84..3950f4ba 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/ice40/arch.cc b/ice40/arch.cc index adc37dbd..c9cda40d 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" -- cgit v1.2.3 From 91db413c60c965b6b7cc095f53c8d03a1658566e Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Sat, 14 Jul 2018 20:33:32 +0100 Subject: Refactor RNG out to separate DeterministicRNG class This well also allow for better lifecycle control over the state of the RNG in the future. --- common/nextpnr.h | 124 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 87c50fe3..e53e4d01 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -265,65 +265,15 @@ class IdStringDB } }; -class BaseCtx : public IdStringDB +class DeterministicRNG { - public: - std::unordered_map> nets; - std::unordered_map> cells; - - BaseCtx() {} - ~BaseCtx() {} - - Context *getCtx() { return reinterpret_cast(this); } - - const Context *getCtx() const { return reinterpret_cast(this); } - - // -------------------------------------------------------------- - - bool allUiReload = false; - bool frameUiReload = false; - std::unordered_set belUiReload; - std::unordered_set wireUiReload; - std::unordered_set pipUiReload; - std::unordered_set 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); - - // -------------------------------------------------------------- + private: + uint64_t rngstate; - uint64_t rngstate = 0x3141592653589793; + public: + DeterministicRNG() : rngstate(0x3141592653589793) + { + } uint64_t rng64() { @@ -383,6 +333,66 @@ struct Context : Arch shuffle(a); } +}; + +class BaseCtx : public IdStringDB, public DeterministicRNG +{ + public: + std::unordered_map> nets; + std::unordered_map> cells; + + BaseCtx() {} + ~BaseCtx() {} + + Context *getCtx() { return reinterpret_cast(this); } + + const Context *getCtx() const { return reinterpret_cast(this); } + + // -------------------------------------------------------------- + + bool allUiReload = false; + bool frameUiReload = false; + std::unordered_set belUiReload; + std::unordered_set wireUiReload; + std::unordered_set pipUiReload; + std::unordered_set 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; -- cgit v1.2.3 From 2f5b94fe309619c221c3e1ea5aa48a4523bd3156 Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Tue, 17 Jul 2018 16:27:50 +0100 Subject: Add basic external locking, lock from P&R --- common/nextpnr.h | 19 +++++++++++++++++++ common/placer1.cc | 14 ++++++++++++++ common/router1.cc | 7 +++++++ 3 files changed, 40 insertions(+) diff --git a/common/nextpnr.h b/common/nextpnr.h index e53e4d01..7aa5b100 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -337,6 +339,11 @@ class DeterministicRNG class BaseCtx : public IdStringDB, public DeterministicRNG { + private: + std::mutex mutex; + bool mutex_owned; + pthread_t mutex_owner; + public: std::unordered_map> nets; std::unordered_map> cells; @@ -344,6 +351,18 @@ class BaseCtx : public IdStringDB, public DeterministicRNG 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(this); } const Context *getCtx() const { return reinterpret_cast(this); } diff --git a/common/placer1.cc b/common/placer1.cc index 74a11040..b229616c 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; @@ -150,6 +156,7 @@ class SAPlacer // Main simulated annealing loop for (int iter = 1;; iter++) { + ctx->lock(); n_move = n_accept = 0; improved = false; @@ -169,6 +176,7 @@ class SAPlacer try_swap_position(cell, try_bel); } } + // Heuristic to improve placement on the 8k if (improved) n_no_progress = 0; @@ -178,6 +186,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 +241,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 +262,7 @@ class SAPlacer } } } + ctx->unlock(); return true; } @@ -436,7 +448,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..a85de7c6 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -414,6 +414,7 @@ bool router1(Context *ctx) std::unordered_set 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); @@ -637,7 +642,9 @@ bool router1(Context *ctx) return true; } catch (log_execution_error_exception) { #ifndef NDEBUG + ctx->lock(); ctx->check(); + ctx->unlock(); #endif return false; } -- cgit v1.2.3 From 03508faabfc2f5b76039cfd13d02a341baa848a4 Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Tue, 17 Jul 2018 19:16:26 +0100 Subject: WIP. --- common/nextpnr.h | 2 +- common/placer1.cc | 9 +++ common/router1.cc | 2 + gui/application.cc | 20 ++--- gui/fpgaviewwidget.cc | 220 ++++++++++++++++++++++++++++++++++++-------------- gui/fpgaviewwidget.h | 62 ++++++++------ ice40/arch.h | 8 ++ 7 files changed, 227 insertions(+), 96 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 7aa5b100..fb5e042b 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -369,7 +369,7 @@ class BaseCtx : public IdStringDB, public DeterministicRNG // -------------------------------------------------------------- - bool allUiReload = false; + bool allUiReload = true; bool frameUiReload = false; std::unordered_set belUiReload; std::unordered_set wireUiReload; diff --git a/common/placer1.cc b/common/placer1.cc index b229616c..b58893ce 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,14 @@ 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; diff --git a/common/router1.cc b/common/router1.cc index a85de7c6..bde3be31 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -637,7 +637,9 @@ 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) { 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..f4bd2b97 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "fpgaviewwidget.h" @@ -241,26 +242,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), 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,17 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) if (fmt.minorVersion() < 1) { printf("Could not get OpenGL 3.1 context - trying anyway...\n "); } + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(1000/20); + + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(pokeRenderer())); + timer->start(1000/2); + + renderThread_ = std::unique_ptr(QThread::create([this] { renderLinesWorker(); })); + renderThread_->start(); } FPGAViewWidget::~FPGAViewWidget() {} @@ -283,8 +293,7 @@ FPGAViewWidget::~FPGAViewWidget() {} void FPGAViewWidget::newContext(Context *ctx) { ctx_ = ctx; - selectedItems_.clear(); - update(); + pokeRenderer(); } QSize FPGAViewWidget::minimumSizeHint() const { return QSize(640, 480); } @@ -297,7 +306,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 +407,158 @@ 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) { + render_.wakeOne(); +} + +void FPGAViewWidget::renderLinesWorker(void) { + for (;;) { + QMutex mutex; + mutex.lock(); + render_.wait(&mutex); + + renderLines(); + + mutex.unlock(); + } +} + +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 belDecals; + std::vector wireDecals; + std::vector pipDecals; + std::vector 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(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 decals) { - selectedItems_ = decals; - selectedItemsChanged_ = true; - update(); + rendererArgsLock_.lock(); + rendererArgs_->selectedItems = decals; + rendererArgs_->highlightedOrSelectedChanged = true; + rendererArgsLock_.unlock(); + pokeRenderer(); } void FPGAViewWidget::onHighlightGroupChanged(std::vector 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..19440054 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -21,12 +21,15 @@ #define MAPGLWIDGET_H #include +#include #include #include #include #include #include #include +#include +#include #include "nextpnr.h" @@ -209,14 +212,6 @@ class LineShader 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 +241,12 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void newContext(Context *ctx); void onSelectedArchItem(std::vector decals); void onHighlightGroupChanged(std::vector decals, int group); + void pokeRenderer(void); private: + void renderLines(void); + void renderLinesWorker(void); + QPoint lastPos_; LineShader lineShader_; QMatrix4x4 viewMove_; @@ -263,23 +262,36 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions Context *ctx_; - QColor backgroundColor_; - QColor gridColor_; - QColor gFrameColor_; - QColor gHiddenColor_; - QColor gInactiveColor_; - QColor gActiveColor_; - QColor gSelectedColor_; - QColor frameColor_; - - LineShaderData selectedShader_; - std::vector selectedItems_; - bool selectedItemsChanged_; - - LineShaderData highlightShader_[8]; - std::vector highlightItems_[8]; - bool highlightItemsChanged_[8]; - QColor highlightColors[8]; + QWaitCondition render_; + std::unique_ptr renderThread_; + + 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 selectedItems; + std::vector highlightedItems[8]; + bool highlightedOrSelectedChanged; + }; + + std::unique_ptr rendererData_; + QMutex rendererDataLock_; + std::unique_ptr rendererArgs_; + QMutex rendererArgsLock_; }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 5dab414b..b89a0b54 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -373,6 +373,7 @@ struct Arch : BaseCtx bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; + refreshUiBel(bel); } void unbindBel(BelId bel) @@ -382,6 +383,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 @@ -475,6 +477,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) @@ -494,6 +497,7 @@ struct Arch : BaseCtx net_wires.erase(it); wire_to_net[wire.index] = IdString(); + refreshUiWire(wire); } bool checkWireAvail(WireId wire) const @@ -541,6 +545,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) @@ -557,6 +563,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 -- cgit v1.2.3 From 0385ad1b1cc3dcd4673b3c674bc28ca12a7c7450 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 10:58:30 +0100 Subject: Refactor renderer thread --- gui/fpgaviewwidget.cc | 31 ++++++-------------------- gui/fpgaviewwidget.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index f4bd2b97..9a03b2a5 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "fpgaviewwidget.h" @@ -242,7 +241,7 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi } FPGAViewWidget::FPGAViewWidget(QWidget *parent) - : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs) + : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), paintTimer_(this), rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs) { colors_.background = QColor("#000000"); colors_.grid = QColor("#333"); @@ -276,16 +275,12 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) printf("Could not get OpenGL 3.1 context - trying anyway...\n "); } - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(1000/20); + connect(&paintTimer_, SIGNAL(timeout()), this, SLOT(update())); + paintTimer_.start(std::chrono::duration(1000/20)); // paint GL 20 times per second - timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(pokeRenderer())); - timer->start(1000/2); - - renderThread_ = std::unique_ptr(QThread::create([this] { renderLinesWorker(); })); - renderThread_->start(); + renderRunner_ = std::unique_ptr(new PeriodicRunner(this, [this] { renderLines(); })); + renderRunner_->start(); + renderRunner_->startTimer(std::chrono::duration(1000/2)); // render line 2 times per second } FPGAViewWidget::~FPGAViewWidget() {} @@ -423,19 +418,7 @@ void FPGAViewWidget::paintGL() } void FPGAViewWidget::pokeRenderer(void) { - render_.wakeOne(); -} - -void FPGAViewWidget::renderLinesWorker(void) { - for (;;) { - QMutex mutex; - mutex.lock(); - render_.wait(&mutex); - - renderLines(); - - mutex.unlock(); - } + renderRunner_->poke(); } void FPGAViewWidget::renderLines(void) diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 19440054..f846abca 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -209,6 +210,60 @@ 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 target_; + QTimer timer_; +public: + explicit PeriodicRunner(QObject *parent, std::function 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 @@ -245,7 +300,6 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions private: void renderLines(void); - void renderLinesWorker(void); QPoint lastPos_; LineShader lineShader_; @@ -261,9 +315,9 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions const float zoomLvl2_ = 50.0f; Context *ctx_; + QTimer paintTimer_; - QWaitCondition render_; - std::unique_ptr renderThread_; + std::unique_ptr renderRunner_; struct { QColor background; -- cgit v1.2.3 From b84a446eeff080715ba0b4b98c14822f0e3f8530 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 11:04:54 +0100 Subject: Mix-in Deterministic RNG at Context instead of BaseCtx --- common/nextpnr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 2a416a05..1f75434d 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -342,7 +342,7 @@ class DeterministicRNG }; -class BaseCtx : public IdStringDB, public DeterministicRNG +class BaseCtx : public IdStringDB { private: std::mutex mutex; @@ -400,7 +400,7 @@ NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_BEGIN -struct Context : Arch +struct Context : Arch, DeterministicRNG { bool verbose = false; bool debug = false; -- cgit v1.2.3 From b4b111a053a5e2aacd036508899277022914ae8f Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 13:15:22 +0100 Subject: Move pthread yield hack into BaseCtx --- common/nextpnr.h | 13 ++++++++++++- common/placer1.cc | 10 +--------- common/router1.cc | 1 + 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 1f75434d..e9cda565 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -346,8 +347,9 @@ class BaseCtx : public IdStringDB { private: std::mutex mutex; - bool mutex_owned; pthread_t mutex_owner; + + std::mutex generation_mutex; public: std::unordered_map> nets; @@ -360,6 +362,7 @@ class BaseCtx : public IdStringDB { mutex.lock(); mutex_owner = pthread_self(); + } void unlock(void) @@ -368,6 +371,14 @@ class BaseCtx : public IdStringDB mutex.unlock(); } + // TODO(q3k): get rid of this hack + void yield(void) + { + for (int i = 0; i < 10; i++) { + pthread_yield(); + } + } + Context *getCtx() { return reinterpret_cast(this); } const Context *getCtx() const { return reinterpret_cast(this); } diff --git a/common/placer1.cc b/common/placer1.cc index b58893ce..c8ba71a4 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -157,14 +156,7 @@ 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->yield(); ctx->lock(); n_move = n_accept = 0; improved = false; diff --git a/common/router1.cc b/common/router1.cc index bde3be31..3a0aa19b 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -495,6 +495,7 @@ bool router1(Context *ctx) #endif return false; } + ctx->yield(); ctx->lock(); iterCnt++; -- cgit v1.2.3 From 19f4b68f07edcbcb24282f5d3941d5d4a97afa03 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 13:19:45 +0100 Subject: clang-format and uncomment debug --- common/nextpnr.h | 11 ++++------- gui/application.cc | 20 ++++++++++---------- gui/fpgaviewwidget.cc | 21 ++++++++++----------- gui/fpgaviewwidget.h | 32 +++++++++++++++----------------- 4 files changed, 39 insertions(+), 45 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index e9cda565..09174320 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -250,10 +250,11 @@ struct CellInfo : ArchCellInfo class IdStringDB { friend class IdString; + private: mutable std::unordered_map *idstring_str_to_idx; mutable std::vector *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); } @@ -279,9 +280,7 @@ class DeterministicRNG uint64_t rngstate; public: - DeterministicRNG() : rngstate(0x3141592653589793) - { - } + DeterministicRNG() : rngstate(0x3141592653589793) {} uint64_t rng64() { @@ -340,7 +339,6 @@ class DeterministicRNG std::sort(a.begin(), a.end()); shuffle(a); } - }; class BaseCtx : public IdStringDB @@ -348,7 +346,7 @@ class BaseCtx : public IdStringDB private: std::mutex mutex; pthread_t mutex_owner; - + std::mutex generation_mutex; public: @@ -362,7 +360,6 @@ class BaseCtx : public IdStringDB { mutex.lock(); mutex_owner = pthread_self(); - } void unlock(void) diff --git a/gui/application.cc b/gui/application.cc index 12453b57..58dc23eb 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 9a03b2a5..b990baca 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -241,9 +241,10 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi } FPGAViewWidget::FPGAViewWidget(QWidget *parent) - : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), paintTimer_(this), rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs) + : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), paintTimer_(this), + rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs) { - colors_.background = QColor("#000000"); + colors_.background = QColor("#000000"); colors_.grid = QColor("#333"); colors_.frame = QColor("#d0d0d0"); colors_.hidden = QColor("#606060"); @@ -275,12 +276,12 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) printf("Could not get OpenGL 3.1 context - trying anyway...\n "); } - connect(&paintTimer_, SIGNAL(timeout()), this, SLOT(update())); - paintTimer_.start(std::chrono::duration(1000/20)); // paint GL 20 times per second + connect(&paintTimer_, SIGNAL(timeout()), this, SLOT(update())); + paintTimer_.start(std::chrono::duration(1000 / 20)); // paint GL 20 times per second renderRunner_ = std::unique_ptr(new PeriodicRunner(this, [this] { renderLines(); })); renderRunner_->start(); - renderRunner_->startTimer(std::chrono::duration(1000/2)); // render line 2 times per second + renderRunner_->startTimer(std::chrono::duration(1000 / 2)); // render line 2 times per second } FPGAViewWidget::~FPGAViewWidget() {} @@ -301,7 +302,8 @@ void FPGAViewWidget::initializeGL() log_error("Could not compile shader.\n"); } initializeOpenGLFunctions(); - glClearColor(colors_.background.red() / 255, colors_.background.green() / 255, colors_.background.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) @@ -417,9 +419,7 @@ void FPGAViewWidget::paintGL() rendererDataLock_.unlock(); } -void FPGAViewWidget::pokeRenderer(void) { - renderRunner_->poke(); -} +void FPGAViewWidget::pokeRenderer(void) { renderRunner_->poke(); } void FPGAViewWidget::renderLines(void) { @@ -439,7 +439,7 @@ void FPGAViewWidget::renderLines(void) ctx_->frameUiReload = false; decalsChanged = true; } - if (ctx_->belUiReload.size() > 0){ + if (ctx_->belUiReload.size() > 0) { ctx_->belUiReload.clear(); decalsChanged = true; } @@ -525,7 +525,6 @@ void FPGAViewWidget::renderLines(void) rendererDataLock_.unlock(); } - void FPGAViewWidget::onSelectedArchItem(std::vector decals) { rendererArgsLock_.lock(); diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index f846abca..0d0ef89c 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -28,8 +28,8 @@ #include #include #include -#include #include +#include #include #include "nextpnr.h" @@ -213,15 +213,16 @@ class LineShader class PeriodicRunner : public QThread { Q_OBJECT -private: + private: QMutex mutex_; QWaitCondition condition_; bool abort_; std::function target_; QTimer timer_; -public: - explicit PeriodicRunner(QObject *parent, std::function target) : - QThread(parent), abort_(false), target_(target), timer_(this) + + public: + explicit PeriodicRunner(QObject *parent, std::function target) + : QThread(parent), abort_(false), target_(target), timer_(this) { connect(&timer_, &QTimer::timeout, this, &PeriodicRunner::poke); } @@ -243,10 +244,7 @@ public: } } - void startTimer(std::chrono::milliseconds value) - { - timer_.start(value); - } + void startTimer(std::chrono::milliseconds value) { timer_.start(value); } ~PeriodicRunner() { @@ -258,10 +256,7 @@ public: wait(); } - void poke(void) - { - condition_.wakeOne(); - } + void poke(void) { condition_.wakeOne(); } }; class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions @@ -319,7 +314,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions std::unique_ptr renderRunner_; - struct { + struct + { QColor background; QColor grid; QColor frame; @@ -330,13 +326,15 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QColor highlight[8]; } colors_; - struct RendererData { + struct RendererData + { LineShaderData decals[4]; LineShaderData selected; LineShaderData highlighted[8]; }; - - struct RendererArgs { + + struct RendererArgs + { std::vector selectedItems; std::vector highlightedItems[8]; bool highlightedOrSelectedChanged; -- cgit v1.2.3 From b5b956bd214742892cd242ec38e4cc64c213e59e Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 17:57:16 +0100 Subject: Remove dead code. --- common/nextpnr.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 09174320..2baedef4 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -347,8 +347,6 @@ class BaseCtx : public IdStringDB std::mutex mutex; pthread_t mutex_owner; - std::mutex generation_mutex; - public: std::unordered_map> nets; std::unordered_map> cells; -- cgit v1.2.3 From 76e5236fb3c161a860b2c494fe44fde3011670af Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 18:24:16 +0100 Subject: Nuke IdStringDB --- common/nextpnr.cc | 8 +++--- common/nextpnr.h | 77 ++++++++++++++++++++++++------------------------------- ecp5/arch.cc | 2 +- generic/arch.cc | 2 +- ice40/arch.cc | 2 +- 5 files changed, 41 insertions(+), 50 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index c60d0e86..3861e5fe 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 IdStringDB *ctx, const std::string &s) +void IdString::set(const BaseCtx *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 IdStringDB *ctx, const std::string &s) } } -const std::string &IdString::str(const IdStringDB *ctx) const { return *ctx->idstring_idx_to_str->at(index); } +const std::string &IdString::str(const BaseCtx *ctx) const { return *ctx->idstring_idx_to_str->at(index); } -const char *IdString::c_str(const IdStringDB *ctx) const { return str(ctx).c_str(); } +const char *IdString::c_str(const BaseCtx *ctx) const { return str(ctx).c_str(); } -void IdString::initialize_add(const IdStringDB *ctx, const char *s, int idx) +void IdString::initialize_add(const BaseCtx *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 2baedef4..d42d3446 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -93,28 +93,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 IdStringDB; +struct BaseCtx; struct Context; struct IdString { int index = 0; - static void initialize_arch(const IdStringDB *ctx); + static void initialize_arch(const BaseCtx *ctx); - static void initialize_add(const IdStringDB *ctx, const char *s, int idx); + static void initialize_add(const BaseCtx *ctx, const char *s, int idx); IdString() {} - void set(const IdStringDB *ctx, const std::string &s); + void set(const BaseCtx *ctx, const std::string &s); - IdString(const IdStringDB *ctx, const std::string &s) { set(ctx, s); } + IdString(const BaseCtx *ctx, const std::string &s) { set(ctx, s); } - IdString(const IdStringDB *ctx, const char *s) { set(ctx, s); } + IdString(const BaseCtx *ctx, const char *s) { set(ctx, s); } - const std::string &str(const IdStringDB *ctx) const; + const std::string &str(const BaseCtx *ctx) const; - const char *c_str(const IdStringDB *ctx) const; + const char *c_str(const BaseCtx *ctx) const; bool operator<(const IdString &other) const { return index < other.index; } @@ -247,39 +247,10 @@ struct CellInfo : ArchCellInfo std::unordered_map pins; }; -class IdStringDB +struct DeterministicRNG { - friend class IdString; - - private: - mutable std::unordered_map *idstring_str_to_idx; - mutable std::vector *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); } - - IdStringDB() - { - idstring_str_to_idx = new std::unordered_map; - idstring_idx_to_str = new std::vector; - IdString::initialize_add(this, "", 0); - IdString::initialize_arch(this); - } - - ~IdStringDB() - { - delete idstring_str_to_idx; - delete idstring_idx_to_str; - } -}; - -class DeterministicRNG -{ - private: uint64_t rngstate; - public: DeterministicRNG() : rngstate(0x3141592653589793) {} uint64_t rng64() @@ -341,19 +312,35 @@ class DeterministicRNG } }; -class BaseCtx : public IdStringDB +struct BaseCtx { - private: + // Lock to perform mutating actions on the Context. std::mutex mutex; pthread_t mutex_owner; - public: + // ID String database. + mutable std::unordered_map *idstring_str_to_idx; + mutable std::vector *idstring_idx_to_str; + + // Placed nets and cells. std::unordered_map> nets; std::unordered_map> cells; - BaseCtx() {} - ~BaseCtx() {} + BaseCtx() + { + idstring_str_to_idx = new std::unordered_map; + idstring_idx_to_str = new std::vector; + IdString::initialize_add(this, "", 0); + IdString::initialize_arch(this); + } + + ~BaseCtx() + { + delete idstring_str_to_idx; + delete idstring_idx_to_str; + } + // Must be called before performing any mutating changes on the Ctx/Arch. void lock(void) { mutex.lock(); @@ -374,6 +361,10 @@ class BaseCtx : public IdStringDB } } + 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(this); } const Context *getCtx() const { return reinterpret_cast(this); } diff --git a/ecp5/arch.cc b/ecp5/arch.cc index fb37aa84..1510a27f 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -62,7 +62,7 @@ BelType Arch::belTypeFromId(IdString type) const // ----------------------------------------------------------------------- -void IdString::initialize_arch(const IdStringDB *ctx) +void IdString::initialize_arch(const BaseCtx *ctx) { #define X(t) initialize_add(ctx, #t, PIN_##t); diff --git a/generic/arch.cc b/generic/arch.cc index edc2ef26..390830aa 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 IdStringDB *ctx) {} +void IdString::initialize_arch(const BaseCtx *ctx) {} // --------------------------------------------------------------- diff --git a/ice40/arch.cc b/ice40/arch.cc index d1400a63..786d8ba1 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -102,7 +102,7 @@ BelType Arch::belTypeFromId(IdString type) const // ----------------------------------------------------------------------- -void IdString::initialize_arch(const IdStringDB *ctx) +void IdString::initialize_arch(const BaseCtx *ctx) { #define X(t) initialize_add(ctx, #t, PIN_##t); #include "portpins.inc" -- cgit v1.2.3 From 5d0dbe9db961f6dbd2494bd8ab730d8926d01626 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 18:24:34 +0100 Subject: clang-format --- ice40/arch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 786d8ba1..64a2a4be 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -19,13 +19,13 @@ #include #include +#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 // ----------------------------------------------------------------------- -- cgit v1.2.3 From 0311a27a53922783363ab607ca8f3832980990c6 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 18:34:59 +0100 Subject: Use UI lock for yielding --- common/nextpnr.h | 32 ++++++++++++++++++++++++++++---- common/placer1.cc | 6 +++--- common/router1.cc | 12 +++++++----- gui/fpgaviewwidget.cc | 4 ++-- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index d42d3446..8b8299bc 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -318,6 +318,11 @@ struct BaseCtx 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 *idstring_str_to_idx; mutable std::vector *idstring_idx_to_str; @@ -353,12 +358,31 @@ struct BaseCtx mutex.unlock(); } - // TODO(q3k): get rid of this hack + // 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) { - for (int i = 0; i < 10; i++) { - pthread_yield(); - } + unlock(); + ui_mutex.lock(); + ui_mutex.unlock(); + lock(); } IdString id(const std::string &s) const { return IdString(this, s); } diff --git a/common/placer1.cc b/common/placer1.cc index c8ba71a4..025c7c15 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -156,8 +156,6 @@ class SAPlacer // Main simulated annealing loop for (int iter = 1;; iter++) { - ctx->yield(); - ctx->lock(); n_move = n_accept = 0; improved = false; @@ -242,7 +240,9 @@ class SAPlacer metrics[net.first] = wl; curr_metric += wl; } - ctx->unlock(); + + // Let the UI show visualization updates. + ctx->yield(); } // Final post-pacement validitiy check ctx->lock(); diff --git a/common/router1.cc b/common/router1.cc index 3a0aa19b..3e4416df 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -495,8 +495,6 @@ bool router1(Context *ctx) #endif return false; } - ctx->yield(); - ctx->lock(); iterCnt++; if (ctx->verbose) @@ -533,9 +531,11 @@ bool router1(Context *ctx) ripupQueue.insert(net_name); } - if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) + if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) { log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, netCnt - int(ripupQueue.size()), int(ripupQueue.size())); + ctx->yield(); + } } int normalRouteCnt = netCnt - int(ripupQueue.size()); @@ -596,8 +596,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)) @@ -626,7 +628,7 @@ bool router1(Context *ctx) if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || iterCnt == 128) ripup_penalty += ctx->getRipupDelayPenalty(); - ctx->unlock(); + ctx->yield(); } log_info("routing complete after %d iterations.\n", iterCnt); diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index b990baca..86aae25d 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -426,7 +426,7 @@ void FPGAViewWidget::renderLines(void) if (ctx_ == nullptr) return; - ctx_->lock(); + ctx_->lock_ui(); // For now, collapse any decal changes into change of all decals. // TODO(q3k): fix this @@ -475,7 +475,7 @@ void FPGAViewWidget::renderLines(void) groupDecals.push_back(ctx_->getGroupDecal(group)); } } - ctx_->unlock(); + ctx_->unlock_ui(); rendererArgsLock_.lock(); auto selectedItems = rendererArgs_->selectedItems; -- cgit v1.2.3 From be14e161ae1963203e380bfbe02cfaeda828f838 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 20 Jul 2018 18:35:42 +0100 Subject: Re-enable drawing Pips. --- ice40/arch.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 64a2a4be..e09f26be 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -484,9 +484,9 @@ DecalXY Arch::getWireDecal(WireId wire) const DecalXY Arch::getPipDecal(PipId pip) const { DecalXY decalxy; - // decalxy.decal.type = DecalId::TYPE_PIP; - // decalxy.decal.index = pip.index; - // decalxy.decal.active = pip_to_net.at(pip.index) != IdString(); + decalxy.decal.type = DecalId::TYPE_PIP; + decalxy.decal.index = pip.index; + decalxy.decal.active = pip_to_net.at(pip.index) != IdString(); return decalxy; }; -- cgit v1.2.3