diff options
-rw-r--r-- | common/arch_pybindings_shared.h | 3 | ||||
-rw-r--r-- | common/pybindings.cc | 2 | ||||
-rw-r--r-- | ecp5/pack.cc | 50 | ||||
-rw-r--r-- | gowin/arch.cc | 42 | ||||
-rw-r--r-- | python/delay_vs_fanout.py | 10 |
5 files changed, 96 insertions, 11 deletions
diff --git a/common/arch_pybindings_shared.h b/common/arch_pybindings_shared.h index 46f1f9be..f44aa70e 100644 --- a/common/arch_pybindings_shared.h +++ b/common/arch_pybindings_shared.h @@ -27,6 +27,9 @@ fn_wrapper_2a_v<Context, decltype(&Context::addBelToRegion), &Context::addBelToR fn_wrapper_2a_v<Context, decltype(&Context::constrainCellToRegion), &Context::constrainCellToRegion, conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "constrainCellToRegion"); +fn_wrapper_2a<Context, decltype(&Context::getNetinfoRouteDelay), &Context::getNetinfoRouteDelay, pass_through<delay_t>, + addr_and_unwrap<NetInfo>, unwrap_context<PortRef &>>::def_wrap(ctx_cls, "getNetinfoRouteDelay"); + fn_wrapper_1a<Context, decltype(&Context::createNet), &Context::createNet, deref_and_wrap<NetInfo>, conv_from_str<IdString>>::def_wrap(ctx_cls, "createNet"); fn_wrapper_3a_v<Context, decltype(&Context::connectPort), &Context::connectPort, conv_from_str<IdString>, diff --git a/common/pybindings.cc b/common/pybindings.cc index 2f672a41..0e087e98 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -285,6 +285,8 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m) WRAP_MAP(m, WireMap, wrap_context<PipMap &>, "WireMap"); WRAP_MAP_UPTR(m, RegionMap, "RegionMap"); + WRAP_VECTOR(m, PortRefVector, wrap_context<PortRef &>); + typedef dict<IdString, ClockFmax> ClockFmaxMap; WRAP_MAP(m, ClockFmaxMap, pass_through<ClockFmax>, "ClockFmaxMap"); diff --git a/ecp5/pack.cc b/ecp5/pack.cc index d0077375..3bc2dbb3 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -1766,6 +1766,26 @@ class Ecp5Packer if (ci->type == id_EXTREFB) { const NetInfo *refo = net_or_nullptr(ci, id_REFCLKO); CellInfo *dcu = nullptr; + std::string loc_bel = std::string("NONE"); + std::string dcu_bel = std::string("NONE"); + if (ci->attrs.count(ctx->id("LOC"))) { + std::string loc = ci->attrs.at(ctx->id("LOC")).as_string(); + if (loc == "EXTREF0" && + (ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F)) + loc_bel = std::string("X42/Y50/EXTREF"); + else if (loc == "EXTREF0" && + (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) + loc_bel = std::string("X42/Y71/EXTREF"); + else if (loc == "EXTREF1" && + (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) + loc_bel = std::string("X69/Y71/EXTREF"); + else if (loc == "EXTREF0" && + (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) + loc_bel = std::string("X46/Y95/EXTREF"); + else if (loc == "EXTREF1" && + (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) + loc_bel = std::string("X71/Y95/EXTREF"); + } if (refo == nullptr) log_error("EXTREFB REFCLKO must not be unconnected\n"); for (auto user : refo->users) { @@ -1775,12 +1795,30 @@ class Ecp5Packer log_error("EXTREFB REFCLKO must only drive a single DCUA\n"); dcu = user.cell; } - if (!dcu->attrs.count(ctx->id("BEL"))) - log_error("DCU must be constrained to a Bel!\n"); - std::string bel = dcu->attrs.at(ctx->id("BEL")).as_string(); - NPNR_ASSERT(bel.substr(bel.length() - 3) == "DCU"); - bel.replace(bel.length() - 3, 3, "EXTREF"); - ci->attrs[ctx->id("BEL")] = bel; + if (dcu != nullptr) { + if (!dcu->attrs.count(ctx->id("BEL"))) + log_error("DCU must be constrained to a Bel!\n"); + dcu_bel = dcu->attrs.at(ctx->id("BEL")).as_string(); + NPNR_ASSERT(dcu_bel.substr(dcu_bel.length() - 3) == "DCU"); + dcu_bel.replace(dcu_bel.length() - 3, 3, "EXTREF"); + } + if (dcu_bel != loc_bel) { + if (dcu_bel == "NONE" && loc_bel == "NONE") { + log_error("EXTREFB has neither a LOC or a directly associated DCUA\n"); + } else if (dcu_bel == "NONE") { + ci->attrs[ctx->id("BEL")] = loc_bel; + dcu_bel = loc_bel; + } else if (loc_bel == "NONE") { + ci->attrs[ctx->id("BEL")] = dcu_bel; + } else { + log_error("EXTREFB has conflicting LOC '%s' and associated DCUA '%s'\n", loc_bel.c_str(), + dcu_bel.c_str()); + } + } else { + if (dcu_bel == "NONE") + log_error("EXTREFB has no LOC or associated DCUA\n"); + ci->attrs[ctx->id("BEL")] = dcu_bel; + } } else if (ci->type == id_PCSCLKDIV) { const NetInfo *clki = net_or_nullptr(ci, id_CLKI); if (clki != nullptr && clki->driver.cell != nullptr && clki->driver.cell->type == id_DCUA) { diff --git a/gowin/arch.cc b/gowin/arch.cc index 0bc0ef56..a4be92cd 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -482,14 +482,34 @@ DelayQuad Arch::getWireTypeDelay(IdString wire) } } +static Loc getLoc(std::smatch match, int maxX, int maxY) +{ + int col = std::stoi(match[2]); + int row = 1; // Top + std::string side = match[1].str(); + if (side == "R") { + row = col; + col = maxX; + } else if (side == "B") { + row = maxY; + } else if (side == "L") { + row = col; + col = 1; + } + int z = match[3].str()[0] - 'A'; + return Loc(col - 1, row - 1, z); +} + void Arch::read_cst(std::istream &in) { std::regex iobre = std::regex("IO_LOC +\"([^\"]+)\" +([^ ;]+) *;.*"); std::regex portre = std::regex("IO_PORT +\"([^\"]+)\" +([^;]+;).*"); std::regex port_attrre = std::regex("([^ =;]+=[^ =;]+) *([^;]*;)"); - std::smatch match, match_attr; - std::string line; + std::regex iobelre = std::regex("IO([TRBL])([0-9]+)([A-Z])"); + std::smatch match, match_attr, match_pinloc; + std::string line, pinline; bool io_loc; + while (!in.eof()) { std::getline(in, line); io_loc = true; @@ -512,11 +532,23 @@ void Arch::read_cst(std::istream &in) } if (io_loc) { // IO_LOC name pin IdString pinname = id(match[2]); + pinline = match[2]; const PairPOD *belname = pairLookup(package->pins.get(), package->num_pins, pinname.index); - if (belname == nullptr) + if (belname != nullptr) { + std::string bel = IdString(belname->src_id).str(this); + it->second->attrs[IdString(ID_BEL)] = bel; + } else if (std::regex_match(pinline, match_pinloc, iobelre)) { + // may be it's IOx#[AB] style? + Loc loc = getLoc(match_pinloc, getGridDimX(), getGridDimY()); + BelId bel = getBelByLocation(loc); + if (bel == BelId()) { + log_error("Pin %s not found\n", pinline.c_str()); + } + std::string belname = getCtx()->nameOfBel(bel); + it->second->attrs[IdString(ID_BEL)] = belname; + } else { log_error("Pin %s not found\n", pinname.c_str(this)); - std::string bel = IdString(belname->src_id).str(this); - it->second->attrs[IdString(ID_BEL)] = bel; + } } else { // IO_PORT attr=value std::string attr_val = match[2]; while (std::regex_match(attr_val, match_attr, port_attrre)) { diff --git a/python/delay_vs_fanout.py b/python/delay_vs_fanout.py new file mode 100644 index 00000000..c417ac78 --- /dev/null +++ b/python/delay_vs_fanout.py @@ -0,0 +1,10 @@ +with open("delay_vs_fanout.csv", "w") as f: + print("fanout,delay", file=f) + for net_name, net in ctx.nets: + if net.driver.cell is None: + continue + if net.driver.cell.type == "DCCA": + continue # ignore global clocks + for user in net.users: + print(f"{len(net.users)},{ctx.getNetinfoRouteDelay(net, user)}", file=f) + |