aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/pack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5/pack.cc')
-rw-r--r--ecp5/pack.cc57
1 files changed, 45 insertions, 12 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 00ed891a..c498d20a 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -2345,6 +2345,7 @@ class Ecp5Packer
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (ci->type == id_ECLKBRIDGECS) {
+ Loc loc;
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}) {
@@ -2358,24 +2359,53 @@ class Ecp5Packer
for (auto bel : ctx->getBels()) {
if (ctx->getBelType(bel) != id_ECLKBRIDGECS)
continue;
- Loc loc = ctx->getBelLocation(bel);
+ 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;
}
}
}
+ if (input->driver.cell != nullptr) {
+ CellInfo *drv = input->driver.cell;
+ if (!drv->attrs.count(ctx->id("BEL")))
+ continue;
+ Loc drv_loc = ctx->getBelLocation(
+ ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string())));
+ BelId closest;
+ int closest_x = -1; // aim for same side of chip
+ for (auto bel : ctx->getBels()) {
+ if (ctx->getBelType(bel) != id_ECLKBRIDGECS)
+ continue;
+ loc = ctx->getBelLocation(bel);
+ if (closest_x == -1 || std::abs(loc.x - drv_loc.x) < std::abs(closest_x - drv_loc.x)) {
+ closest_x = loc.x;
+ closest = bel;
+ }
+ }
+ NPNR_ASSERT(closest != BelId());
+ loc = ctx->getBelLocation(closest);
+ ci->attrs[ctx->id("BEL")] = ctx->getBelName(closest).str(ctx);
+ goto eclkbridge_done;
+ }
+ }
+ // If all else fails, place randomly
+ for (auto bel : ctx->getBels()) {
+ if (ctx->getBelType(bel) != id_ECLKBRIDGECS)
+ continue;
+ loc = ctx->getBelLocation(bel);
+ ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx);
}
eclkbridge_done:
+ 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;
+ }
+ }
continue;
}
}
@@ -2575,7 +2605,7 @@ class Ecp5Packer
std::unordered_set<IdString> changed_cells;
for (auto net : changed_nets)
for (auto &user : ctx->nets.at(net)->users)
- if (user.port == id_CLKI || user.port == id_ECLKI)
+ if (user.port == id_CLKI || user.port == id_ECLKI || user.port == id_CLK0 || user.port == id_CLK1)
changed_cells.insert(user.cell->name);
changed_nets.clear();
for (auto cell : sorted(changed_cells)) {
@@ -2592,6 +2622,9 @@ class Ecp5Packer
copy_constraint(ci, id_CLKI, id_CDIVX, ratio);
} else if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) {
copy_constraint(ci, id_ECLKI, id_ECLKO, 1);
+ } else if (ci->type == id_ECLKBRIDGECS) {
+ copy_constraint(ci, id_CLK0, id_ECSOUT, 1);
+ copy_constraint(ci, id_CLK1, id_ECSOUT, 1);
} else if (ci->type == id_DCCA) {
copy_constraint(ci, id_CLKI, id_CLKO, 1);
} else if (ci->type == id_EHXPLLL) {
@@ -2651,12 +2684,12 @@ class Ecp5Packer
prepack_checks();
pack_io();
pack_dqsbuf();
+ preplace_plls();
pack_iologic();
pack_ebr();
pack_dsps();
pack_dcus();
pack_misc();
- preplace_plls();
pack_constants();
pack_dram();
pack_carries();