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 --- ecp5/arch.h | 1 + 1 file changed, 1 insertion(+) (limited to 'ecp5') diff --git a/ecp5/arch.h b/ecp5/arch.h index 18a70fe8..6b32f284 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -471,6 +471,7 @@ struct Arch : BaseCtx int getGridDimY() const { return chip_info->height; }; int getTileBelDimZ(int, int) const { return max_loc_bels; }; int getTilePipDimZ(int, int) const { return 1; }; + char getNameDelimiter() const { return '/'; } // ------------------------------------------------- -- 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 --- ecp5/arch.cc | 15 ++++++++++++--- ecp5/arch.h | 13 ++++++++----- ecp5/arch_pybindings.h | 2 +- ecp5/globals.cc | 6 +++--- ecp5/pack.cc | 46 +++++++++++++++++++++------------------------- 5 files changed, 45 insertions(+), 37 deletions(-) (limited to 'ecp5') 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 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 --- ecp5/globals.cc | 13 ++++++------- ecp5/pack.cc | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'ecp5') diff --git a/ecp5/globals.cc b/ecp5/globals.cc index ad99272e..478e5fac 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -238,8 +238,7 @@ class Ecp5GlobalRouter if (visit.empty() || visit.size() > 50000) { if (allow_fail) return false; - log_error("cannot route global from %s to %s.\n", ctx->getWireName(src).c_str(ctx), - ctx->getWireName(dst).c_str(ctx)); + log_error("cannot route global from %s to %s.\n", ctx->nameOfWire(src), ctx->nameOfWire(dst)); } cursor = visit.front(); visit.pop(); @@ -325,8 +324,8 @@ class Ecp5GlobalRouter } else { // Check for dedicated routing if (has_short_route(ctx->getBelPinWire(drv_bel, drv.port), ctx->getBelPinWire(dcc->bel, id_CLKI))) { - // log_info("dedicated route %s -> %s\n", ctx->getWireName(ctx->getBelPinWire(drv_bel, - // drv.port)).c_str(ctx), ctx->getBelName(dcc->bel).c_str(ctx)); + // log_info("dedicated route %s -> %s\n", ctx->nameOfWire(ctx->getBelPinWire(drv_bel, + // drv.port)), ctx->nameOfWire(dcc->bel)); dedicated_routing = true; return 0; } @@ -347,8 +346,8 @@ class Ecp5GlobalRouter while (true) { if (visit.empty() || visit.size() > 10000) { - // log_info ("dist %s -> %s = inf\n", ctx->getWireName(src).c_str(ctx), - // ctx->getWireName(dst).c_str(ctx)); + // log_info ("dist %s -> %s = inf\n", ctx->nameOfWire(src), + // ctx->nameOfWire(dst)); return false; } cursor = visit.front(); @@ -372,7 +371,7 @@ class Ecp5GlobalRouter cursor = ctx->getPipSrcWire(fnd->second); length++; } - // log_info ("dist %s -> %s = %d\n", ctx->getWireName(src).c_str(ctx), ctx->getWireName(dst).c_str(ctx), + // log_info ("dist %s -> %s = %d\n", ctx->nameOfWire(src), ctx->nameOfWire(dst), // length); return length < thresh; } diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 8d21c5b3..ed2dfc29 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -1853,7 +1853,7 @@ class Ecp5Packer next = upstream.front(); upstream.pop(); if (ctx->debug) - log_info(" visited %s\n", ctx->getWireName(next).c_str(ctx)); + log_info(" visited %s\n", ctx->nameOfWire(next)); IdString basename = ctx->getWireBasename(next); if (basename == bnke_name || basename == global_name) { break; -- 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 --- ecp5/arch.cc | 104 ++++++++++++++++++++++--------------------------- ecp5/arch.h | 26 ++++++------- ecp5/arch_pybindings.h | 6 +-- ecp5/bitstream.cc | 15 +++---- 4 files changed, 66 insertions(+), 85 deletions(-) (limited to 'ecp5') diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 928a9c5f..d86bad5d 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -37,17 +37,6 @@ NEXTPNR_NAMESPACE_BEGIN -static std::tuple split_identifier_name(const std::string &name) -{ - size_t first_slash = name.find('/'); - NPNR_ASSERT(first_slash != std::string::npos); - size_t second_slash = name.find('/', first_slash + 1); - NPNR_ASSERT(second_slash != std::string::npos); - return std::make_tuple(std::stoi(name.substr(1, first_slash)), - std::stoi(name.substr(first_slash + 2, second_slash - first_slash)), - name.substr(second_slash + 1)); -}; - // ----------------------------------------------------------------------- void IdString::initialize_arch(const BaseCtx *ctx) @@ -133,6 +122,17 @@ Arch::Arch(ArchArgs args) : args(args) 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))); + + for (int i = 0; i < chip_info->width; i++) { + IdString x_id = id(stringf("X%d", i)); + x_ids.push_back(x_id); + id_to_x[x_id] = i; + } + for (int i = 0; i < chip_info->height; i++) { + IdString y_id = id(stringf("Y%d", i)); + y_ids.push_back(y_id); + id_to_y[y_id] = i; + } } // ----------------------------------------------------------------------- @@ -215,29 +215,21 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdStringList name) const { - // TODO: take advantage of IdStringList for fast parsing + if (name.size() != 3) + return BelId(); 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(getCtx())); + loc.x = id_to_x.at(name[0]); + loc.y = id_to_y.at(name[1]); ret.location = loc; const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < int(loci->bel_data.size()); i++) { - if (std::strcmp(loci->bel_data[i].name.get(), basename.c_str()) == 0) { + if (std::strcmp(loci->bel_data[i].name.get(), name[2].c_str(this)) == 0) { ret.index = i; - break; + return ret; } } -#if 0 - if (ret.index >= 0) - bel_by_name[name] = ret; -#endif - return ret; + return BelId(); } BelRange Arch::getBelsByTile(int x, int y) const @@ -286,36 +278,31 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const // ----------------------------------------------------------------------- -WireId Arch::getWireByName(IdString name) const +WireId Arch::getWireByName(IdStringList name) const { + if (name.size() != 3) + return WireId(); WireId ret; - auto it = wire_by_name.find(name); - if (it != wire_by_name.end()) - return it->second; - Location loc; - std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + loc.x = id_to_x.at(name[0]); + loc.y = id_to_y.at(name[1]); ret.location = loc; const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < int(loci->wire_data.size()); i++) { - if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) { + if (std::strcmp(loci->wire_data[i].name.get(), name[2].c_str(this)) == 0) { ret.index = i; - ret.location = loc; - break; + return ret; } } - if (ret.index >= 0) - wire_by_name[name] = ret; - else - ret.location = Location(); - return ret; + return WireId(); } // ----------------------------------------------------------------------- -PipId Arch::getPipByName(IdString name) const +PipId Arch::getPipByName(IdStringList name) const { + if (name.size() != 3) + return PipId(); auto it = pip_by_name.find(name); if (it != pip_by_name.end()) return it->second; @@ -323,7 +310,8 @@ PipId Arch::getPipByName(IdString name) const PipId ret; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + loc.x = id_to_x.at(name[0]); + loc.y = id_to_y.at(name[1]); ret.location = loc; const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < int(loci->pip_data.size()); i++) { @@ -333,24 +321,23 @@ PipId Arch::getPipByName(IdString name) const pip_by_name[getPipName(curr)] = curr; } if (pip_by_name.find(name) == pip_by_name.end()) - NPNR_ASSERT_FALSE_STR("no pip named " + name.str(this)); + NPNR_ASSERT_FALSE_STR("no pip named " + name.str(getCtx())); return pip_by_name[name]; } -IdString Arch::getPipName(PipId pip) const +IdStringList Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); - int x = pip.location.x; - int y = pip.location.y; - - std::string src_name = getWireName(getPipSrcWire(pip)).str(this); - std::replace(src_name.begin(), src_name.end(), '/', '.'); - - std::string dst_name = getWireName(getPipDstWire(pip)).str(this); - std::replace(dst_name.begin(), dst_name.end(), '/', '.'); + // TODO: can we improve how pip names are stored/built? + auto &pip_data = locInfo(pip)->pip_data[pip.index]; + WireId src = getPipSrcWire(pip), dst = getPipDstWire(pip); + std::string pip_name = stringf("%d_%d_%s->%d_%d_%s", pip_data.rel_src_loc.x, pip_data.rel_src_loc.y, + getWireBasename(src).c_str(this), pip_data.rel_dst_loc.x, pip_data.rel_dst_loc.y, + getWireBasename(dst).c_str(this)); - return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); + std::array ids{x_ids.at(pip.location.x), y_ids.at(pip.location.y), id(pip_name)}; + return IdStringList(ids); } // ----------------------------------------------------------------------- @@ -1215,7 +1202,7 @@ const std::vector Arch::availableRouters = {"router1", "router2"}; // ----------------------------------------------------------------------- -GroupId Arch::getGroupByName(IdString name) const +GroupId Arch::getGroupByName(IdStringList name) const { for (auto g : getGroups()) if (getGroupName(g) == name) @@ -1223,7 +1210,7 @@ GroupId Arch::getGroupByName(IdString name) const return GroupId(); } -IdString Arch::getGroupName(GroupId group) const +IdStringList Arch::getGroupName(GroupId group) const { std::string suffix; @@ -1232,10 +1219,11 @@ IdString Arch::getGroupName(GroupId group) const suffix = "switchbox"; break; default: - return IdString(); + return IdStringList(); } - return id("X" + std::to_string(group.location.x) + "/Y" + std::to_string(group.location.y) + "/" + suffix); + std::array ids{x_ids.at(group.location.x), y_ids.at(group.location.y), id(suffix)}; + return IdStringList(ids); } std::vector Arch::getGroups() const diff --git a/ecp5/arch.h b/ecp5/arch.h index 303d9afe..9997cd5c 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -441,9 +441,7 @@ struct Arch : BaseCtx const PackageInfoPOD *package_info; const SpeedGradePOD *speed_grade; - mutable std::unordered_map bel_by_name; - mutable std::unordered_map wire_by_name; - mutable std::unordered_map pip_by_name; + mutable std::unordered_map pip_by_name; std::vector bel_to_cell; std::unordered_map wire_to_net; @@ -452,6 +450,8 @@ struct Arch : BaseCtx // fast access to X and Y IdStrings for building object names std::vector x_ids, y_ids; + // inverse of the above for name->object mapping + std::unordered_map id_to_x, id_to_y; ArchArgs args; Arch(ArchArgs args); @@ -598,16 +598,14 @@ struct Arch : BaseCtx // ------------------------------------------------- - WireId getWireByName(IdString name) const; + WireId getWireByName(IdStringList name) const; - IdString getWireName(WireId wire) const + IdStringList getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); - - std::stringstream name; - name << "X" << wire.location.x << "/Y" << wire.location.y << "/" - << locInfo(wire)->wire_data[wire.index].name.get(); - return id(name.str()); + std::array ids{x_ids.at(wire.location.x), y_ids.at(wire.location.y), + id(locInfo(wire)->wire_data[wire.index].name.get())}; + return IdStringList(ids); } IdString getWireType(WireId wire) const @@ -716,8 +714,8 @@ struct Arch : BaseCtx // ------------------------------------------------- - PipId getPipByName(IdString name) const; - IdString getPipName(PipId pip) const; + PipId getPipByName(IdStringList name) const; + IdStringList getPipName(PipId pip) const; IdString getPipType(PipId pip) const { return IdString(); } @@ -895,8 +893,8 @@ struct Arch : BaseCtx // ------------------------------------------------- - GroupId getGroupByName(IdString name) const; - IdString getGroupName(GroupId group) const; + GroupId getGroupByName(IdStringList name) const; + IdStringList getGroupName(GroupId group) const; std::vector getGroups() const; std::vector getGroupBels(GroupId group) const; std::vector getGroupWires(GroupId group) const; diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h index 90c7c757..4228f12b 100644 --- a/ecp5/arch_pybindings.h +++ b/ecp5/arch_pybindings.h @@ -42,7 +42,7 @@ template <> struct string_converter template <> struct string_converter { - WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByNameStr(name); } std::string to_str(Context *ctx, WireId id) { @@ -54,7 +54,7 @@ template <> struct string_converter template <> struct string_converter { - WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByNameStr(name); } std::string to_str(Context *ctx, WireId id) { @@ -66,7 +66,7 @@ template <> struct string_converter template <> struct string_converter { - PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByNameStr(name); } std::string to_str(Context *ctx, PipId id) { diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 0841fa32..4a43bfca 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -811,14 +811,12 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex NetInfo *lsrnet = nullptr; if (ci->ports.find(ctx->id("LSR")) != ci->ports.end() && ci->ports.at(ctx->id("LSR")).net != nullptr) lsrnet = ci->ports.at(ctx->id("LSR")).net; - if (ctx->getBoundWireNet(ctx->getWireByName( - ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/LSR0")))) == lsrnet) { + if (ctx->getBoundWireNet(ctx->getWireByLocAndBasename(bel.location, "LSR0")) == lsrnet) { cc.tiles[tname].add_enum("LSR0.SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE")); cc.tiles[tname].add_enum("LSR0.LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR")); } - if (ctx->getBoundWireNet(ctx->getWireByName( - ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/LSR1")))) == lsrnet) { + if (ctx->getBoundWireNet(ctx->getWireByLocAndBasename(bel.location, "LSR1")) == lsrnet) { cc.tiles[tname].add_enum("LSR1.SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE")); cc.tiles[tname].add_enum("LSR1.LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR")); @@ -827,12 +825,10 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex NetInfo *clknet = nullptr; if (ci->ports.find(ctx->id("CLK")) != ci->ports.end() && ci->ports.at(ctx->id("CLK")).net != nullptr) clknet = ci->ports.at(ctx->id("CLK")).net; - if (ctx->getBoundWireNet(ctx->getWireByName( - ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/CLK0")))) == clknet) { + if (ctx->getBoundWireNet(ctx->getWireByLocAndBasename(bel.location, "CLK0")) == clknet) { cc.tiles[tname].add_enum("CLK0.CLKMUX", str_or_default(ci->params, ctx->id("CLKMUX"), "CLK")); } - if (ctx->getBoundWireNet(ctx->getWireByName( - ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/CLK1")))) == clknet) { + if (ctx->getBoundWireNet(ctx->getWireByLocAndBasename(bel.location, "CLK1")) == clknet) { cc.tiles[tname].add_enum("CLK1.CLKMUX", str_or_default(ci->params, ctx->id("CLKMUX"), "CLK")); } } @@ -907,8 +903,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex (ci->ports.find(ctx->id("IOLTO")) == ci->ports.end() || ci->ports.at(ctx->id("IOLTO")).net == nullptr)) { // Tie tristate low if unconnected for outputs or bidir - std::string jpt = fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/JPADDT" << pio.back()); - WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); + WireId jpt_wire = ctx->getWireByLocAndBasename(bel.location, fmt_str("JPADDT" << pio.back())); PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin(); WireId cib_wire = ctx->getPipSrcWire(jpt_pip); std::string cib_tile = -- cgit v1.2.3