aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/arch_pybindings_shared.h3
-rw-r--r--common/pybindings.cc2
-rw-r--r--ecp5/pack.cc50
-rw-r--r--gowin/arch.cc42
-rw-r--r--python/delay_vs_fanout.py10
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)
+