From 90edf33c95de975b7f8204624a995c4826c52b84 Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Fri, 29 Jan 2021 11:01:36 +0000 Subject: common: Adding IdStringList type Using an optimised storage for <=4 objects to avoid excessive heap allocations. Signed-off-by: D. Shah --- common/nextpnr.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'common') diff --git a/common/nextpnr.h b/common/nextpnr.h index b4f68f93..68a341f3 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -145,6 +145,73 @@ template <> struct hash NEXTPNR_NAMESPACE_BEGIN +// An small size optimised array that is statically allocated when the size is N or less; heap allocated otherwise +template class SSOArray +{ + union + { + T data_static[N]; + T *data_heap; + }; + size_t m_size; + + private: + inline bool is_heap() { return (m_size > N); } + void alloc() + { + if (is_heap()) { + data_heap = new T[m_size]; + } + } + + public: + T *data() { return is_heap() ? data_heap : &data_static; } + const T *data() const { return is_heap() ? data_heap : &data_static; } + size_t size() const { return m_size; } + + T *begin() { return data(); } + T *end() { return data() + m_size; } + const T *begin() const { return data(); } + const T *end() const { return data() + m_size; } + + SSOArray(size_t size, const T &init = T()) : m_size(size) + { + alloc(); + std::fill(begin(), end(), init); + } + + template SSOArray(const Tother &other) : m_size(other.size()) + { + alloc(); + std::copy(other.begin(), other.end(), begin()); + } + + ~SSOArray() + { + if (is_heap()) { + delete[] data_heap; + } + } + + bool operator==(const SSOArray &other) const + { + if (size() != other.size()) + return false; + return std::equal(begin(), end(), other.begin()); + } + bool operator!=(const SSOArray &other) const + { + if (size() != other.size()) + return true; + return !std::equal(begin(), end(), other.begin()); + } +}; + +struct IdStringList +{ + SSOArray ids; +}; + struct GraphicElement { enum type_t -- cgit v1.2.3 From ff92d19fed274c6469720cc726e80dc777fa767f Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Fri, 29 Jan 2021 11:11:08 +0000 Subject: arch: Add getNameDelimiter API for string lists Signed-off-by: D. Shah --- common/arch_pybindings_shared.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'common') diff --git a/common/arch_pybindings_shared.h b/common/arch_pybindings_shared.h index 5295c6ab..1cd70c99 100644 --- a/common/arch_pybindings_shared.h +++ b/common/arch_pybindings_shared.h @@ -10,6 +10,9 @@ readonly_wrapper, conv_from_str>::def_wrap(ctx_cls, "top_module"); +fn_wrapper_0a>::def_wrap( + ctx_cls, "getNameDelimiter"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getNetByAlias"); fn_wrapper_2a_v, -- cgit v1.2.3 From 0dbe7f96a39640c42dbb2ebb41324d0edf2a5f4b Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Fri, 29 Jan 2021 11:29:32 +0000 Subject: common: First pass at IdStringList methods Signed-off-by: D. Shah --- common/nextpnr.cc | 35 +++++++++++++++++++++++++++++++++++ common/nextpnr.h | 32 +++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 9a856b99..57baedf9 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -69,6 +69,41 @@ void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx) ctx->idstring_idx_to_str->push_back(&insert_rc.first->first); } +IdStringList IdStringList::parse(Context *ctx, const std::string &str) +{ + char delim = ctx->getNameDelimiter(); + size_t id_count = std::count(str.begin(), str.end(), delim) + 1; + IdStringList list(id_count); + size_t start = 0; + for (size_t i = 0; i < id_count; i++) { + size_t end = str.find(delim, start); + NPNR_ASSERT((i == (id_count - 1)) || (end != std::string::npos)); + list.ids[i] = ctx->id(str.substr(start, end - start)); + start = end + 1; + } + return list; +} + +void IdStringList::build_str(const Context *ctx, std::string &str) const +{ + char delim = ctx->getNameDelimiter(); + bool first = true; + str.clear(); + for (auto entry : ids) { + if (!first) + str += delim; + str += entry.str(ctx); + first = false; + } +} + +std::string IdStringList::str(const Context *ctx) const +{ + std::string s; + build_str(ctx, s); + return s; +} + TimingConstrObjectId BaseCtx::timingWildcardObject() { TimingConstrObjectId id; diff --git a/common/nextpnr.h b/common/nextpnr.h index 68a341f3..66f31867 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -156,7 +156,7 @@ template class SSOArray size_t m_size; private: - inline bool is_heap() { return (m_size > N); } + inline bool is_heap() const { return (m_size > N); } void alloc() { if (is_heap()) { @@ -165,8 +165,8 @@ template class SSOArray } public: - T *data() { return is_heap() ? data_heap : &data_static; } - const T *data() const { return is_heap() ? data_heap : &data_static; } + T *data() { return is_heap() ? data_heap : data_static; } + const T *data() const { return is_heap() ? data_heap : data_static; } size_t size() const { return m_size; } T *begin() { return data(); } @@ -174,6 +174,8 @@ template class SSOArray const T *begin() const { return data(); } const T *end() const { return data() + m_size; } + SSOArray() : m_size(0){}; + SSOArray(size_t size, const T &init = T()) : m_size(size) { alloc(); @@ -205,11 +207,35 @@ template class SSOArray return true; return !std::equal(begin(), end(), other.begin()); } + T &operator[](size_t idx) + { + NPNR_ASSERT(idx < m_size); + return data()[idx]; + } + const T &operator[](size_t idx) const + { + NPNR_ASSERT(idx < m_size); + return data()[idx]; + } }; struct IdStringList { SSOArray ids; + + IdStringList(){}; + explicit IdStringList(size_t n) : ids(n, IdString()){}; + explicit IdStringList(IdString id) : ids(1, id){}; + template IdStringList(const Tlist &list) : ids(list){}; + + static IdStringList parse(Context *ctx, const std::string &str); + void build_str(const Context *ctx, std::string &str) const; + std::string str(const Context *ctx) const; + + size_t size() const { return ids.size(); } + const IdString *begin() const { return ids.begin(); } + const IdString *end() const { return ids.end(); } + const IdString &operator[](size_t idx) const { return ids[idx]; } }; struct GraphicElement -- cgit v1.2.3 From 6d23461bcd83d27c6b365948a5e85db80389832e Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Fri, 29 Jan 2021 12:12:12 +0000 Subject: ecp5: Proof-of-concept using IdStringList for bel names This uses the new IdStringList API to store bel names for the ECP5. Note that other arches and the GUI do not yet build with this proof-of-concept patch. getBelByName still uses the old implementation and could be more efficiently implemented with further development. Signed-off-by: D. Shah --- common/archcheck.cc | 4 ++-- common/nextpnr.cc | 22 +++++++++++++++++++--- common/nextpnr.h | 26 ++++++++++++++++++++++---- common/place_common.cc | 7 +++---- common/placer1.cc | 8 ++++---- common/placer_heap.cc | 4 ++-- common/timing_opt.cc | 9 ++++----- 7 files changed, 56 insertions(+), 24 deletions(-) (limited to 'common') diff --git a/common/archcheck.cc b/common/archcheck.cc index f5760c88..412feca9 100644 --- a/common/archcheck.cc +++ b/common/archcheck.cc @@ -36,10 +36,10 @@ void archcheck_names(const Context *ctx) log_info("Checking bel names..\n"); for (BelId bel : ctx->getBels()) { - IdString name = ctx->getBelName(bel); + IdStringList name = ctx->getBelName(bel); BelId bel2 = ctx->getBelByName(name); if (bel != bel2) { - log_error("bel != bel2, name = %s\n", name.c_str(ctx)); + log_error("bel != bel2, name = %s\n", ctx->nameOfBel(bel)); } } diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 57baedf9..c9084a75 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -111,6 +111,14 @@ TimingConstrObjectId BaseCtx::timingWildcardObject() return id; } +std::string &StrRingBuffer::next() +{ + std::string &s = buffer.at(index++); + if (index >= N) + index = 0; + return s; +} + TimingConstrObjectId BaseCtx::timingClockDomainObject(NetInfo *clockDomain) { NPNR_ASSERT(clockDomain->clkconstr != nullptr); @@ -283,7 +291,9 @@ void BaseCtx::removeConstraint(IdString constrName) const char *BaseCtx::nameOfBel(BelId bel) const { const Context *ctx = getCtx(); - return ctx->getBelName(bel).c_str(ctx); + std::string &s = ctx->log_strs.next(); + ctx->getBelName(bel).build_str(ctx, s); + return s.c_str(); } const char *BaseCtx::nameOfWire(WireId wire) const @@ -304,6 +314,12 @@ const char *BaseCtx::nameOfGroup(GroupId group) const return ctx->getGroupName(group).c_str(ctx); } +BelId BaseCtx::getBelByNameStr(const std::string &str) +{ + Context *ctx = getCtx(); + return ctx->getBelByName(IdStringList::parse(ctx, str)); +} + WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const { if (net_info->driver.cell == nullptr) @@ -655,7 +671,7 @@ void BaseCtx::archInfoToAttributes() if (ci->attrs.find(id("BEL")) != ci->attrs.end()) { ci->attrs.erase(ci->attrs.find(id("BEL"))); } - ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).str(this); + ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).str(getCtx()); ci->attrs[id("BEL_STRENGTH")] = (int)ci->belStrength; } if (ci->constr_x != ci->UNCONSTR) @@ -707,7 +723,7 @@ void BaseCtx::attributesToArchInfo() if (str != ci->attrs.end()) strength = (PlaceStrength)str->second.as_int64(); - BelId b = getCtx()->getBelByName(id(val->second.as_string())); + BelId b = getCtx()->getBelByNameStr(val->second.as_string()); getCtx()->bindBel(b, ci, strength); } diff --git a/common/nextpnr.h b/common/nextpnr.h index 66f31867..9523e418 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -148,14 +148,13 @@ NEXTPNR_NAMESPACE_BEGIN // An small size optimised array that is statically allocated when the size is N or less; heap allocated otherwise template class SSOArray { + private: union { T data_static[N]; T *data_heap; }; size_t m_size; - - private: inline bool is_heap() const { return (m_size > N); } void alloc() { @@ -224,8 +223,8 @@ struct IdStringList SSOArray ids; IdStringList(){}; - explicit IdStringList(size_t n) : ids(n, IdString()){}; - explicit IdStringList(IdString id) : ids(1, id){}; + IdStringList(size_t n) : ids(n, IdString()){}; + IdStringList(IdString id) : ids(1, id){}; template IdStringList(const Tlist &list) : ids(list){}; static IdStringList parse(Context *ctx, const std::string &str); @@ -238,6 +237,19 @@ struct IdStringList const IdString &operator[](size_t idx) const { return ids[idx]; } }; +// A ring buffer of strings, so we can return a simple const char * pointer for %s formatting - inspired by how logging +// in Yosys works Let's just hope noone tries to log more than 100 things in one call.... +class StrRingBuffer +{ + private: + static const size_t N = 100; + std::array buffer; + size_t index = 0; + + public: + std::string &next(); +}; + struct GraphicElement { enum type_t @@ -760,6 +772,9 @@ struct BaseCtx mutable std::unordered_map *idstring_str_to_idx; mutable std::vector *idstring_idx_to_str; + // Temporary string backing store for logging + mutable StrRingBuffer log_strs; + // Project settings and config switches std::unordered_map settings; @@ -875,6 +890,9 @@ struct BaseCtx const char *nameOfPip(PipId pip) const; const char *nameOfGroup(GroupId group) const; + // Overrides of arch functions that take a string and handle IdStringList parsing + BelId getBelByNameStr(const std::string &str); + // -------------------------------------------------------------- bool allUiReload = true; diff --git a/common/place_common.cc b/common/place_common.cc index 3f89169a..6526c38e 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -158,8 +158,7 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) all_placed = true; } if (ctx->verbose) - log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx), - ctx->getBelName(best_bel).c_str(ctx)); + log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx), ctx->nameOfBel(best_bel)); ctx->bindBel(best_bel, cell, STRENGTH_WEAK); cell = ripup_target; @@ -375,7 +374,7 @@ class ConstraintLegaliseWorker if (confl_cell != nullptr) { if (ctx->verbose) log_info(" '%s' already placed at '%s'\n", ctx->nameOf(confl_cell), - ctx->getBelName(confl_cell->bel).c_str(ctx)); + ctx->nameOfBel(confl_cell->bel)); NPNR_ASSERT(confl_cell->belStrength < STRENGTH_STRONG); ctx->unbindBel(target); rippedCells.insert(confl_cell->name); @@ -489,7 +488,7 @@ class ConstraintLegaliseWorker for (auto cell : sorted(ctx->cells)) if (get_constraints_distance(ctx, cell.second) != 0) log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx), - ctx->getBelName(cell.second->bel).c_str(ctx)); + ctx->nameOfBel(cell.second->bel)); return score; } }; diff --git a/common/placer1.cc b/common/placer1.cc index 1c039090..c54c3cf2 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -154,7 +154,7 @@ class SAPlacer auto loc = cell->attrs.find(ctx->id("BEL")); if (loc != cell->attrs.end()) { std::string loc_name = loc->second.as_string(); - BelId bel = ctx->getBelByName(ctx->id(loc_name)); + BelId bel = ctx->getBelByNameStr(loc_name); if (bel == BelId()) { log_error("No Bel named \'%s\' located for " "this chip (processing BEL attribute on \'%s\')\n", @@ -409,18 +409,18 @@ class SAPlacer if (ctx->force) { log_warning("post-placement validity check failed for Bel '%s' " "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + ctx->nameOfBel(bel), cell_text.c_str()); } else { log_error("post-placement validity check failed for Bel '%s' " "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + ctx->nameOfBel(bel), cell_text.c_str()); } } } for (auto cell : sorted(ctx->cells)) if (get_constraints_distance(ctx, cell.second) != 0) log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx), - ctx->getBelName(cell.second->bel).c_str(ctx)); + ctx->nameOfBel(cell.second->bel)); timing_analysis(ctx); ctx->unlock(); return true; diff --git a/common/placer_heap.cc b/common/placer_heap.cc index d149a5b0..7882c8da 100644 --- a/common/placer_heap.cc +++ b/common/placer_heap.cc @@ -305,7 +305,7 @@ class HeAPPlacer if (ctx->getBoundBelCell(cell.second->bel) != cell.second) log_error("Found cell %s with mismatched binding\n", cell.first.c_str(ctx)); if (ctx->debug) - log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->getBelName(cell.second->bel).c_str(ctx)); + log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel)); } ctx->unlock(); @@ -379,7 +379,7 @@ class HeAPPlacer auto loc = cell->attrs.find(ctx->id("BEL")); if (loc != cell->attrs.end()) { std::string loc_name = loc->second.as_string(); - BelId bel = ctx->getBelByName(ctx->id(loc_name)); + BelId bel = ctx->getBelByNameStr(loc_name); if (bel == BelId()) { log_error("No Bel named \'%s\' located for " "this chip (processing BEL attribute on \'%s\')\n", diff --git a/common/timing_opt.cc b/common/timing_opt.cc index 025084b7..7ee7b805 100644 --- a/common/timing_opt.cc +++ b/common/timing_opt.cc @@ -427,7 +427,7 @@ class TimingOptimiser if (pn->users.at(i).cell == port->cell && pn->users.at(i).port == port->port) crit = net_crit.at(pn->name).criticality.at(i); log_info(" %s.%s at %s crit %0.02f\n", port->cell->name.c_str(ctx), port->port.c_str(ctx), - ctx->getBelName(port->cell->bel).c_str(ctx), crit); + ctx->nameOfBel(port->cell->bel), crit); } if (std::find(path_cells.begin(), path_cells.end(), port->cell->name) != path_cells.end()) continue; @@ -472,10 +472,9 @@ class TimingOptimiser if (ctx->debug) { for (auto cell : path_cells) { - log_info("Candidate neighbours for %s (%s):\n", cell.c_str(ctx), - ctx->getBelName(ctx->cells[cell]->bel).c_str(ctx)); + log_info("Candidate neighbours for %s (%s):\n", cell.c_str(ctx), ctx->nameOfBel(ctx->cells[cell]->bel)); for (auto neigh : cell_neighbour_bels.at(cell)) { - log_info(" %s\n", ctx->getBelName(neigh).c_str(ctx)); + log_info(" %s\n", ctx->nameOfBel(neigh)); } } } @@ -597,7 +596,7 @@ class TimingOptimiser CellInfo *cell = ctx->cells.at(rt_entry.first).get(); cell_swap_bel(cell, rt_entry.second); if (ctx->debug) - log_info(" %s at %s\n", rt_entry.first.c_str(ctx), ctx->getBelName(rt_entry.second).c_str(ctx)); + log_info(" %s at %s\n", rt_entry.first.c_str(ctx), ctx->nameOfBel(rt_entry.second)); } } else { -- cgit v1.2.3 From 9388df19d3ab3ca1b127defafe6fa3f71147f451 Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Fri, 29 Jan 2021 12:58:41 +0000 Subject: refactor: Replace getXName().c_str(ctx) with ctx->nameOfX This makes the ongoing migration to IdStringList easier. Signed-off-by: D. Shah --- common/archcheck.cc | 8 ++++---- common/placer1.cc | 6 +++--- common/timing.cc | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'common') diff --git a/common/archcheck.cc b/common/archcheck.cc index 412feca9..6efa3a1e 100644 --- a/common/archcheck.cc +++ b/common/archcheck.cc @@ -48,7 +48,7 @@ void archcheck_names(const Context *ctx) IdString name = ctx->getWireName(wire); WireId wire2 = ctx->getWireByName(name); if (wire != wire2) { - log_error("wire != wire2, name = %s\n", name.c_str(ctx)); + log_error("wire != wire2, name = %s\n", ctx->nameOfWire(wire)); } } @@ -67,7 +67,7 @@ void archcheck_names(const Context *ctx) IdString name = ctx->getPipName(pip); PipId pip2 = ctx->getPipByName(name); if (pip != pip2) { - log_error("pip != pip2, name = %s\n", name.c_str(ctx)); + log_error("pip != pip2, name = %s\n", ctx->nameOfPip(pip)); } } #endif @@ -109,7 +109,7 @@ void archcheck_locs(const Context *ctx) if (bel == BelId()) continue; Loc loc = ctx->getBelLocation(bel); - dbg(" + %d %s\n", z, ctx->getBelName(bel).c_str(ctx)); + dbg(" + %d %s\n", z, ctx->nameOfBel(bel)); log_assert(x == loc.x); log_assert(y == loc.y); log_assert(z == loc.z); @@ -118,7 +118,7 @@ void archcheck_locs(const Context *ctx) for (BelId bel : ctx->getBelsByTile(x, y)) { Loc loc = ctx->getBelLocation(bel); - dbg(" - %d %s\n", loc.z, ctx->getBelName(bel).c_str(ctx)); + dbg(" - %d %s\n", loc.z, ctx->nameOfBel(bel)); log_assert(x == loc.x); log_assert(y == loc.y); log_assert(usedz.count(loc.z)); diff --git a/common/placer1.cc b/common/placer1.cc index c54c3cf2..280dd02e 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -563,9 +563,9 @@ class SAPlacer } commit_cost_changes(moveChange); #if 0 - log_info("swap %s -> %s\n", cell->name.c_str(ctx), ctx->getBelName(newBel).c_str(ctx)); + log_info("swap %s -> %s\n", cell->name.c_str(ctx), ctx->nameOfBel(newBel)); if (other_cell != nullptr) - log_info("swap %s -> %s\n", other_cell->name.c_str(ctx), ctx->getBelName(oldBel).c_str(ctx)); + log_info("swap %s -> %s\n", other_cell->name.c_str(ctx), ctx->nameOfBel(oldBel)); #endif return true; swap_fail: @@ -590,7 +590,7 @@ class SAPlacer { BelId oldBel = cell->bel; #if 0 - log_info("%s old: %s new: %s\n", cell->name.c_str(ctx), ctx->getBelName(cell->bel).c_str(ctx), ctx->getBelName(newBel).c_str(ctx)); + log_info("%s old: %s new: %s\n", cell->name.c_str(ctx), ctx->nameOfBel(cell->bel), ctx->nameOfBel(newBel)); #endif CellInfo *bound = ctx->getBoundBelCell(newBel); if (bound != nullptr) diff --git a/common/timing.cc b/common/timing.cc index d8445989..9fb14a33 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -885,8 +885,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p auto pip = it->second.pip; NPNR_ASSERT(pip != PipId()); delay = ctx->getPipDelay(pip).maxDelay(); - log_info(" %1.3f %s\n", ctx->getDelayNS(delay), - ctx->getPipName(pip).c_str(ctx)); + log_info(" %1.3f %s\n", ctx->getDelayNS(delay), ctx->nameOfPip(pip)); cursor = ctx->getPipSrcWire(pip); } } -- cgit v1.2.3 From d792bce0fb03529ee57b6f6ed5b0c234f503e452 Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Fri, 29 Jan 2021 13:30:56 +0000 Subject: ecp5: Implement IdStringList for all arch object names This is a complete implementation of IdStringList for ECP5; excluding the GUI (which you will have to disable for it to build). Signed-off-by: D. Shah --- common/archcheck.cc | 4 ++-- common/nextpnr.cc | 34 +++++++++++++++++++++++++++++----- common/nextpnr.h | 25 ++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/archcheck.cc b/common/archcheck.cc index 6efa3a1e..28b0c147 100644 --- a/common/archcheck.cc +++ b/common/archcheck.cc @@ -45,7 +45,7 @@ void archcheck_names(const Context *ctx) log_info("Checking wire names..\n"); for (WireId wire : ctx->getWires()) { - IdString name = ctx->getWireName(wire); + IdStringList name = ctx->getWireName(wire); WireId wire2 = ctx->getWireByName(name); if (wire != wire2) { log_error("wire != wire2, name = %s\n", ctx->nameOfWire(wire)); @@ -64,7 +64,7 @@ void archcheck_names(const Context *ctx) #ifndef ARCH_ECP5 log_info("Checking pip names..\n"); for (PipId pip : ctx->getPips()) { - IdString name = ctx->getPipName(pip); + IdStringList name = ctx->getPipName(pip); PipId pip2 = ctx->getPipByName(name); if (pip != pip2) { log_error("pip != pip2, name = %s\n", ctx->nameOfPip(pip)); diff --git a/common/nextpnr.cc b/common/nextpnr.cc index c9084a75..f7f368f1 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -299,19 +299,25 @@ const char *BaseCtx::nameOfBel(BelId bel) const const char *BaseCtx::nameOfWire(WireId wire) const { const Context *ctx = getCtx(); - return ctx->getWireName(wire).c_str(ctx); + std::string &s = ctx->log_strs.next(); + ctx->getWireName(wire).build_str(ctx, s); + return s.c_str(); } const char *BaseCtx::nameOfPip(PipId pip) const { const Context *ctx = getCtx(); - return ctx->getPipName(pip).c_str(ctx); + std::string &s = ctx->log_strs.next(); + ctx->getPipName(pip).build_str(ctx, s); + return s.c_str(); } const char *BaseCtx::nameOfGroup(GroupId group) const { const Context *ctx = getCtx(); - return ctx->getGroupName(group).c_str(ctx); + std::string &s = ctx->log_strs.next(); + ctx->getGroupName(group).build_str(ctx, s); + return s.c_str(); } BelId BaseCtx::getBelByNameStr(const std::string &str) @@ -320,6 +326,24 @@ BelId BaseCtx::getBelByNameStr(const std::string &str) return ctx->getBelByName(IdStringList::parse(ctx, str)); } +WireId BaseCtx::getWireByNameStr(const std::string &str) +{ + Context *ctx = getCtx(); + return ctx->getWireByName(IdStringList::parse(ctx, str)); +} + +PipId BaseCtx::getPipByNameStr(const std::string &str) +{ + Context *ctx = getCtx(); + return ctx->getPipByName(IdStringList::parse(ctx, str)); +} + +GroupId BaseCtx::getGroupByNameStr(const std::string &str) +{ + Context *ctx = getCtx(); + return ctx->getGroupByName(IdStringList::parse(ctx, str)); +} + WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const { if (net_info->driver.cell == nullptr) @@ -701,10 +725,10 @@ void BaseCtx::archInfoToAttributes() for (auto &item : ni->wires) { if (!first) routing += ";"; - routing += getCtx()->getWireName(item.first).c_str(this); + routing += getCtx()->getWireName(item.first).str(getCtx()); routing += ";"; if (item.second.pip != PipId()) - routing += getCtx()->getPipName(item.second.pip).c_str(this); + routing += getCtx()->getPipName(item.second.pip).str(getCtx()); routing += ";" + std::to_string(item.second.strength); first = false; } diff --git a/common/nextpnr.h b/common/nextpnr.h index 9523e418..19d919e1 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -235,8 +235,28 @@ struct IdStringList const IdString *begin() const { return ids.begin(); } const IdString *end() const { return ids.end(); } const IdString &operator[](size_t idx) const { return ids[idx]; } + bool operator==(const IdStringList &other) const { return ids == other.ids; } + bool operator!=(const IdStringList &other) const { return ids != other.ids; } }; +NEXTPNR_NAMESPACE_END + +namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdStringList &obj) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(obj.size())); + for (auto &id : obj) + boost::hash_combine(seed, hash()(id)); + return seed; + } +}; +} // namespace std + +NEXTPNR_NAMESPACE_BEGIN + // A ring buffer of strings, so we can return a simple const char * pointer for %s formatting - inspired by how logging // in Yosys works Let's just hope noone tries to log more than 100 things in one call.... class StrRingBuffer @@ -890,8 +910,11 @@ struct BaseCtx const char *nameOfPip(PipId pip) const; const char *nameOfGroup(GroupId group) const; - // Overrides of arch functions that take a string and handle IdStringList parsing + // Wrappers of arch functions that take a string and handle IdStringList parsing BelId getBelByNameStr(const std::string &str); + WireId getWireByNameStr(const std::string &str); + PipId getPipByNameStr(const std::string &str); + GroupId getGroupByNameStr(const std::string &str); // -------------------------------------------------------------- -- cgit v1.2.3 From 6566a011b43289b9b550f3b7f8801156275cb321 Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Mon, 1 Feb 2021 11:46:10 +0000 Subject: nexus: Implement IdStringList for all arch object names Signed-off-by: D. Shah --- common/nextpnr.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'common') diff --git a/common/nextpnr.h b/common/nextpnr.h index 19d919e1..d4db9e9e 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -181,6 +181,12 @@ template class SSOArray std::fill(begin(), end(), init); } + SSOArray(const SSOArray &other) : m_size(other.size()) + { + alloc(); + std::copy(other.begin(), other.end(), begin()); + } + template SSOArray(const Tother &other) : m_size(other.size()) { alloc(); -- cgit v1.2.3 From 7cff69f9453e0c95f8eb9a12b004afa20b69501e Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Tue, 2 Feb 2021 14:48:29 +0000 Subject: generic: Use IdStringList for all arch object names Signed-off-by: D. Shah --- common/nextpnr.h | 15 +++++++++++++++ common/pybindings.h | 12 ++++++++++++ common/timing_opt.cc | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/nextpnr.h b/common/nextpnr.h index d4db9e9e..78bbf66e 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -243,6 +243,21 @@ struct IdStringList const IdString &operator[](size_t idx) const { return ids[idx]; } bool operator==(const IdStringList &other) const { return ids == other.ids; } bool operator!=(const IdStringList &other) const { return ids != other.ids; } + bool operator<(const IdStringList &other) const + { + if (size() > other.size()) + return false; + if (size() < other.size()) + return true; + for (size_t i = 0; i < size(); i++) { + IdString a = ids[i], b = other[i]; + if (a.index < b.index) + return true; + if (a.index > b.index) + return false; + } + return false; + } }; NEXTPNR_NAMESPACE_END diff --git a/common/pybindings.h b/common/pybindings.h index e50ffd1b..3e33a374 100644 --- a/common/pybindings.h +++ b/common/pybindings.h @@ -74,6 +74,18 @@ template <> struct string_converter inline std::string to_str(Context *ctx, IdString id) { return id.str(ctx); } }; +template <> struct string_converter +{ + IdStringList from_str(Context *ctx, std::string name) { return IdStringList::parse(ctx, name); } + std::string to_str(Context *ctx, const IdStringList &id) { return id.str(ctx); } +}; + +template <> struct string_converter +{ + IdStringList from_str(Context *ctx, std::string name) { return IdStringList::parse(ctx, name); } + std::string to_str(Context *ctx, const IdStringList &id) { return id.str(ctx); } +}; + } // namespace PythonConversion NEXTPNR_NAMESPACE_END diff --git a/common/timing_opt.cc b/common/timing_opt.cc index 7ee7b805..9c601e48 100644 --- a/common/timing_opt.cc +++ b/common/timing_opt.cc @@ -59,7 +59,7 @@ template <> struct hash> return seed; } }; -#if !defined(ARCH_GENERIC) && !defined(ARCH_GOWIN) +#if !defined(ARCH_GOWIN) template <> struct hash> { std::size_t -- cgit v1.2.3