ecp5: Infrastructure for FF packing

Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
David Shah 2018-07-17 14:19:21 +02:00
parent eb773f246d
commit 7c89aed70e
3 changed files with 71 additions and 0 deletions

View File

@ -18,6 +18,7 @@
*/
#include "cells.h"
#include <algorithm>
#include "design_utils.h"
#include "log.h"
#include "util.h"
@ -121,4 +122,47 @@ std::unique_ptr<CellInfo> create_ecp5_cell(Context *ctx, IdString type, std::str
return new_cell;
}
static void set_param_safe(bool has_ff, CellInfo *lc, IdString name, const std::string &value)
{
NPNR_ASSERT(!has_ff || lc->params.at(name) == value);
lc->params[name] = value;
}
static void replace_port_safe(bool has_ff, CellInfo *ff, IdString ff_port, CellInfo *lc, IdString lc_port)
{
if (has_ff) {
assert(lc->ports.at(lc_port).net == ff->ports.at(ff_port).net);
NetInfo *ffnet = ff->ports.at(ff_port).net;
if (ffnet != nullptr)
ffnet->users.erase(
std::remove_if(ffnet->users.begin(), ffnet->users.end(),
[ff, ff_port](PortRef port) { return port.cell == ff && port.port == ff_port; }),
ffnet->users.end());
} else {
replace_port(ff, ff_port, lc, lc_port);
}
}
void ff_to_lc(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool driven_by_lut)
{
bool has_ff = lc->ports.at(ctx->id("Q0")).net != nullptr || lc->ports.at(ctx->id("Q1")).net != nullptr;
std::string reg = "REG" + std::to_string(index);
set_param_safe(has_ff, lc, ctx->id("SRMODE"), str_or_default(ff->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
set_param_safe(has_ff, lc, ctx->id("GSR"), str_or_default(ff->params, ctx->id("GSR"), "DISABLED"));
set_param_safe(has_ff, lc, ctx->id("CEMUX"), str_or_default(ff->params, ctx->id("CEMUX"), "1"));
set_param_safe(has_ff, lc, ctx->id("LSRMUX"), str_or_default(ff->params, ctx->id("LSRMUX"), "LSR"));
lc->params[ctx->id(reg + "_SD")] = driven_by_lut ? "1" : "0";
lc->params[ctx->id(reg + "_REGSET")] = str_or_default(ff->params, ctx->id("REGSET"), "RESET");
replace_port_safe(has_ff, ff, ctx->id("CLK"), lc, ctx->id("CLK"));
replace_port_safe(has_ff, ff, ctx->id("LSR"), lc, ctx->id("LSR"));
replace_port_safe(has_ff, ff, ctx->id("CE"), lc, ctx->id("CE"));
replace_port(ff, ctx->id("Q"), lc, ctx->id("Q" + std::to_string(index)));
if (driven_by_lut) {
replace_port(ff, ctx->id("DI"), lc, ctx->id("DI" + std::to_string(index)));
} else {
replace_port(ff, ctx->id("DI"), lc, ctx->id("M" + std::to_string(index)));
}
}
NEXTPNR_NAMESPACE_END

View File

@ -46,6 +46,8 @@ inline bool is_pfumx(const BaseCtx *ctx, const CellInfo *cell) { return cell->ty
inline bool is_l6mux(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("L6MUX21"); }
void ff_to_lc(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool driven_by_lut);
NEXTPNR_NAMESPACE_END
#endif

View File

@ -52,6 +52,23 @@ class Ecp5Packer
new_cells.clear();
}
// Find FFs associated with LUTs, or LUT expansion muxes
void find_lutff_pairs()
{
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_lut(ctx, ci) || is_pfumx(ctx, ci) || is_l6mux(ctx, ci)) {
NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
if (znet != nullptr) {
CellInfo *ff = net_only_drives(ctx, znet, is_ff, ctx->id("DI"), false);
if (ff != nullptr) {
lutffPairs[ci->name] = ff->name;
}
}
}
}
}
// Simple "packer" to remove nextpnr IOBUFs, this assumes IOBUFs are manually instantiated
void pack_io()
{
@ -126,6 +143,13 @@ class Ecp5Packer
replace_port(ci, ctx->id("Z"), packed.get(), ctx->id("OFX0"));
ctx->nets.erase(f0->name);
ctx->nets.erase(f1->name);
if (lutffPairs.find(ci->name) != lutffPairs.end()) {
CellInfo *ff = ctx->cells.at(lutffPairs[ci->name]).get();
ff_to_lc(ctx, ff, packed.get(), 0, true);
packed_cells.insert(ff->name);
}
new_cells.push_back(std::move(packed));
packed_cells.insert(lc0->name);
packed_cells.insert(lc1->name);
@ -157,6 +181,7 @@ class Ecp5Packer
};
std::unordered_map<IdString, SliceUsage> sliceUsage;
std::unordered_map<IdString, IdString> lutffPairs;
};
// Main pack function