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 ++++----- ecp5/arch.cc | 15 ++++++++++++--- ecp5/arch.h | 13 ++++++++----- ecp5/arch_pybindings.h | 2 +- ecp5/globals.cc | 6 +++--- ecp5/pack.cc | 46 +++++++++++++++++++++------------------------- 12 files changed, 101 insertions(+), 61 deletions(-) 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 { diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 25f95c53..928a9c5f 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -128,6 +128,11 @@ Arch::Arch(ArchArgs args) : args(args) bucket.name = bel_type; buckets.push_back(bucket); } + + for (int i = 0; i < chip_info->width; i++) + x_ids.push_back(id(stringf("X%d", i))); + for (int i = 0; i < chip_info->height; i++) + y_ids.push_back(id(stringf("Y%d", i))); } // ----------------------------------------------------------------------- @@ -208,16 +213,18 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- -BelId Arch::getBelByName(IdString name) const +BelId Arch::getBelByName(IdStringList name) const { + // TODO: take advantage of IdStringList for fast parsing BelId ret; +#if 0 auto it = bel_by_name.find(name); if (it != bel_by_name.end()) return it->second; - +#endif Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(getCtx())); ret.location = loc; const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < int(loci->bel_data.size()); i++) { @@ -226,8 +233,10 @@ BelId Arch::getBelByName(IdString name) const break; } } +#if 0 if (ret.index >= 0) bel_by_name[name] = ret; +#endif return ret; } diff --git a/ecp5/arch.h b/ecp5/arch.h index 6b32f284..303d9afe 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -450,6 +450,9 @@ struct Arch : BaseCtx std::unordered_map pip_to_net; std::unordered_map wire_fanout; + // fast access to X and Y IdStrings for building object names + std::vector x_ids, y_ids; + ArchArgs args; Arch(ArchArgs args); @@ -475,19 +478,19 @@ struct Arch : BaseCtx // ------------------------------------------------- - BelId getBelByName(IdString name) const; + BelId getBelByName(IdStringList name) const; template const LocationTypePOD *locInfo(Id &id) const { return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); } - IdString getBelName(BelId bel) const + IdStringList getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - std::stringstream name; - name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << locInfo(bel)->bel_data[bel.index].name.get(); - return id(name.str()); + std::array ids{x_ids.at(bel.location.x), y_ids.at(bel.location.y), + id(locInfo(bel)->bel_data[bel.index].name.get())}; + return IdStringList(ids); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h index dd3161ae..90c7c757 100644 --- a/ecp5/arch_pybindings.h +++ b/ecp5/arch_pybindings.h @@ -30,7 +30,7 @@ namespace PythonConversion { template <> struct string_converter { - BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByNameStr(name); } std::string to_str(Context *ctx, BelId id) { diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 218090e1..ad99272e 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -176,8 +176,8 @@ class Ecp5GlobalRouter } } if (upstream.size() > 30000) { - log_error("failed to route HPBX%02d00 to %s.%s\n", global_index, - ctx->getBelName(user.cell->bel).c_str(ctx), user.port.c_str(ctx)); + log_error("failed to route HPBX%02d00 to %s.%s\n", global_index, ctx->nameOfBel(user.cell->bel), + user.port.c_str(ctx)); } } // Set all the pips we found along the way @@ -300,7 +300,7 @@ class Ecp5GlobalRouter if (drv.cell == nullptr) { return 0; } else if (drv.cell->attrs.count(ctx->id("BEL"))) { - drv_bel = ctx->getBelByName(ctx->id(drv.cell->attrs.at(ctx->id("BEL")).as_string())); + drv_bel = ctx->getBelByNameStr(drv.cell->attrs.at(ctx->id("BEL")).as_string()); } else { // Check if driver is a singleton BelId last_bel; diff --git a/ecp5/pack.cc b/ecp5/pack.cc index b60d6c7d..8d21c5b3 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -522,7 +522,7 @@ class Ecp5Packer trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str()); } else { log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx), - ctx->getBelName(pinBel).c_str(ctx)); + ctx->nameOfBel(pinBel)); } trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx); } @@ -1657,7 +1657,7 @@ class Ecp5Packer CellInfo *dcu = clki->driver.cell; if (!dcu->attrs.count(ctx->id("BEL"))) log_error("DCU must be constrained to a Bel!\n"); - BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL")).as_string())); + BelId bel = ctx->getBelByNameStr(dcu->attrs.at(ctx->id("BEL")).as_string()); if (bel == BelId()) log_error("Invalid DCU bel '%s'\n", dcu->attrs.at(ctx->id("BEL")).c_str()); Loc loc = ctx->getBelLocation(bel); @@ -1704,7 +1704,7 @@ class Ecp5Packer for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL"))) - available_plls.erase(ctx->getBelByName(ctx->id(ci->attrs.at(ctx->id("BEL")).as_string()))); + available_plls.erase(ctx->getBelByNameStr(ci->attrs.at(ctx->id("BEL")).as_string())); } // Place PLL connected to fixed drivers such as IO close to their source for (auto cell : sorted(ctx->cells)) { @@ -1716,7 +1716,7 @@ class Ecp5Packer const CellInfo *drivercell = drivernet->driver.cell; if (!drivercell->attrs.count(ctx->id("BEL"))) continue; - BelId drvbel = ctx->getBelByName(ctx->id(drivercell->attrs.at(ctx->id("BEL")).as_string())); + BelId drvbel = ctx->getBelByNameStr(drivercell->attrs.at(ctx->id("BEL")).as_string()); Loc drvloc = ctx->getBelLocation(drvbel); BelId closest_pll; int closest_distance = std::numeric_limits::max(); @@ -1848,8 +1848,8 @@ class Ecp5Packer WireId next; while (true) { if (upstream.empty() || upstream.size() > 30000) - log_error("failed to route bank %d ECLK%d to %s.%s\n", bank, found_eclk, - ctx->getBelName(usr_bel).c_str(ctx), usr_port.name.c_str(ctx)); + log_error("failed to route bank %d ECLK%d to %s.%s\n", bank, found_eclk, ctx->nameOfBel(usr_bel), + usr_port.name.c_str(ctx)); next = upstream.front(); upstream.pop(); if (ctx->debug) @@ -1913,17 +1913,17 @@ class Ecp5Packer log_error("DQSBUFM can only be used with a pin-constrained PIO connected to its DQSI input" "(while processing '%s').\n", ci->name.c_str(ctx)); - BelId pio_bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())); + BelId pio_bel = ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string()); NPNR_ASSERT(pio_bel != BelId()); Loc pio_loc = ctx->getBelLocation(pio_bel); if (pio_loc.z != 0) log_error("PIO '%s' does not appear to be a DQS site (expecting an 'A' pin).\n", - ctx->getBelName(pio_bel).c_str(ctx)); + ctx->nameOfBel(pio_bel)); pio_loc.z = 8; BelId dqsbuf = ctx->getBelByLocation(pio_loc); if (dqsbuf == BelId() || ctx->getBelType(dqsbuf) != id_DQSBUFM) log_error("PIO '%s' does not appear to be a DQS site (didn't find a DQSBUFM).\n", - ctx->getBelName(pio_bel).c_str(ctx)); + ctx->nameOfBel(pio_bel)); ci->attrs[ctx->id("BEL")] = ctx->getBelName(dqsbuf).str(ctx); bool got_dqsg = ctx->getPIODQSGroup(pio_bel, dqsbuf_dqsg[ci->name].first, dqsbuf_dqsg[ci->name].second); NPNR_ASSERT(got_dqsg); @@ -2078,15 +2078,14 @@ class Ecp5Packer log_error("IOLOGIC functionality (DDR, DELAY, DQS, etc) can only be used with pin-constrained PIO " "(while processing '%s').\n", curr->name.c_str(ctx)); - BelId bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())); + BelId bel = ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string()); NPNR_ASSERT(bel != BelId()); return bel; }; auto create_pio_iologic = [&](CellInfo *pio, CellInfo *curr) { BelId bel = get_pio_bel(pio, curr); - log_info("IOLOGIC component %s connected to PIO Bel %s\n", curr->name.c_str(ctx), - ctx->getBelName(bel).c_str(ctx)); + log_info("IOLOGIC component %s connected to PIO Bel %s\n", curr->name.c_str(ctx), ctx->nameOfBel(bel)); Loc loc = ctx->getBelLocation(bel); bool s = false; if (loc.y == 0 || loc.y == (ctx->chip_info->height - 1)) @@ -2292,8 +2291,7 @@ class Ecp5Packer replace_port(ci, ctx->id("D2"), iol, id_TXDATA2); replace_port(ci, ctx->id("D3"), iol, id_TXDATA3); if (ci->type == ctx->id("ODDR71B")) { - Loc loc = - ctx->getBelLocation(ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string()))); + Loc loc = ctx->getBelLocation(ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string())); if (loc.z % 2 == 1) log_error("ODDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx)); replace_port(ci, ctx->id("D4"), iol, id_TXDATA4); @@ -2326,8 +2324,7 @@ class Ecp5Packer replace_port(ci, ctx->id("Q2"), iol, id_RXDATA2); replace_port(ci, ctx->id("Q3"), iol, id_RXDATA3); if (ci->type == ctx->id("IDDR71B")) { - Loc loc = - ctx->getBelLocation(ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string()))); + Loc loc = ctx->getBelLocation(ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string())); if (loc.z % 2 == 1) log_error("IDDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx)); replace_port(ci, ctx->id("Q4"), iol, id_RXDATA4); @@ -2579,7 +2576,7 @@ class Ecp5Packer if (!user.cell->attrs.count(ctx->id("BEL"))) continue; Loc user_loc = ctx->getBelLocation( - ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL")).as_string()))); + ctx->getBelByNameStr(user.cell->attrs.at(ctx->id("BEL")).as_string())); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != id_ECLKBRIDGECS) continue; @@ -2594,8 +2591,8 @@ class Ecp5Packer CellInfo *drv = input->driver.cell; if (!drv->attrs.count(ctx->id("BEL"))) continue; - Loc drv_loc = ctx->getBelLocation( - ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string()))); + Loc drv_loc = + ctx->getBelLocation(ctx->getBelByNameStr(drv->attrs.at(ctx->id("BEL")).as_string())); BelId closest; int closest_x = -1; // aim for same side of chip for (auto bel : ctx->getBels()) { @@ -2639,7 +2636,7 @@ class Ecp5Packer if (ci->type == id_IOLOGIC || ci->type == id_DQSBUFM) { if (!ci->ports.count(id_ECLK) || ci->ports.at(id_ECLK).net == nullptr) continue; - BelId bel = ctx->getBelByName(ctx->id(str_or_default(ci->attrs, ctx->id("BEL")))); + BelId bel = ctx->getBelByNameStr(str_or_default(ci->attrs, ctx->id("BEL"))); NPNR_ASSERT(bel != BelId()); Loc pioLoc = ctx->getBelLocation(bel); if (ci->type == id_DQSBUFM) @@ -2683,8 +2680,7 @@ class Ecp5Packer const NetInfo *eclko = net_or_nullptr(ci, id_ECLKO); if (eclki != nullptr && eclki->driver.cell != nullptr) { if (eclki->driver.cell->type == id_ECLKBRIDGECS) { - BelId bel = - ctx->getBelByName(ctx->id(eclki->driver.cell->attrs.at(ctx->id("BEL")).as_string())); + BelId bel = ctx->getBelByNameStr(eclki->driver.cell->attrs.at(ctx->id("BEL")).as_string()); Loc loc = ctx->getBelLocation(bel); ci->attrs[ctx->id("BEL")] = ctx->getBelName(ctx->getBelByLocation(Loc(loc.x, loc.y, 15))).str(ctx); @@ -2697,7 +2693,7 @@ class Ecp5Packer for (auto user : eclko->users) { if (user.cell->type == id_TRELLIS_ECLKBUF) { Loc eckbuf_loc = ctx->getBelLocation( - ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL")).as_string()))); + ctx->getBelByNameStr(user.cell->attrs.at(ctx->id("BEL")).as_string())); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != id_ECLKSYNCB) continue; @@ -2726,7 +2722,7 @@ class Ecp5Packer const CellInfo *uc = usr.cell; if (uc->type != id_DQSBUFM || !uc->attrs.count(ctx->id("BEL"))) continue; - BelId dqsb_bel = ctx->getBelByName(ctx->id(uc->attrs.at(ctx->id("BEL")).as_string())); + BelId dqsb_bel = ctx->getBelByNameStr(uc->attrs.at(ctx->id("BEL")).as_string()); Loc dqsb_loc = ctx->getBelLocation(dqsb_bel); if (dqsb_loc.x > 15) right_bank_users = true; @@ -2809,7 +2805,7 @@ class Ecp5Packer CellInfo *drv = clki->driver.cell; if (drv->type != id_ECLKSYNCB || !drv->attrs.count(ctx->id("BEL"))) continue; - BelId bel = ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string())); + BelId bel = ctx->getBelByNameStr(drv->attrs.at(ctx->id("BEL")).as_string()); // Find a CLKDIVF that is routeable from the ECLKSYNC std::queue visit; visit.push(ctx->getBelPinWire(bel, id_ECLKO)); -- cgit v1.2.3