mirror of https://github.com/YosysHQ/nextpnr.git
gowin: convert latches to DFFs with LATCH attribute during packing
Instead of teaching all DFF infrastructure about 12 DL latch types, pack_latches() converts them to corresponding DFF types early and sets a LATCH attribute. This attribute is picked up by gowin_pack to set REGMODE=LATCH instead of FF.
This commit is contained in:
parent
7d5fb8c240
commit
0de6a67e80
|
|
@ -907,6 +907,7 @@ X(DLP)
|
|||
X(DLPE)
|
||||
X(DLNP)
|
||||
X(DLNPE)
|
||||
X(LATCH)
|
||||
|
||||
// Shadow RAM
|
||||
X(ROM16)
|
||||
|
|
|
|||
|
|
@ -981,15 +981,7 @@ inline bool incompatible_ffs(const CellInfo *ff, const CellInfo *adj_ff)
|
|||
(ff->type == id_DFFNPE && adj_ff->type != id_DFFNCE) ||
|
||||
(ff->type == id_DFFNCE && adj_ff->type != id_DFFNPE) || (ff->type == id_DFF && adj_ff->type != id_DFF) ||
|
||||
(ff->type == id_DFFE && adj_ff->type != id_DFFE) || (ff->type == id_DFFN && adj_ff->type != id_DFFN) ||
|
||||
(ff->type == id_DFFNE && adj_ff->type != id_DFFNE) ||
|
||||
(ff->type == id_DL && adj_ff->type != id_DL) ||
|
||||
(ff->type == id_DLE && adj_ff->type != id_DLE) ||
|
||||
(ff->type == id_DLN && adj_ff->type != id_DLN) ||
|
||||
(ff->type == id_DLNE && adj_ff->type != id_DLNE) ||
|
||||
(ff->type == id_DLC && adj_ff->type != id_DLP) || (ff->type == id_DLP && adj_ff->type != id_DLC) ||
|
||||
(ff->type == id_DLCE && adj_ff->type != id_DLPE) || (ff->type == id_DLPE && adj_ff->type != id_DLCE) ||
|
||||
(ff->type == id_DLNC && adj_ff->type != id_DLNP) || (ff->type == id_DLNP && adj_ff->type != id_DLNC) ||
|
||||
(ff->type == id_DLNCE && adj_ff->type != id_DLNPE) || (ff->type == id_DLNPE && adj_ff->type != id_DLNCE));
|
||||
(ff->type == id_DFFNE && adj_ff->type != id_DFFNE));
|
||||
}
|
||||
|
||||
// placement validation
|
||||
|
|
|
|||
|
|
@ -9,20 +9,18 @@ namespace {
|
|||
// Return true if a cell is a LUT
|
||||
inline bool type_is_lut(IdString cell_type) { return cell_type.in(id_LUT1, id_LUT2, id_LUT3, id_LUT4); }
|
||||
inline bool is_lut(const CellInfo *cell) { return type_is_lut(cell->type); }
|
||||
// Return true if a cell is a latch
|
||||
inline bool type_is_latch(IdString cell_type)
|
||||
{
|
||||
return cell_type.in(id_DL, id_DLE, id_DLN, id_DLNE, id_DLC, id_DLCE, id_DLNC, id_DLNCE, id_DLP, id_DLPE,
|
||||
id_DLNP, id_DLNPE);
|
||||
}
|
||||
inline bool is_latch(const CellInfo *cell) { return type_is_latch(cell->type); }
|
||||
// Return true if a cell is a DFF (or latch, which uses the same BEL sites)
|
||||
// Return true if a cell is a DFF
|
||||
inline bool type_is_dff(IdString cell_type)
|
||||
{
|
||||
return cell_type.in(id_DFF, id_DFFE, id_DFFN, id_DFFNE, id_DFFS, id_DFFSE, id_DFFNS, id_DFFNSE, id_DFFR, id_DFFRE,
|
||||
id_DFFNR, id_DFFNRE, id_DFFP, id_DFFPE, id_DFFNP, id_DFFNPE, id_DFFC, id_DFFCE, id_DFFNC,
|
||||
id_DFFNCE) ||
|
||||
type_is_latch(cell_type);
|
||||
id_DFFNCE);
|
||||
}
|
||||
// Return true if a cell is a latch (before packing converts them to DFFs)
|
||||
inline bool type_is_latch(IdString cell_type)
|
||||
{
|
||||
return cell_type.in(id_DL, id_DLE, id_DLN, id_DLNE, id_DLC, id_DLCE, id_DLNC, id_DLNCE, id_DLP, id_DLPE,
|
||||
id_DLNP, id_DLNPE);
|
||||
}
|
||||
inline bool is_dff(const CellInfo *cell) { return type_is_dff(cell->type); }
|
||||
// Return true if a cell is a ALU
|
||||
|
|
|
|||
|
|
@ -718,6 +718,9 @@ void GowinPacker::run(void)
|
|||
pack_ssram();
|
||||
ctx->check();
|
||||
|
||||
pack_latches();
|
||||
ctx->check();
|
||||
|
||||
constrain_lutffs();
|
||||
ctx->check();
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ struct GowinPacker
|
|||
std::unique_ptr<CellInfo> alu_add_cout_block(Context *ctx, CellInfo *tail, NetInfo *cout_net);
|
||||
std::unique_ptr<CellInfo> alu_add_dummy_block(Context *ctx, CellInfo *tail);
|
||||
void optimize_alu_lut(CellInfo *ci, int mode);
|
||||
void pack_latches(void);
|
||||
void constrain_lutffs(void);
|
||||
std::unique_ptr<CellInfo> ssram_make_lut(Context *ctx, CellInfo *ci, int index);
|
||||
|
||||
|
|
|
|||
|
|
@ -558,13 +558,7 @@ static bool incompatible_ffs(IdString type_a, IdString type_b)
|
|||
(type_a == id_DFFNP && type_b != id_DFFNC) || (type_a == id_DFFNC && type_b != id_DFFNP) ||
|
||||
(type_a == id_DFFNPE && type_b != id_DFFNCE) || (type_a == id_DFFNCE && type_b != id_DFFNPE) ||
|
||||
(type_a == id_DFF && type_b != id_DFF) || (type_a == id_DFFN && type_b != id_DFFN) ||
|
||||
(type_a == id_DFFE && type_b != id_DFFE) || (type_a == id_DFFNE && type_b != id_DFFNE) ||
|
||||
(type_a == id_DL && type_b != id_DL) || (type_a == id_DLE && type_b != id_DLE) ||
|
||||
(type_a == id_DLN && type_b != id_DLN) || (type_a == id_DLNE && type_b != id_DLNE) ||
|
||||
(type_a == id_DLC && type_b != id_DLP) || (type_a == id_DLP && type_b != id_DLC) ||
|
||||
(type_a == id_DLCE && type_b != id_DLPE) || (type_a == id_DLPE && type_b != id_DLCE) ||
|
||||
(type_a == id_DLNC && type_b != id_DLNP) || (type_a == id_DLNP && type_b != id_DLNC) ||
|
||||
(type_a == id_DLNCE && type_b != id_DLNPE) || (type_a == id_DLNPE && type_b != id_DLNCE));
|
||||
(type_a == id_DFFE && type_b != id_DFFE) || (type_a == id_DFFNE && type_b != id_DFFNE));
|
||||
}
|
||||
|
||||
void GowinPacker::pack_io_regs(void)
|
||||
|
|
|
|||
|
|
@ -503,6 +503,36 @@ void GowinPacker::pack_alus(void)
|
|||
}
|
||||
}
|
||||
|
||||
// ===================================
|
||||
// convert latches to DFFs with LATCH attribute
|
||||
// ===================================
|
||||
void GowinPacker::pack_latches(void)
|
||||
{
|
||||
// Latch-to-DFF type mapping: latches use the same BEL as DFFs,
|
||||
// just with REGMODE set to LATCH instead of FF.
|
||||
const dict<IdString, IdString> latch_to_dff = {
|
||||
{id_DL, id_DFF}, {id_DLE, id_DFFE},
|
||||
{id_DLN, id_DFFN}, {id_DLNE, id_DFFNE},
|
||||
{id_DLC, id_DFFC}, {id_DLCE, id_DFFCE},
|
||||
{id_DLNC, id_DFFNC}, {id_DLNCE, id_DFFNCE},
|
||||
{id_DLP, id_DFFP}, {id_DLPE, id_DFFPE},
|
||||
{id_DLNP, id_DFFNP}, {id_DLNPE, id_DFFNPE},
|
||||
};
|
||||
|
||||
int converted = 0;
|
||||
for (auto &cell : ctx->cells) {
|
||||
CellInfo *ci = cell.second.get();
|
||||
auto it = latch_to_dff.find(ci->type);
|
||||
if (it != latch_to_dff.end()) {
|
||||
ci->type = it->second;
|
||||
ci->setAttr(id_LATCH, 1);
|
||||
++converted;
|
||||
}
|
||||
}
|
||||
if (converted)
|
||||
log_info("Converted %d latches to DFFs.\n", converted);
|
||||
}
|
||||
|
||||
// ===================================
|
||||
// glue LUT and FF
|
||||
// ===================================
|
||||
|
|
@ -514,10 +544,7 @@ void GowinPacker::constrain_lutffs(void)
|
|||
{id_DFFS, id_D}, {id_DFFSE, id_D}, {id_DFFNS, id_D}, {id_DFFNSE, id_D},
|
||||
{id_DFFR, id_D}, {id_DFFRE, id_D}, {id_DFFNR, id_D}, {id_DFFNRE, id_D},
|
||||
{id_DFFP, id_D}, {id_DFFPE, id_D}, {id_DFFNP, id_D}, {id_DFFNPE, id_D},
|
||||
{id_DFFC, id_D}, {id_DFFCE, id_D}, {id_DFFNC, id_D}, {id_DFFNCE, id_D},
|
||||
{id_DL, id_D}, {id_DLE, id_D}, {id_DLN, id_D}, {id_DLNE, id_D},
|
||||
{id_DLC, id_D}, {id_DLCE, id_D}, {id_DLNC, id_D}, {id_DLNCE, id_D},
|
||||
{id_DLP, id_D}, {id_DLPE, id_D}, {id_DLNP, id_D}, {id_DLNPE, id_D}};
|
||||
{id_DFFC, id_D}, {id_DFFCE, id_D}, {id_DFFNC, id_D}, {id_DFFNCE, id_D}};
|
||||
|
||||
int lutffs = h.constrain_cell_pairs(lut_outs, dff_ins, 1, 1);
|
||||
log_info("Constrained %d LUTFF pairs.\n", lutffs);
|
||||
|
|
|
|||
Loading…
Reference in New Issue