diff options
author | David Shah <davey1576@gmail.com> | 2019-02-25 12:46:06 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-25 12:46:06 +0000 |
commit | 031725c80eb6c2c0f922b6fa5be57c42330a8a3b (patch) | |
tree | 49215217265802745407465c41f9b493e74f47b1 /ecp5/pack.cc | |
parent | e87fb696653262bea08caa100f0a5d4d31d2a310 (diff) | |
parent | df79d94944b4d92207be7ddedc6424b7c931f313 (diff) | |
download | nextpnr-031725c80eb6c2c0f922b6fa5be57c42330a8a3b.tar.gz nextpnr-031725c80eb6c2c0f922b6fa5be57c42330a8a3b.tar.bz2 nextpnr-031725c80eb6c2c0f922b6fa5be57c42330a8a3b.zip |
Merge pull request #242 from YosysHQ/ecp5next
ecp5: Fixes and QoR improvements
Diffstat (limited to 'ecp5/pack.cc')
-rw-r--r-- | ecp5/pack.cc | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 64682fd2..1b07c2ae 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -27,6 +27,7 @@ #include "design_utils.h" #include "globals.h" #include "log.h" +#include "timing.h" #include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -164,6 +165,7 @@ class Ecp5Packer CellInfo *ci = cell.second; if (is_lut(ctx, ci) && procdLuts.find(cell.first) == procdLuts.end()) { NetInfo *znet = ci->ports.at(ctx->id("Z")).net; + std::vector<NetInfo *> inpnets; if (znet != nullptr) { for (auto user : znet->users) { if (is_lut(ctx, user.cell) && user.cell != ci && @@ -228,12 +230,67 @@ class Ecp5Packer } } } + + // Pack LUTs feeding the same CCU2, RAM or DFF into a SLICE + if (znet != nullptr && znet->users.size() < 10) { + for (auto user : znet->users) { + if (is_lc(ctx, user.cell) || user.cell->type == ctx->id("DP16KD") || is_ff(ctx, user.cell)) { + for (auto port : user.cell->ports) { + if (port.second.type != PORT_IN || port.second.net == nullptr || + port.second.net == znet) + continue; + if (port.second.net->users.size() > 10) + continue; + CellInfo *drv = port.second.net->driver.cell; + if (drv == nullptr) + continue; + if (is_lut(ctx, drv) && !procdLuts.count(drv->name) && + can_pack_lutff(ci->name, drv->name)) { + procdLuts.insert(ci->name); + procdLuts.insert(drv->name); + lutPairs[ci->name] = drv->name; + goto paired_inlut; + } + } + } + } + } + + // Pack LUTs sharing an input with a simple fanout-based heuristic + for (const char *inp : {"A", "B", "C", "D"}) { + NetInfo *innet = ci->ports.at(ctx->id(inp)).net; + if (innet != nullptr && innet->users.size() < 5 && innet->users.size() > 1) + inpnets.push_back(innet); + } + std::sort(inpnets.begin(), inpnets.end(), + [&](const NetInfo *a, const NetInfo *b) { return a->users.size() < b->users.size(); }); + for (auto inet : inpnets) { + for (auto &user : inet->users) { + if (user.cell == nullptr || user.cell == ci || !is_lut(ctx, user.cell)) + continue; + if (procdLuts.count(user.cell->name)) + continue; + if (can_pack_lutff(ci->name, user.cell->name)) { + procdLuts.insert(ci->name); + procdLuts.insert(user.cell->name); + lutPairs[ci->name] = user.cell->name; + goto paired_inlut; + } + } + } + if (false) { paired_inlut: continue; } } } + if (ctx->debug) { + log_info("Singleton LUTs (packer QoR debug): \n"); + for (auto cell : sorted(ctx->cells)) + if (is_lut(ctx, cell.second) && !procdLuts.count(cell.first)) + log_info(" %s\n", cell.first.c_str(ctx)); + } } // Return true if an port is a top level port that provides its own IOBUF @@ -940,11 +997,11 @@ class Ecp5Packer if (is_lut(ctx, ci)) { std::unique_ptr<CellInfo> slice = create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE"); - lut_to_slice(ctx, ci, slice.get(), 0); + lut_to_slice(ctx, ci, slice.get(), 1); auto ff = lutffPairs.find(ci->name); if (ff != lutffPairs.end()) { - ff_to_slice(ctx, ctx->cells.at(ff->second).get(), slice.get(), 0, true); + ff_to_slice(ctx, ctx->cells.at(ff->second).get(), slice.get(), 1, true); packed_cells.insert(ff->second); fflutPairs.erase(ff->second); lutffPairs.erase(ci->name); @@ -1825,7 +1882,8 @@ class Ecp5Packer } iol->params[ctx->id("DELAY.DEL_VALUE")] = std::to_string(lookup_delay(str_or_default(ci->params, ctx->id("DEL_MODE"), "USER_DEFINED"))); - if (ci->params.count(ctx->id("DEL_VALUE")) && ci->params.at(ctx->id("DEL_VALUE")) != "DELAY0") + if (ci->params.count(ctx->id("DEL_VALUE")) && + ci->params.at(ctx->id("DEL_VALUE")).substr(0, 5) != "DELAY") iol->params[ctx->id("DELAY.DEL_VALUE")] = ci->params.at(ctx->id("DEL_VALUE")); if (ci->ports.count(id_LOADN)) replace_port(ci, id_LOADN, iol, id_LOADN); @@ -2388,6 +2446,9 @@ 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.is_carry = str_or_default(ci->params, id("MODE"), "LOGIC") == "CCU2"; + ci->sliceInfo.sd0 = int_or_default(ci->params, id("REG0_SD"), 0); + ci->sliceInfo.sd1 = int_or_default(ci->params, id("REG1_SD"), 0); 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) |