aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2019-10-11 14:52:31 +0100
committerDavid Shah <dave@ds0.me>2019-10-11 14:52:31 +0100
commit8f86ccc412e9e094f785d60269bd3d9c3fa8809a (patch)
tree7c1ed1b2b3ae2943906cc387e5840f08fd47f686 /ecp5
parentf2fd1bf80a96e1964c37a657146b6101b1a2e4ab (diff)
downloadnextpnr-8f86ccc412e9e094f785d60269bd3d9c3fa8809a.tar.gz
nextpnr-8f86ccc412e9e094f785d60269bd3d9c3fa8809a.tar.bz2
nextpnr-8f86ccc412e9e094f785d60269bd3d9c3fa8809a.zip
ecp5: Add support for ECLKBRIDGECS
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/pack.cc53
1 files changed, 52 insertions, 1 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 559345fa..244a79d5 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -1560,6 +1560,7 @@ class Ecp5Packer
};
std::map<std::pair<int, int>, EdgeClockInfo> eclks;
+ std::map<NetInfo *, int> bridge_side_hint;
void make_eclk(PortInfo &usr_port, CellInfo *usr_cell, BelId usr_bel, int bank)
{
@@ -1575,6 +1576,8 @@ class Ecp5Packer
break;
}
} else if (free_eclk == -1) {
+ if (bridge_side_hint.count(ecknet) && bridge_side_hint.at(ecknet) != i)
+ continue;
free_eclk = i;
}
}
@@ -2346,6 +2349,44 @@ class Ecp5Packer
}
}
flush_cells();
+ // Constrain ECLK-related cells
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (ci->type == id_ECLKBRIDGECS) {
+ NetInfo *i0 = get_net_or_empty(ci, id_CLK0), *i1 = get_net_or_empty(ci, id_CLK1),
+ *o = get_net_or_empty(ci, id_ECSOUT);
+ for (NetInfo *input : {i0, i1}) {
+ if (input == nullptr)
+ continue;
+ for (auto user : input->users) {
+ 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())));
+ for (auto bel : ctx->getBels()) {
+ if (ctx->getBelType(bel) != id_ECLKBRIDGECS)
+ continue;
+ Loc loc = ctx->getBelLocation(bel);
+ if (loc.x == user_loc.x) {
+ ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx);
+ if (o != nullptr)
+ for (auto user2 : o->users) {
+ // Set side hint to ensure edge clock choice is routeable
+ if (user2.cell->type == id_ECLKSYNCB && user2.port == id_ECLKI) {
+ NetInfo *synco = get_net_or_empty(user2.cell, id_ECLKO);
+ if (synco != nullptr)
+ bridge_side_hint[synco] = (loc.x > 1) ? 0 : 1;
+ }
+ }
+ goto eclkbridge_done;
+ }
+ }
+ }
+ }
+ eclkbridge_done:
+ continue;
+ }
+ }
// Promote/route edge clocks
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
@@ -2366,7 +2407,6 @@ class Ecp5Packer
}
}
flush_cells();
- // Constrain ECLK-related cells
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (ci->type == id_CLKDIVF) {
@@ -2392,7 +2432,18 @@ class Ecp5Packer
clkdiv_done:
continue;
} else if (ci->type == id_ECLKSYNCB) {
+ const NetInfo *eclki = net_or_nullptr(ci, id_ECLKI);
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()));
+ Loc loc = ctx->getBelLocation(bel);
+ ci->attrs[ctx->id("BEL")] =
+ ctx->getBelName(ctx->getBelByLocation(Loc(loc.x, loc.y, 15))).str(ctx);
+ goto eclksync_done;
+ }
+ }
if (eclko == nullptr)
log_error("ECLKSYNCB '%s' has disconnected port ECLKO\n", ci->name.c_str(ctx));
for (auto user : eclko->users) {