diff options
author | David Shah <dave@ds0.me> | 2019-02-25 11:07:21 +0000 |
---|---|---|
committer | David Shah <dave@ds0.me> | 2019-02-25 11:49:25 +0000 |
commit | 95a85c8ea76cdd0a1c5824200451569366c9eb8c (patch) | |
tree | 264b6927d3a31691b58f4889e3dc30664508f6ec /ecp5 | |
parent | a0fa16439942d15e9be745ec074fc1ba3a2a7c95 (diff) | |
download | nextpnr-95a85c8ea76cdd0a1c5824200451569366c9eb8c.tar.gz nextpnr-95a85c8ea76cdd0a1c5824200451569366c9eb8c.tar.bz2 nextpnr-95a85c8ea76cdd0a1c5824200451569366c9eb8c.zip |
ecp5: Improve packing density
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'ecp5')
-rw-r--r-- | ecp5/arch.cc | 2 | ||||
-rw-r--r-- | ecp5/pack.cc | 58 |
2 files changed, 59 insertions, 1 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc index fdc9c8fc..cd5fa0cb 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -457,7 +457,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second); return (130 - 25 * args.speed) * - (8 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); + (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const diff --git a/ecp5/pack.cc b/ecp5/pack.cc index b05aec71..9f987f35 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -165,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 && @@ -229,14 +230,71 @@ 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 bool is_top_port(PortRef &port) { |