From d792bce0fb03529ee57b6f6ed5b0c234f503e452 Mon Sep 17 00:00:00 2001 From: "D. Shah" Date: Fri, 29 Jan 2021 13:30:56 +0000 Subject: [PATCH] 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 +++++++++- ecp5/arch.cc | 104 ++++++++++++++++++----------------------- ecp5/arch.h | 26 +++++------ ecp5/arch_pybindings.h | 6 +-- ecp5/bitstream.cc | 15 ++---- 7 files changed, 121 insertions(+), 93 deletions(-) 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); // -------------------------------------------------------------- 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; + // 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)); - 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(), '/', '.'); - - 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 =