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 ++++++++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 24 deletions(-) (limited to 'common') 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); } -- 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(-) (limited to 'common') 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(+) (limited to 'common') 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 ++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'common') 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) { -- 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(-) (limited to 'common') 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(-) (limited to 'common') 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 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'common') 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) -- 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(-) (limited to 'common') 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 ++++++++++++++++++++++++------------------------------- 2 files changed, 38 insertions(+), 47 deletions(-) (limited to 'common') 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); } -- 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 +++++++----- 3 files changed, 38 insertions(+), 12 deletions(-) (limited to 'common') 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); -- cgit v1.2.3 From 30e2f0e1e8cfdb24abe6c3a8013691497c706975 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 21 Jul 2018 21:40:06 +0200 Subject: Add Loc constructors Signed-off-by: Clifford Wolf --- common/nextpnr.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'common') diff --git a/common/nextpnr.h b/common/nextpnr.h index 40fd3d13..c8915c19 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -164,6 +164,9 @@ struct Loc { int x = -1, y = -1, z = -1; + Loc() {} + Loc(int x, int y, int z) : x(x), y(y), z(z) {} + bool operator==(const Loc &other) const { return (x == other.x) && (y == other.y) && (z == other.z); } bool operator!=(const Loc &other) const { return (x != other.x) || (y != other.y) || (z == other.z); } }; -- cgit v1.2.3 From 1e96999863da24021c215a3706b5a442789ba3a7 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 22 Jul 2018 00:50:49 +0200 Subject: clangformat Signed-off-by: Clifford Wolf --- common/router1.cc | 55 +++++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 30 deletions(-) (limited to 'common') diff --git a/common/router1.cc b/common/router1.cc index a171374f..f8d86a5b 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -251,7 +251,8 @@ struct Router } } - Router(Context *ctx, RipupScoreboard &scores, IdString net_name, int user_idx = -1, bool reroute = false, bool ripup = false, delay_t ripup_penalty = 0) + Router(Context *ctx, RipupScoreboard &scores, IdString net_name, int user_idx = -1, bool reroute = false, + bool ripup = false, delay_t ripup_penalty = 0) : ctx(ctx), scores(scores), net_name(net_name), ripup(ripup), ripup_penalty(ripup_penalty) { auto net_info = ctx->nets.at(net_name).get(); @@ -336,7 +337,8 @@ struct Router user_it.port.c_str(ctx), user_port.c_str(ctx), user_it.cell->name.c_str(ctx), ctx->getBelName(dst_bel).c_str(ctx)); - std::function register_existing_path = [ctx, net_info, &src_wires, ®ister_existing_path](WireId wire) -> delay_t { + std::function register_existing_path = + [ctx, net_info, &src_wires, ®ister_existing_path](WireId wire) -> delay_t { auto it = src_wires.find(wire); if (it != src_wires.end()) return it->second; @@ -345,7 +347,7 @@ struct Router delay_t delay = register_existing_path(ctx->getPipSrcWire(pip)); delay += ctx->getPipDelay(pip).maxDelay(); delay += ctx->getWireDelay(wire).maxDelay(); - delay -= 2*ctx->getDelayEpsilon(); + delay -= 2 * ctx->getDelayEpsilon(); src_wires[wire] = delay; return delay; @@ -361,7 +363,7 @@ struct Router } register_existing_path(dst_wire); - check_next_user_for_existing_path:; + check_next_user_for_existing_path:; } std::vector ripup_wires; @@ -371,8 +373,8 @@ struct Router for (auto &it : ripup_wires) { if (ctx->debug) - log(" Unbind dangling wire for net %s: %s\n", - net_name.c_str(ctx), ctx->getWireName(it).c_str(ctx)); + log(" Unbind dangling wire for net %s: %s\n", net_name.c_str(ctx), + ctx->getWireName(it).c_str(ctx)); ctx->unbindWire(it); } } @@ -499,9 +501,8 @@ struct RouteJob }; }; -void addFullNetRouteJob(Context *ctx, IdString net_name, - std::unordered_map> &cache, - std::priority_queue, RouteJob::Greater> &queue) +void addFullNetRouteJob(Context *ctx, IdString net_name, std::unordered_map> &cache, + std::priority_queue, RouteJob::Greater> &queue) { NetInfo *net_info = ctx->nets.at(net_name).get(); @@ -541,8 +542,7 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, bool got_slack = false; - for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) - { + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { if (net_cache[user_idx]) continue; @@ -550,8 +550,8 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, auto dst_bel = user_info.cell->bel; if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", - user_info.cell->name.c_str(ctx), user_info.cell->type.c_str(ctx)); + log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_info.cell->name.c_str(ctx), + user_info.cell->type.c_str(ctx)); IdString user_port = user_info.port; @@ -595,8 +595,7 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, net_cache[user_idx] = true; } -void addNetRouteJobs(Context *ctx, IdString net_name, - std::unordered_map> &cache, +void addNetRouteJobs(Context *ctx, IdString net_name, std::unordered_map> &cache, std::priority_queue, RouteJob::Greater> &queue) { NetInfo *net_info = ctx->nets.at(net_name).get(); @@ -629,8 +628,7 @@ void addNetRouteJobs(Context *ctx, IdString net_name, if (net_cache.empty()) net_cache.resize(net_info->users.size()); - for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) - { + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { if (net_cache[user_idx]) continue; @@ -638,8 +636,8 @@ void addNetRouteJobs(Context *ctx, IdString net_name, auto dst_bel = user_info.cell->bel; if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", - user_info.cell->name.c_str(ctx), user_info.cell->type.c_str(ctx)); + log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_info.cell->name.c_str(ctx), + user_info.cell->type.c_str(ctx)); IdString user_port = user_info.port; @@ -661,12 +659,10 @@ void addNetRouteJobs(Context *ctx, IdString net_name, auto it = net_info->wires.find(cursor); if (it == net_info->wires.end()) { if (ctx->debug) - log("Adding job [%s %d]: %s %s (%s) -> %s %s (%s)\n", - net_name.c_str(ctx), user_idx, + log("Adding job [%s %d]: %s %s (%s) -> %s %s (%s)\n", net_name.c_str(ctx), user_idx, ctx->getBelName(src_bel).c_str(ctx), driver_port.c_str(ctx), - ctx->getWireName(src_wire).c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx), user_port.c_str(ctx), - ctx->getWireName(dst_wire).c_str(ctx)); + ctx->getWireName(src_wire).c_str(ctx), ctx->getBelName(dst_bel).c_str(ctx), + user_port.c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx)); RouteJob job; job.net = net_name; job.user_idx = user_idx; @@ -736,7 +732,7 @@ bool router1(Context *ctx) bool printNets = ctx->verbose && (jobQueue.size() < 10); while (!jobQueue.empty()) { - if(ctx->debug) + if (ctx->debug) log("Next job slack: %f\n", double(jobQueue.top().slack)); auto net_name = jobQueue.top().net; @@ -745,8 +741,8 @@ bool router1(Context *ctx) if (printNets) { if (user_idx < 0) - log_info(" routing all %d users of net %s\n", - int(ctx->nets.at(net_name)->users.size()), net_name.c_str(ctx)); + log_info(" routing all %d users of net %s\n", int(ctx->nets.at(net_name)->users.size()), + net_name.c_str(ctx)); else log_info(" routing user %d of net %s\n", user_idx, net_name.c_str(ctx)); } @@ -854,9 +850,8 @@ bool router1(Context *ctx) } if (!ctx->verbose) - log_info("iteration %d: routed %d nets without ripup, routed %d nets with ripup.\n", - iterCnt, int(normalRouteNets.size()), int(ripupQueue.size())); - + log_info("iteration %d: routed %d nets without ripup, routed %d nets with ripup.\n", iterCnt, + int(normalRouteNets.size()), int(ripupQueue.size())); totalVisitCnt += visitCnt; totalRevisitCnt += revisitCnt; -- cgit v1.2.3 From c6e4ad322745b478f0f289f4cc5f3668e05700ac Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 22 Jul 2018 02:16:03 +0200 Subject: Move common patterns from router1 to Context API Signed-off-by: Clifford Wolf --- common/nextpnr.cc | 56 ++++++++++++++ common/nextpnr.h | 4 + common/router1.cc | 214 ++++++++++++++++-------------------------------------- 3 files changed, 124 insertions(+), 150 deletions(-) (limited to 'common') diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 3861e5fe..ac292e77 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -51,6 +51,62 @@ void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx) ctx->idstring_idx_to_str->push_back(&insert_rc.first->first); } +WireId Context::getNetinfoSourceWire(NetInfo *net_info) const +{ + if (net_info->driver.cell == nullptr) + return WireId(); + + auto src_bel = net_info->driver.cell->bel; + + if (src_bel == BelId()) + return WireId(); + + IdString driver_port = net_info->driver.port; + + auto driver_port_it = net_info->driver.cell->pins.find(driver_port); + if (driver_port_it != net_info->driver.cell->pins.end()) + driver_port = driver_port_it->second; + + return getWireBelPin(src_bel, portPinFromId(driver_port)); +} + +WireId Context::getNetinfoSinkWire(NetInfo *net_info, int user_idx) const +{ + auto &user_info = net_info->users[user_idx]; + auto dst_bel = user_info.cell->bel; + + if (dst_bel == BelId()) + return WireId(); + + IdString user_port = user_info.port; + + auto user_port_it = user_info.cell->pins.find(user_port); + + if (user_port_it != user_info.cell->pins.end()) + user_port = user_port_it->second; + + return getWireBelPin(dst_bel, portPinFromId(user_port)); +} + +delay_t Context::getNetinfoRouteDelay(NetInfo *net_info, int user_idx) const +{ + WireId src_wire = getNetinfoSourceWire(net_info); + WireId cursor = getNetinfoSinkWire(net_info, user_idx); + delay_t delay = getWireDelay(src_wire).maxDelay(); + + while (cursor != WireId() && cursor != src_wire) { + auto it = net_info->wires.find(cursor); + if (it == net_info->wires.end()) + break; + PipId pip = it->second.pip; + delay += getPipDelay(pip).maxDelay(); + delay += getWireDelay(cursor).maxDelay(); + cursor = getPipSrcWire(pip); + } + + return delay; +} + static uint32_t xorshift32(uint32_t x) { x ^= x << 13; diff --git a/common/nextpnr.h b/common/nextpnr.h index d89eb15b..bb40e1b6 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -460,6 +460,10 @@ struct Context : Arch, DeterministicRNG // -------------------------------------------------------------- + WireId getNetinfoSourceWire(NetInfo *net_info) const; + WireId getNetinfoSinkWire(NetInfo *net_info, int user_idx) const; + delay_t getNetinfoRouteDelay(NetInfo *net_info, int user_idx) const; + // provided by router1.cc bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay); diff --git a/common/router1.cc b/common/router1.cc index f8d86a5b..dbe3a003 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -263,42 +263,26 @@ struct Router if (ctx->debug) log(" Source: %s.%s.\n", net_info->driver.cell->name.c_str(ctx), net_info->driver.port.c_str(ctx)); - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), - net_info->driver.cell->type.c_str(ctx)); - - if (ctx->debug) - log(" Source bel: %s\n", ctx->getBelName(src_bel).c_str(ctx)); - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s (pin %s) on source cell %s " - "(bel %s).\n", - net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), - ctx->getBelName(src_bel).c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", + net_info->driver.port.c_str(ctx), net_info->driver.cell->name.c_str(ctx)); if (ctx->debug) log(" Source wire: %s\n", ctx->getWireName(src_wire).c_str(ctx)); std::unordered_map src_wires; - std::vector users_array; + std::vector users_array; if (user_idx < 0) { // route all users - users_array = net_info->users; + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) + users_array.push_back(user_idx); ctx->shuffle(users_array); } else { // route only the selected user - users_array.push_back(net_info->users[user_idx]); + users_array.push_back(user_idx); } if (reroute) { @@ -312,30 +296,12 @@ struct Router ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay(); - for (auto &user_it : net_info->users) { - auto dst_bel = user_it.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_it.cell->name.c_str(ctx), - user_it.cell->type.c_str(ctx)); - - if (ctx->debug) - log(" Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); - - IdString user_port = user_it.port; - - auto user_port_it = user_it.cell->pins.find(user_port); - - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_it.port.c_str(ctx), user_port.c_str(ctx), user_it.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", + net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); std::function register_existing_path = [ctx, net_info, &src_wires, ®ister_existing_path](WireId wire) -> delay_t { @@ -379,33 +345,15 @@ struct Router } } - for (auto &user_it : users_array) { - if (ctx->debug) - log(" Route to: %s.%s.\n", user_it.cell->name.c_str(ctx), user_it.port.c_str(ctx)); - - auto dst_bel = user_it.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_it.cell->name.c_str(ctx), - user_it.cell->type.c_str(ctx)); - + for (int user_idx : users_array) { if (ctx->debug) - log(" Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); - - IdString user_port = user_it.port; + log(" Route to: %s.%s.\n", net_info->users[user_idx].cell->name.c_str(ctx), net_info->users[user_idx].port.c_str(ctx)); - auto user_port_it = user_it.cell->pins.find(user_port); - - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_it.port.c_str(ctx), user_port.c_str(ctx), user_it.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", + net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); if (ctx->debug) { log(" Destination wire: %s\n", ctx->getWireName(dst_wire).c_str(ctx)); @@ -509,25 +457,11 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, std::unordered_mapdriver.cell == nullptr) return; - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), - net_info->driver.cell->type.c_str(ctx)); - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s (pin %s) on source cell %s " - "(bel %s).\n", - net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), - ctx->getBelName(src_bel).c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", + net_info->driver.port.c_str(ctx), net_info->driver.cell->name.c_str(ctx)); auto &net_cache = cache[net_name]; @@ -546,41 +480,25 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, std::unordered_mapusers[user_idx]; - auto dst_bel = user_info.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_info.cell->name.c_str(ctx), - user_info.cell->type.c_str(ctx)); - - IdString user_port = user_info.port; - - auto user_port_it = user_info.cell->pins.find(user_port); - - if (user_port_it != user_info.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_info.port.c_str(ctx), user_port.c_str(ctx), user_info.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", + net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); if (user_idx == 0) - job.slack = user_info.budget - ctx->estimateDelay(src_wire, dst_wire); + job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); else - job.slack = std::min(job.slack, user_info.budget - ctx->estimateDelay(src_wire, dst_wire)); + job.slack = std::min(job.slack, net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); WireId cursor = dst_wire; while (src_wire != cursor) { auto it = net_info->wires.find(cursor); if (it == net_info->wires.end()) { if (!got_slack) - job.slack = user_info.budget - ctx->estimateDelay(src_wire, dst_wire); + job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); else - job.slack = std::min(job.slack, user_info.budget - ctx->estimateDelay(src_wire, dst_wire)); + job.slack = std::min(job.slack, net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); got_slack = true; break; } @@ -603,25 +521,11 @@ void addNetRouteJobs(Context *ctx, IdString net_name, std::unordered_mapdriver.cell == nullptr) return; - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), - net_info->driver.cell->type.c_str(ctx)); - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s (pin %s) on source cell %s " - "(bel %s).\n", - net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), - ctx->getBelName(src_bel).c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", + net_info->driver.port.c_str(ctx), net_info->driver.cell->name.c_str(ctx)); auto &net_cache = cache[net_name]; @@ -632,41 +536,20 @@ void addNetRouteJobs(Context *ctx, IdString net_name, std::unordered_mapusers[user_idx]; - auto dst_bel = user_info.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_info.cell->name.c_str(ctx), - user_info.cell->type.c_str(ctx)); - - IdString user_port = user_info.port; - - auto user_port_it = user_info.cell->pins.find(user_port); - - if (user_port_it != user_info.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_info.port.c_str(ctx), user_port.c_str(ctx), user_info.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", + net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); WireId cursor = dst_wire; while (src_wire != cursor) { auto it = net_info->wires.find(cursor); if (it == net_info->wires.end()) { - if (ctx->debug) - log("Adding job [%s %d]: %s %s (%s) -> %s %s (%s)\n", net_name.c_str(ctx), user_idx, - ctx->getBelName(src_bel).c_str(ctx), driver_port.c_str(ctx), - ctx->getWireName(src_wire).c_str(ctx), ctx->getBelName(dst_bel).c_str(ctx), - user_port.c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx)); RouteJob job; job.net = net_name; job.user_idx = user_idx; - job.slack = user_info.budget - ctx->estimateDelay(src_wire, dst_wire); + job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); job.randtag = ctx->rng(); queue.push(job); net_cache[user_idx] = true; @@ -870,6 +753,37 @@ bool router1(Context *ctx) totalVisitCnt, (100.0 * totalRevisitCnt) / totalVisitCnt, (100.0 * totalOvertimeRevisitCnt) / totalVisitCnt); + { + float tns = 0; + int tns_net_count = 0; + int tns_arc_count = 0; + for (auto &net_it : ctx->nets) { + bool got_negative_slack = false; + NetInfo *net_info = ctx->nets.at(net_it.first).get(); + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { + delay_t arc_delay = ctx->getNetinfoRouteDelay(net_info, user_idx); + delay_t arc_budget = net_info->users[user_idx].budget; + delay_t arc_slack = arc_budget - arc_delay; + if (arc_slack < 0) { + if (!got_negative_slack) { + if (ctx->verbose) + log_info("net %s has negative slack arcs:\n", net_info->name.c_str(ctx)); + tns_net_count++; + } + if (ctx->verbose) + log_info(" arc %s -> %s has %f ns slack (delay %f, budget %f)\n", + ctx->getWireName(ctx->getNetinfoSourceWire(net_info)).c_str(ctx), + ctx->getWireName(ctx->getNetinfoSinkWire(net_info, user_idx)).c_str(ctx), + ctx->getDelayNS(arc_slack), ctx->getDelayNS(arc_delay), ctx->getDelayNS(arc_budget)); + tns += ctx->getDelayNS(arc_slack); + tns_arc_count++; + } + } + } + log_info("final tns with respect to arc budgets: %f ns (%d nets, %d arcs)\n", + tns, tns_net_count, tns_arc_count); + } + NPNR_ASSERT(jobQueue.empty()); jobCache.clear(); -- cgit v1.2.3 From 62b66e02085371c456dee95dc08d2cd41351c91f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 22 Jul 2018 10:59:21 +0200 Subject: Rename getWireBelPin to getBelPinWire Signed-off-by: Clifford Wolf --- common/nextpnr.cc | 4 ++-- common/place_common.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/nextpnr.cc b/common/nextpnr.cc index ac292e77..74747642 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -67,7 +67,7 @@ WireId Context::getNetinfoSourceWire(NetInfo *net_info) const if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - return getWireBelPin(src_bel, portPinFromId(driver_port)); + return getBelPinWire(src_bel, portPinFromId(driver_port)); } WireId Context::getNetinfoSinkWire(NetInfo *net_info, int user_idx) const @@ -85,7 +85,7 @@ WireId Context::getNetinfoSinkWire(NetInfo *net_info, int user_idx) const if (user_port_it != user_info.cell->pins.end()) user_port = user_port_it->second; - return getWireBelPin(dst_bel, portPinFromId(user_port)); + return getBelPinWire(dst_bel, portPinFromId(user_port)); } delay_t Context::getNetinfoRouteDelay(NetInfo *net_info, int user_idx) const diff --git a/common/place_common.cc b/common/place_common.cc index 370eff23..95b7b2aa 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -36,7 +36,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type if (driver_cell->bel == BelId()) return 0; ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); - WireId drv_wire = ctx->getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port)); + WireId drv_wire = ctx->getBelPinWire(driver_cell->bel, ctx->portPinFromId(net->driver.port)); if (driver_gb) return 0; float worst_slack = 1000; @@ -48,7 +48,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type if (load_cell->bel == BelId()) continue; if (ctx->timing_driven && type == MetricType::COST) { - WireId user_wire = ctx->getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port)); + WireId user_wire = ctx->getBelPinWire(load_cell->bel, ctx->portPinFromId(load.port)); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); if (slack < 0) -- cgit v1.2.3 From a436facfd0a610c8b055e07d3a72e4122df677c6 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 23 Jul 2018 12:44:26 +0200 Subject: Add fallback to estimateDelay() in getNetinfoRouteDelay() Signed-off-by: Clifford Wolf --- common/nextpnr.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 74747642..2c50c9a1 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -92,7 +92,7 @@ delay_t Context::getNetinfoRouteDelay(NetInfo *net_info, int user_idx) const { WireId src_wire = getNetinfoSourceWire(net_info); WireId cursor = getNetinfoSinkWire(net_info, user_idx); - delay_t delay = getWireDelay(src_wire).maxDelay(); + delay_t delay = 0; while (cursor != WireId() && cursor != src_wire) { auto it = net_info->wires.find(cursor); @@ -104,6 +104,11 @@ delay_t Context::getNetinfoRouteDelay(NetInfo *net_info, int user_idx) const cursor = getPipSrcWire(pip); } + if (cursor == src_wire) + delay += getWireDelay(src_wire).maxDelay(); + else + delay += estimateDelay(src_wire, cursor); + return delay; } -- cgit v1.2.3 From 38962d0f02720799d797326cc3d5ce906f853359 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 23 Jul 2018 12:45:31 +0200 Subject: clangformat Signed-off-by: Clifford Wolf --- common/router1.cc | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'common') diff --git a/common/router1.cc b/common/router1.cc index dbe3a003..fbf3c467 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -266,8 +266,8 @@ struct Router auto src_wire = ctx->getNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s on source cell %s.\n", - net_info->driver.port.c_str(ctx), net_info->driver.cell->name.c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), + net_info->driver.cell->name.c_str(ctx)); if (ctx->debug) log(" Source wire: %s\n", ctx->getWireName(src_wire).c_str(ctx)); @@ -301,7 +301,8 @@ struct Router if (dst_wire == WireId()) log_error("No wire found for port %s on destination cell %s.\n", - net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); + net_info->users[user_idx].port.c_str(ctx), + net_info->users[user_idx].cell->name.c_str(ctx)); std::function register_existing_path = [ctx, net_info, &src_wires, ®ister_existing_path](WireId wire) -> delay_t { @@ -347,7 +348,8 @@ struct Router for (int user_idx : users_array) { if (ctx->debug) - log(" Route to: %s.%s.\n", net_info->users[user_idx].cell->name.c_str(ctx), net_info->users[user_idx].port.c_str(ctx)); + log(" Route to: %s.%s.\n", net_info->users[user_idx].cell->name.c_str(ctx), + net_info->users[user_idx].port.c_str(ctx)); auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); @@ -460,8 +462,8 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, std::unordered_mapgetNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s on source cell %s.\n", - net_info->driver.port.c_str(ctx), net_info->driver.cell->name.c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), + net_info->driver.cell->name.c_str(ctx)); auto &net_cache = cache[net_name]; @@ -483,8 +485,8 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, std::unordered_mapgetNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s on destination cell %s.\n", - net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx), + net_info->users[user_idx].cell->name.c_str(ctx)); if (user_idx == 0) job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); @@ -498,7 +500,8 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, std::unordered_mapusers[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); else - job.slack = std::min(job.slack, net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); + job.slack = std::min(job.slack, + net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); got_slack = true; break; } @@ -524,8 +527,8 @@ void addNetRouteJobs(Context *ctx, IdString net_name, std::unordered_mapgetNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s on source cell %s.\n", - net_info->driver.port.c_str(ctx), net_info->driver.cell->name.c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), + net_info->driver.cell->name.c_str(ctx)); auto &net_cache = cache[net_name]; @@ -539,8 +542,8 @@ void addNetRouteJobs(Context *ctx, IdString net_name, std::unordered_mapgetNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s on destination cell %s.\n", - net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx), + net_info->users[user_idx].cell->name.c_str(ctx)); WireId cursor = dst_wire; while (src_wire != cursor) { @@ -772,16 +775,17 @@ bool router1(Context *ctx) } if (ctx->verbose) log_info(" arc %s -> %s has %f ns slack (delay %f, budget %f)\n", - ctx->getWireName(ctx->getNetinfoSourceWire(net_info)).c_str(ctx), - ctx->getWireName(ctx->getNetinfoSinkWire(net_info, user_idx)).c_str(ctx), - ctx->getDelayNS(arc_slack), ctx->getDelayNS(arc_delay), ctx->getDelayNS(arc_budget)); + ctx->getWireName(ctx->getNetinfoSourceWire(net_info)).c_str(ctx), + ctx->getWireName(ctx->getNetinfoSinkWire(net_info, user_idx)).c_str(ctx), + ctx->getDelayNS(arc_slack), ctx->getDelayNS(arc_delay), + ctx->getDelayNS(arc_budget)); tns += ctx->getDelayNS(arc_slack); tns_arc_count++; } } } - log_info("final tns with respect to arc budgets: %f ns (%d nets, %d arcs)\n", - tns, tns_net_count, tns_arc_count); + log_info("final tns with respect to arc budgets: %f ns (%d nets, %d arcs)\n", tns, tns_net_count, + tns_arc_count); } NPNR_ASSERT(jobQueue.empty()); -- cgit v1.2.3 From e647604e2a584917ad2fc9acfe838a1395c613c2 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 23 Jul 2018 14:03:23 +0200 Subject: Add Context::archcheck() and "nextpnr-ice40 --test" Signed-off-by: Clifford Wolf --- common/archcheck.cc | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++ common/log.h | 6 +-- common/nextpnr.h | 1 + 3 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 common/archcheck.cc (limited to 'common') diff --git a/common/archcheck.cc b/common/archcheck.cc new file mode 100644 index 00000000..5c4ef26c --- /dev/null +++ b/common/archcheck.cc @@ -0,0 +1,146 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "nextpnr.h" +#include "log.h" + +#if 0 +#define dbg(...) log(__VA_ARGS__) +#else +#define dbg(...) +#endif + +USING_NEXTPNR_NAMESPACE + +namespace { + +void archcheck_names(const Context *ctx) +{ + log_info("Checking entity names.\n"); + + log_info("Checking bel names..\n"); + for (BelId bel : ctx->getBels()) { + IdString name = ctx->getBelName(bel); + BelId bel2 = ctx->getBelByName(name); + log_assert(bel == bel2); + } + + log_info("Checking wire names..\n"); + for (WireId wire : ctx->getWires()) { + IdString name = ctx->getWireName(wire); + WireId wire2 = ctx->getWireByName(name); + log_assert(wire == wire2); + } + + log_info("Checking pip names..\n"); + for (PipId pip : ctx->getPips()) { + IdString name = ctx->getPipName(pip); + PipId pip2 = ctx->getPipByName(name); + log_assert(pip == pip2); + } + + log_break(); +} + +void archcheck_locs(const Context *ctx) +{ + log_info("Checking location data.\n"); + + log_info("Checking all bels..\n"); + for (BelId bel : ctx->getBels()) { + log_assert(bel != BelId()); + dbg("> %s\n", ctx->getBelName(bel).c_str(ctx)); + + Loc loc = ctx->getBelLocation(bel); + dbg(" ... %d %d %d\n", loc.x, loc.y, loc.z); + + log_assert(0 <= loc.x); + log_assert(0 <= loc.y); + log_assert(0 <= loc.z); + log_assert(loc.x < ctx->getGridDimX()); + log_assert(loc.y < ctx->getGridDimY()); + log_assert(loc.z < ctx->getTileDimZ(loc.x, loc.y)); + + BelId bel2 = ctx->getBelByLocation(loc); + dbg(" ... %s\n", ctx->getBelName(bel2).c_str(ctx)); + log_assert(bel == bel2); + } + + log_info("Checking all locations..\n"); + for (int x = 0; x < ctx->getGridDimX(); x++) + for (int y = 0; y < ctx->getGridDimY(); y++) + { + dbg("> %d %d\n", x, y); + std::unordered_set usedz; + + for (int z = 0; z < ctx->getTileDimZ(x, y); z++) { + BelId bel = ctx->getBelByLocation(Loc(x, y, z)); + if (bel == BelId()) + continue; + Loc loc = ctx->getBelLocation(bel); + dbg(" + %d %s\n", z, ctx->getBelName(bel).c_str(ctx)); + log_assert(x == loc.x); + log_assert(y == loc.y); + log_assert(z == loc.z); + usedz.insert(z); + } + + for (BelId bel : ctx->getBelsByTile(x, y)) { + Loc loc = ctx->getBelLocation(bel); + dbg(" - %d %s\n", loc.z, ctx->getBelName(bel).c_str(ctx)); + log_assert(x == loc.x); + log_assert(y == loc.y); + log_assert(usedz.count(loc.z)); + usedz.erase(loc.z); + } + + log_assert(usedz.empty()); + } + + log_break(); +} + +void archcheck_conn(const Context *ctx) +{ +#if 0 + log_info("Checking connectivity data.\n"); + + log_info("Checking all wires..\n"); + for (WireId wire : ctx->getWires()) + { + ... + } +#endif +} + +} // namespace + +NEXTPNR_NAMESPACE_BEGIN + +void Context::archcheck() const +{ + log_info("Running architecture database integrity check.\n"); + log_break(); + + archcheck_names(this); + archcheck_locs(this); + archcheck_conn(this); +} + +NEXTPNR_NAMESPACE_END diff --git a/common/log.h b/common/log.h index c3607e39..35450311 100644 --- a/common/log.h +++ b/common/log.h @@ -69,17 +69,13 @@ NPNR_NORETURN void log_cmd_error(const char *format, ...) NPNR_ATTRIBUTE(format( void log_break(); void log_flush(); -#ifndef NDEBUG static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) { if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); } #define log_assert(_assert_expr_) \ - YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) -#else -#define log_assert(_assert_expr_) -#endif + NEXTPNR_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) #define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__) #define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) diff --git a/common/nextpnr.h b/common/nextpnr.h index bb40e1b6..021772fe 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -472,6 +472,7 @@ struct Context : Arch, DeterministicRNG uint32_t checksum() const; void check() const; + void archcheck() const; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3