aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/pack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5/pack.cc')
-rw-r--r--ecp5/pack.cc163
1 files changed, 159 insertions, 4 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 2d2f7578..78bf7a87 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -357,9 +357,9 @@ class Ecp5Packer
}
// Pass to pack LUT5s into a newly created slice
- void pack_lut5s()
+ void pack_lut5xs()
{
- log_info("Packing LUT5s...\n");
+ log_info("Packing LUT5-7s...\n");
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_pfumx(ctx, ci)) {
@@ -377,6 +377,8 @@ class Ecp5Packer
log_error("PFUMX '%s' has BLUT driven by cell other than a LUT\n", ci->name.c_str(ctx));
if (lut1 == nullptr)
log_error("PFUMX '%s' has ALUT driven by cell other than a LUT\n", ci->name.c_str(ctx));
+ if (ctx->verbose)
+ log_info(" mux '%s' forms part of a LUT5\n", cell.first.c_str(ctx));
replace_port(lut0, ctx->id("A"), packed.get(), ctx->id("A0"));
replace_port(lut0, ctx->id("B"), packed.get(), ctx->id("B0"));
replace_port(lut0, ctx->id("C"), packed.get(), ctx->id("C0"));
@@ -412,8 +414,157 @@ class Ecp5Packer
}
}
flush_cells();
- }
+ // Pack LUT6s
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (is_l6mux(ctx, ci)) {
+ NetInfo *ofx0_0 = ci->ports.at(ctx->id("D0")).net;
+ if (ofx0_0 == nullptr)
+ log_error("L6MUX21 '%s' has disconnected port 'D0'\n", ci->name.c_str(ctx));
+ NetInfo *ofx0_1 = ci->ports.at(ctx->id("D1")).net;
+ if (ofx0_1 == nullptr)
+ log_error("L6MUX21 '%s' has disconnected port 'D1'\n", ci->name.c_str(ctx));
+ CellInfo *slice0 = net_driven_by(ctx, ofx0_0, is_lc, ctx->id("OFX0"));
+ CellInfo *slice1 = net_driven_by(ctx, ofx0_1, is_lc, ctx->id("OFX0"));
+ if (slice0 == nullptr) {
+ if (!net_driven_by(ctx, ofx0_0, is_l6mux, ctx->id("Z")) &&
+ !net_driven_by(ctx, ofx0_0, is_lc, ctx->id("OFX1")))
+ log_error("L6MUX21 '%s' has D0 driven by cell other than a SLICE OFX0 but not a LUT7 mux "
+ "('%s.%s')\n",
+ ci->name.c_str(ctx), ofx0_0->driver.cell->name.c_str(ctx),
+ ofx0_0->driver.port.c_str(ctx));
+ continue;
+ }
+ if (slice1 == nullptr) {
+ if (!net_driven_by(ctx, ofx0_1, is_l6mux, ctx->id("Z")) &&
+ !net_driven_by(ctx, ofx0_1, is_lc, ctx->id("OFX1")))
+ log_error("L6MUX21 '%s' has D1 driven by cell other than a SLICE OFX0 but not a LUT7 mux "
+ "('%s.%s')\n",
+ ci->name.c_str(ctx), ofx0_0->driver.cell->name.c_str(ctx),
+ ofx0_0->driver.port.c_str(ctx));
+ continue;
+ }
+ if (ctx->verbose)
+ log_info(" mux '%s' forms part of a LUT6\n", cell.first.c_str(ctx));
+ replace_port(ci, ctx->id("D0"), slice1, id_FXA);
+ replace_port(ci, ctx->id("D1"), slice1, id_FXB);
+ replace_port(ci, ctx->id("SD"), slice1, id_M1);
+ replace_port(ci, ctx->id("Z"), slice1, id_OFX1);
+ slice0->constr_z = 1;
+ slice0->constr_x = 0;
+ slice0->constr_y = 0;
+ slice0->constr_parent = slice1;
+ slice1->constr_z = 0;
+ slice1->constr_abs_z = true;
+ slice1->constr_children.push_back(slice0);
+
+ if (lutffPairs.find(ci->name) != lutffPairs.end()) {
+ CellInfo *ff = ctx->cells.at(lutffPairs[ci->name]).get();
+ ff_to_slice(ctx, ff, slice1, 1, true);
+ packed_cells.insert(ff->name);
+ sliceUsage[slice1->name].ff1_used = true;
+ lutffPairs.erase(ci->name);
+ fflutPairs.erase(ff->name);
+ }
+
+ packed_cells.insert(ci->name);
+ }
+ }
+ flush_cells();
+ // Pack LUT7s
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (is_l6mux(ctx, ci)) {
+ NetInfo *ofx1_0 = ci->ports.at(ctx->id("D0")).net;
+ if (ofx1_0 == nullptr)
+ log_error("L6MUX21 '%s' has disconnected port 'D0'\n", ci->name.c_str(ctx));
+ NetInfo *ofx1_1 = ci->ports.at(ctx->id("D1")).net;
+ if (ofx1_1 == nullptr)
+ log_error("L6MUX21 '%s' has disconnected port 'D1'\n", ci->name.c_str(ctx));
+ CellInfo *slice1 = net_driven_by(ctx, ofx1_0, is_lc, ctx->id("OFX1"));
+ CellInfo *slice3 = net_driven_by(ctx, ofx1_1, is_lc, ctx->id("OFX1"));
+ if (slice1 == nullptr)
+ log_error("L6MUX21 '%s' has D0 driven by cell other than a SLICE OFX ('%s.%s')\n",
+ ci->name.c_str(ctx), ofx1_0->driver.cell->name.c_str(ctx),
+ ofx1_0->driver.port.c_str(ctx));
+ if (slice3 == nullptr)
+ log_error("L6MUX21 '%s' has D1 driven by cell other than a SLICE OFX ('%s.%s')\n",
+ ci->name.c_str(ctx), ofx1_1->driver.cell->name.c_str(ctx),
+ ofx1_1->driver.port.c_str(ctx));
+
+ NetInfo *fxa_0 = slice1->ports.at(id_FXA).net;
+ if (fxa_0 == nullptr)
+ log_error("SLICE '%s' has disconnected port 'FXA'\n", slice1->name.c_str(ctx));
+ NetInfo *fxa_1 = slice3->ports.at(id_FXA).net;
+ if (fxa_1 == nullptr)
+ log_error("SLICE '%s' has disconnected port 'FXA'\n", slice3->name.c_str(ctx));
+
+ CellInfo *slice0 = net_driven_by(ctx, fxa_0, is_lc, ctx->id("OFX0"));
+ CellInfo *slice2 = net_driven_by(ctx, fxa_1, is_lc, ctx->id("OFX0"));
+ if (slice0 == nullptr)
+ log_error("SLICE '%s' has FXA driven by cell other than a SLICE OFX0 ('%s.%s')\n",
+ slice1->name.c_str(ctx), fxa_0->driver.cell->name.c_str(ctx),
+ fxa_0->driver.port.c_str(ctx));
+ if (slice2 == nullptr)
+ log_error("SLICE '%s' has FXA driven by cell other than a SLICE OFX0 ('%s.%s')\n",
+ slice3->name.c_str(ctx), fxa_1->driver.cell->name.c_str(ctx),
+ fxa_1->driver.port.c_str(ctx));
+
+ replace_port(ci, ctx->id("D0"), slice2, id_FXA);
+ replace_port(ci, ctx->id("D1"), slice2, id_FXB);
+ replace_port(ci, ctx->id("SD"), slice2, id_M1);
+ replace_port(ci, ctx->id("Z"), slice2, id_OFX1);
+
+ for (auto slice : {slice0, slice1, slice2, slice3}) {
+ slice->constr_children.clear();
+ slice->constr_abs_z = false;
+ slice->constr_x = slice->UNCONSTR;
+ slice->constr_y = slice->UNCONSTR;
+ slice->constr_z = slice->UNCONSTR;
+ slice->constr_parent = nullptr;
+ }
+ slice3->constr_children.clear();
+ slice3->constr_abs_z = true;
+ slice3->constr_z = 0;
+
+ slice2->constr_children.clear();
+ slice2->constr_abs_z = true;
+ slice2->constr_z = 1;
+ slice2->constr_x = 0;
+ slice2->constr_y = 0;
+ slice2->constr_parent = slice3;
+ slice3->constr_children.push_back(slice2);
+
+ slice1->constr_children.clear();
+ slice1->constr_abs_z = true;
+ slice1->constr_z = 2;
+ slice1->constr_x = 0;
+ slice1->constr_y = 0;
+ slice1->constr_parent = slice3;
+ slice3->constr_children.push_back(slice1);
+
+ slice0->constr_children.clear();
+ slice0->constr_abs_z = true;
+ slice0->constr_z = 3;
+ slice0->constr_x = 0;
+ slice0->constr_y = 0;
+ slice0->constr_parent = slice3;
+ slice3->constr_children.push_back(slice0);
+
+ if (lutffPairs.find(ci->name) != lutffPairs.end()) {
+ CellInfo *ff = ctx->cells.at(lutffPairs[ci->name]).get();
+ ff_to_slice(ctx, ff, slice2, 1, true);
+ packed_cells.insert(ff->name);
+ sliceUsage[slice2->name].ff1_used = true;
+ lutffPairs.erase(ci->name);
+ fflutPairs.erase(ff->name);
+ }
+ packed_cells.insert(ci->name);
+ }
+ }
+ flush_cells();
+ }
// Create a feed in to the carry chain
CellInfo *make_carry_feed_in(NetInfo *carry, PortRef chain_in)
{
@@ -1183,7 +1334,7 @@ class Ecp5Packer
pack_dram();
pack_carries();
find_lutff_pairs();
- pack_lut5s();
+ pack_lut5xs();
pair_luts();
pack_lut_pairs();
pack_remaining_luts();
@@ -1252,6 +1403,10 @@ void Arch::assignArchInfo()
ci->sliceInfo.clkmux = id(str_or_default(ci->params, id_CLKMUX, "CLK"));
ci->sliceInfo.lsrmux = id(str_or_default(ci->params, id_LSRMUX, "LSR"));
ci->sliceInfo.srmode = id(str_or_default(ci->params, id_SRMODE, "LSR_OVER_CE"));
+ ci->sliceInfo.has_l6mux = false;
+ if (ci->ports.count(id_FXA) && ci->ports[id_FXA].net != nullptr &&
+ ci->ports[id_FXA].net->driver.port == id_OFX0)
+ ci->sliceInfo.has_l6mux = true;
}
}
}