machxo2: Add LUT and FF packing functions.
This commit is contained in:
parent
f2a240550e
commit
da6204442f
@ -143,12 +143,29 @@ std::unique_ptr<CellInfo> create_machxo2_cell(Context *ctx, IdString type, std::
|
||||
|
||||
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
|
||||
{
|
||||
lc->params[ctx->id("LUT0_INITVAL")] = lut->params[ctx->id("INIT")];
|
||||
|
||||
for (std::string i : {"A", "B", "C", "D"}) {
|
||||
IdString lut_port = ctx->id(i);
|
||||
IdString lc_port = ctx->id(i + "0");
|
||||
replace_port(lut, lut_port, lc, lc_port);
|
||||
}
|
||||
|
||||
replace_port(lut, ctx->id("Z"), lc, ctx->id("F0"));
|
||||
}
|
||||
|
||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
|
||||
{
|
||||
// By this point, we have shown that LUT4 Z is attached to FACADE_FF DI.
|
||||
// This connection will be preserved by port replacement, but the SD mux
|
||||
// which selects the actual DFF input needs to be told to use the
|
||||
// FACADE_SLICE DI input instead of the FACADE_SLICE M input.
|
||||
lc->params[ctx->id("REG0_SD")] = std::string("0");
|
||||
|
||||
replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK"));
|
||||
replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0"));
|
||||
replace_port(dff, ctx->id("LSR"), lc, ctx->id("LSR"));
|
||||
replace_port(dff, ctx->id("Q"), lc, ctx->id("Q0"));
|
||||
}
|
||||
|
||||
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set<IdString> &todelete_cells)
|
||||
|
@ -24,17 +24,17 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
// Create a generic arch cell and return it
|
||||
// Create a MachXO2 arch cell and return it
|
||||
// Name will be automatically assigned if not specified
|
||||
std::unique_ptr<CellInfo> create_machxo2_cell(Context *ctx, IdString type, std::string name = "");
|
||||
|
||||
// Return true if a cell is a LUT
|
||||
inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return false; }
|
||||
inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("LUT4"); }
|
||||
|
||||
// Return true if a cell is a flipflop
|
||||
inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return false; }
|
||||
inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("FACADE_FF"); }
|
||||
|
||||
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return false; }
|
||||
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("FACADE_SLICE"); }
|
||||
|
||||
// Convert a LUT primitive to (part of) an GENERIC_SLICE, swapping ports
|
||||
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||
|
@ -27,6 +27,65 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
// Pack LUTs and LUT-FF pairs
|
||||
static void pack_lut_lutffs(Context *ctx)
|
||||
{
|
||||
log_info("Packing LUT-FFs..\n");
|
||||
|
||||
std::unordered_set<IdString> packed_cells;
|
||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (ctx->verbose)
|
||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
|
||||
if (is_lut(ctx, ci)) {
|
||||
std::unique_ptr<CellInfo> packed =
|
||||
create_machxo2_cell(ctx, ctx->id("FACADE_SLICE"), ci->name.str(ctx) + "_LC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin()));
|
||||
|
||||
packed_cells.insert(ci->name);
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
|
||||
// See if we can pack into a DFF. Both LUT4 and FF outputs are
|
||||
// available for a given slice, so we can pack a FF even if the
|
||||
// LUT4 drives more than one FF.
|
||||
NetInfo *o = ci->ports.at(ctx->id("Z")).net;
|
||||
CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("DI"), false);
|
||||
auto lut_bel = ci->attrs.find(ctx->id("BEL"));
|
||||
bool packed_dff = false;
|
||||
|
||||
if (dff) {
|
||||
if (ctx->verbose)
|
||||
log_info("found attached dff %s\n", dff->name.c_str(ctx));
|
||||
auto dff_bel = dff->attrs.find(ctx->id("BEL"));
|
||||
if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) {
|
||||
// Locations don't match, can't pack
|
||||
} else {
|
||||
lut_to_lc(ctx, ci, packed.get(), false);
|
||||
dff_to_lc(ctx, dff, packed.get(), false);
|
||||
if (dff_bel != dff->attrs.end())
|
||||
packed->attrs[ctx->id("BEL")] = dff_bel->second;
|
||||
packed_cells.insert(dff->name);
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx));
|
||||
packed_dff = true;
|
||||
}
|
||||
}
|
||||
if (!packed_dff) {
|
||||
lut_to_lc(ctx, ci, packed.get(), true);
|
||||
}
|
||||
new_cells.push_back(std::move(packed));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto pcell : packed_cells) {
|
||||
ctx->cells.erase(pcell);
|
||||
}
|
||||
for (auto &ncell : new_cells) {
|
||||
ctx->cells[ncell->name] = std::move(ncell);
|
||||
}
|
||||
}
|
||||
|
||||
// Merge a net into a constant net
|
||||
static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
|
||||
{
|
||||
@ -135,6 +194,7 @@ bool Arch::pack()
|
||||
log_break();
|
||||
pack_constants(ctx);
|
||||
pack_io(ctx);
|
||||
pack_lut_lutffs(ctx);
|
||||
ctx->settings[ctx->id("pack")] = 1;
|
||||
ctx->assignArchInfo();
|
||||
log_info("Checksum: 0x%08x\n", ctx->checksum());
|
||||
|
Loading…
Reference in New Issue
Block a user