From 3ae8b86003eb6b378c10ddd0f602c40abe28552b Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 16 Nov 2018 17:27:23 +0000 Subject: ecp5: Adding mux support up to LUT6 Signed-off-by: David Shah --- ecp5/arch.cc | 3 ++- ecp5/cells.h | 2 +- ecp5/pack.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 6 deletions(-) (limited to 'ecp5') diff --git a/ecp5/arch.cc b/ecp5/arch.cc index fc3c97bf..22b350c7 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -556,7 +556,8 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort if (cell->type == id_TRELLIS_SLICE) { bool has_carry = str_or_default(cell->params, id("MODE"), "LOGIC") == "CCU2"; if (fromPort == id_A0 || fromPort == id_B0 || fromPort == id_C0 || fromPort == id_D0 || fromPort == id_A1 || - fromPort == id_B1 || fromPort == id_C1 || fromPort == id_D1 || fromPort == id_M0 || fromPort == id_FCI) { + fromPort == id_B1 || fromPort == id_C1 || fromPort == id_D1 || fromPort == id_M0 || fromPort == id_M1 || + fromPort == id_FXA || fromPort == id_FXB || fromPort == id_FCI) { return getDelayFromTimingDatabase(has_carry ? id_SCCU2C : id_SLOGICB, fromPort, toPort, delay); } diff --git a/ecp5/cells.h b/ecp5/cells.h index 9c2ff3cf..dcef99e3 100644 --- a/ecp5/cells.h +++ b/ecp5/cells.h @@ -36,7 +36,7 @@ inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type inline bool is_carry(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("CCU2C"); } -inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("TRELLIS_LC"); } +inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("TRELLIS_SLICE"); } inline bool is_trellis_io(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("TRELLIS_IO"); } diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 2d2f7578..b3f19327 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)) { @@ -412,8 +412,50 @@ 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) + log_error("L6MUX21 '%s' has D0 driven by cell other than a SLICE ('%s.%s')\n", ci->name.c_str(ctx), + ofx0_0->driver.cell->name.c_str(ctx), ofx0_0->driver.port.c_str(ctx)); + if (slice1 == nullptr) + log_error("L6MUX21 '%s' has D1 driven by cell other than a SLICE ('%s.%s')\n", ci->name.c_str(ctx), + ofx0_1->driver.cell->name.c_str(ctx), ofx0_1->driver.port.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_abs_z = true; + 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); + } + } + } // Create a feed in to the carry chain CellInfo *make_carry_feed_in(NetInfo *carry, PortRef chain_in) { @@ -1183,7 +1225,7 @@ class Ecp5Packer pack_dram(); pack_carries(); find_lutff_pairs(); - pack_lut5s(); + pack_lut5xs(); pair_luts(); pack_lut_pairs(); pack_remaining_luts(); -- cgit v1.2.3 From 458aa20161504c06dbfc282be3dd7717a575a31e Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 16 Nov 2018 17:36:34 +0000 Subject: ecp5: More optimal LUT6 placement Signed-off-by: David Shah --- ecp5/arch_place.cc | 6 ++++++ ecp5/archdefs.h | 1 + ecp5/pack.cc | 5 ++++- 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'ecp5') diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index 41f87cb8..ff70bb5a 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -75,6 +75,8 @@ bool Arch::isBelLocationValid(BelId bel) const bel_cells.push_back(cell_other); } } + if (getBoundBelCell(bel) != nullptr && getBoundBelCell(bel)->sliceInfo.has_l6mux && ((bel_loc.z % 2) == 1)) + return false; return slicesCompatible(bel_cells); } else { CellInfo *cell = getBoundBelCell(bel); @@ -92,6 +94,10 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const std::vector bel_cells; Loc bel_loc = getBelLocation(bel); + + if (cell->sliceInfo.has_l6mux && ((bel_loc.z % 2) == 1)) + return false; + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { CellInfo *cell_other = getBoundBelCell(bel_other); if (cell_other != nullptr && bel_other != bel) { diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 9428960c..bfc5769b 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -158,6 +158,7 @@ struct ArchCellInfo struct { bool using_dff; + bool has_l6mux; IdString clk_sig, lsr_sig, clkmux, lsrmux, srmode; } sliceInfo; }; diff --git a/ecp5/pack.cc b/ecp5/pack.cc index b3f19327..08969f87 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -435,7 +435,6 @@ class Ecp5Packer replace_port(ci, ctx->id("SD"), slice1, id_M1); replace_port(ci, ctx->id("Z"), slice1, id_OFX1); slice0->constr_z = 1; - slice0->constr_abs_z = true; slice0->constr_x = 0; slice0->constr_y = 0; slice0->constr_parent = slice1; @@ -1294,6 +1293,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; } } } -- cgit v1.2.3 From 76f575fb2979c6391e4cb0ceb5844f25e91cafd7 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 18 Nov 2018 17:17:46 +0000 Subject: ecp5: Add support for LUT7 mux Signed-off-by: David Shah --- ecp5/pack.cc | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 6 deletions(-) (limited to 'ecp5') diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 08969f87..78bf7a87 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -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")); @@ -424,12 +426,26 @@ class Ecp5Packer 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) - log_error("L6MUX21 '%s' has D0 driven by cell other than a SLICE ('%s.%s')\n", ci->name.c_str(ctx), - ofx0_0->driver.cell->name.c_str(ctx), ofx0_0->driver.port.c_str(ctx)); - if (slice1 == nullptr) - log_error("L6MUX21 '%s' has D1 driven by cell other than a SLICE ('%s.%s')\n", ci->name.c_str(ctx), - ofx0_1->driver.cell->name.c_str(ctx), ofx0_1->driver.port.c_str(ctx)); + 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); @@ -454,6 +470,100 @@ class Ecp5Packer 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) -- cgit v1.2.3