diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/arch_pybindings_shared.h | 3 | ||||
-rw-r--r-- | common/archcheck.cc | 16 | ||||
-rw-r--r-- | common/nextpnr.cc | 91 | ||||
-rw-r--r-- | common/nextpnr.h | 155 | ||||
-rw-r--r-- | common/place_common.cc | 7 | ||||
-rw-r--r-- | common/placer1.cc | 14 | ||||
-rw-r--r-- | common/placer_heap.cc | 4 | ||||
-rw-r--r-- | common/pybindings.h | 12 | ||||
-rw-r--r-- | common/timing.cc | 3 | ||||
-rw-r--r-- | common/timing_opt.cc | 11 |
10 files changed, 279 insertions, 37 deletions
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<Context, decltype(&Context::hierarchy), &Context::hierarchy, wr readwrite_wrapper<Context, decltype(&Context::top_module), &Context::top_module, conv_to_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "top_module"); +fn_wrapper_0a<Context, decltype(&Context::getNameDelimiter), &Context::getNameDelimiter, pass_through<char>>::def_wrap( + ctx_cls, "getNameDelimiter"); + fn_wrapper_1a<Context, decltype(&Context::getNetByAlias), &Context::getNetByAlias, deref_and_wrap<NetInfo>, conv_from_str<IdString>>::def_wrap(ctx_cls, "getNetByAlias"); fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>, diff --git a/common/archcheck.cc b/common/archcheck.cc index f5760c88..28b0c147 100644 --- a/common/archcheck.cc +++ b/common/archcheck.cc @@ -36,19 +36,19 @@ 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)); } } 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", name.c_str(ctx)); + log_error("wire != wire2, name = %s\n", ctx->nameOfWire(wire)); } } @@ -64,10 +64,10 @@ 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", 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/nextpnr.cc b/common/nextpnr.cc index 9a856b99..f7f368f1 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; @@ -76,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); @@ -248,25 +291,57 @@ 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 { 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) +{ + Context *ctx = getCtx(); + 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 @@ -620,7 +695,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) @@ -650,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; } @@ -672,7 +747,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 b4f68f93..78bbf66e 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -145,6 +145,152 @@ template <> struct hash<NEXTPNR_NAMESPACE_PREFIX IdString> NEXTPNR_NAMESPACE_BEGIN +// An small size optimised array that is statically allocated when the size is N or less; heap allocated otherwise +template <typename T, size_t N> class SSOArray +{ + private: + union + { + T data_static[N]; + T *data_heap; + }; + size_t m_size; + inline bool is_heap() const { 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() : m_size(0){}; + + SSOArray(size_t size, const T &init = T()) : m_size(size) + { + alloc(); + std::fill(begin(), end(), init); + } + + SSOArray(const SSOArray &other) : m_size(other.size()) + { + alloc(); + std::copy(other.begin(), other.end(), begin()); + } + + template <typename Tother> 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()); + } + 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<IdString, 4> ids; + + IdStringList(){}; + IdStringList(size_t n) : ids(n, IdString()){}; + IdStringList(IdString id) : ids(1, id){}; + template <typename Tlist> 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]; } + 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 + +namespace std { +template <> struct hash<NEXTPNR_NAMESPACE_PREFIX IdStringList> +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdStringList &obj) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, hash<size_t>()(obj.size())); + for (auto &id : obj) + boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(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 +{ + private: + static const size_t N = 100; + std::array<std::string, N> buffer; + size_t index = 0; + + public: + std::string &next(); +}; + struct GraphicElement { enum type_t @@ -667,6 +813,9 @@ struct BaseCtx mutable std::unordered_map<std::string, int> *idstring_str_to_idx; mutable std::vector<const std::string *> *idstring_idx_to_str; + // Temporary string backing store for logging + mutable StrRingBuffer log_strs; + // Project settings and config switches std::unordered_map<IdString, Property> settings; @@ -782,6 +931,12 @@ struct BaseCtx const char *nameOfPip(PipId pip) const; const char *nameOfGroup(GroupId group) const; + // 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); + // -------------------------------------------------------------- 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..280dd02e 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; @@ -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/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/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<const IdString> inline std::string to_str(Context *ctx, IdString id) { return id.str(ctx); } }; +template <> struct string_converter<IdStringList> +{ + 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<const IdStringList> +{ + 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.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); } } diff --git a/common/timing_opt.cc b/common/timing_opt.cc index 025084b7..9c601e48 100644 --- a/common/timing_opt.cc +++ b/common/timing_opt.cc @@ -59,7 +59,7 @@ template <> struct hash<std::pair<int, NEXTPNR_NAMESPACE_PREFIX BelId>> return seed; } }; -#if !defined(ARCH_GENERIC) && !defined(ARCH_GOWIN) +#if !defined(ARCH_GOWIN) template <> struct hash<std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, NEXTPNR_NAMESPACE_PREFIX BelId>> { std::size_t @@ -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 { |