aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorAidan Klein <aidan@shader.me>2021-08-18 20:49:55 -0400
committerAidan Klein <aidan@shader.me>2021-08-18 20:49:55 -0400
commite6006805cea00aa636a643def2f1c0f69bed3178 (patch)
tree10e9d1da89883d8f2f5120e228fd953a41cb0774 /ecp5
parentdd6376433154e008045695f5420469670b0c3a88 (diff)
downloadnextpnr-e6006805cea00aa636a643def2f1c0f69bed3178.tar.gz
nextpnr-e6006805cea00aa636a643def2f1c0f69bed3178.tar.bz2
nextpnr-e6006805cea00aa636a643def2f1c0f69bed3178.zip
Make EXTREFB handling more robust
Avoids a segfault if an EXTREFB does not connect directly to its associated DCUA. Also adds location constraints specifically for EXTREFB.
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/pack.cc50
1 files changed, 44 insertions, 6 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index d0077375..11d2f0ef 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) {