ecp5: Add support for flipflops with preload

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2019-12-07 12:14:34 +00:00
parent f0887427da
commit 349be76d26
3 changed files with 25 additions and 5 deletions

View File

@ -759,6 +759,10 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET")); str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET"));
cc.tiles[tname].add_enum(slice + ".REG1.REGSET", cc.tiles[tname].add_enum(slice + ".REG1.REGSET",
str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET")); str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET"));
cc.tiles[tname].add_enum(slice + ".REG0.LSRMODE",
str_or_default(ci->params, ctx->id("REG0_LSRMODE"), "LSR"));
cc.tiles[tname].add_enum(slice + ".REG1.LSRMODE",
str_or_default(ci->params, ctx->id("REG1_LSRMODE"), "LSR"));
cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1")); cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1"));
if (ci->sliceInfo.using_dff) { if (ci->sliceInfo.using_dff) {

View File

@ -243,6 +243,7 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive
lc->params[ctx->id(reg + "_SD")] = std::string(driven_by_lut ? "1" : "0"); lc->params[ctx->id(reg + "_SD")] = std::string(driven_by_lut ? "1" : "0");
lc->params[ctx->id(reg + "_REGSET")] = str_or_default(ff->params, ctx->id("REGSET"), "RESET"); lc->params[ctx->id(reg + "_REGSET")] = str_or_default(ff->params, ctx->id("REGSET"), "RESET");
lc->params[ctx->id(reg + "_LSRMODE")] = str_or_default(ff->params, ctx->id("LSRMODE"), "LSR");
replace_port_safe(has_ff, ff, ctx->id("CLK"), lc, ctx->id("CLK")); replace_port_safe(has_ff, ff, ctx->id("CLK"), lc, ctx->id("CLK"));
if (ff->ports.find(ctx->id("LSR")) != ff->ports.end()) if (ff->ports.find(ctx->id("LSR")) != ff->ports.end())
replace_port_safe(has_ff, ff, ctx->id("LSR"), lc, ctx->id("LSR")); replace_port_safe(has_ff, ff, ctx->id("LSR"), lc, ctx->id("LSR"));
@ -250,10 +251,21 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive
replace_port_safe(has_ff, ff, ctx->id("CE"), lc, ctx->id("CE")); 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))); replace_port(ff, ctx->id("Q"), lc, ctx->id("Q" + std::to_string(index)));
if (driven_by_lut) { if (get_net_or_empty(ff, ctx->id("M")) != nullptr) {
replace_port(ff, ctx->id("DI"), lc, ctx->id("DI" + std::to_string(index))); // PRLD FFs that use both M and DI
NPNR_ASSERT(!driven_by_lut);
// As M is used; must route DI through a new LUT
lc->params[ctx->id(reg + "_SD")] = std::string("1");
lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] = Property(0xFF00, 16);
replace_port(ff, ctx->id("DI"), lc, ctx->id("D" + std::to_string(index)));
replace_port(ff, ctx->id("M"), lc, ctx->id("M" + std::to_string(index)));
connect_ports(ctx, lc, ctx->id("F" + std::to_string(index)), lc, ctx->id("DI" + std::to_string(index)));
} else { } else {
replace_port(ff, ctx->id("DI"), lc, ctx->id("M" + 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)));
}
} }
} }

View File

@ -112,7 +112,8 @@ class Ecp5Packer
NetInfo *znet = ci->ports.at(ctx->id("Z")).net; NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
if (znet != nullptr) { if (znet != nullptr) {
CellInfo *ff = net_only_drives(ctx, znet, is_ff, ctx->id("DI"), false); CellInfo *ff = net_only_drives(ctx, znet, is_ff, ctx->id("DI"), false);
if (ff != nullptr) { // Can't combine preload FF with LUT due to conflict on M
if (ff != nullptr && get_net_or_empty(ff, ctx->id("M")) == nullptr) {
lutffPairs[ci->name] = ff->name; lutffPairs[ci->name] = ff->name;
fflutPairs[ff->name] = ci->name; fflutPairs[ff->name] = ci->name;
} }
@ -232,6 +233,8 @@ class Ecp5Packer
// Return true if a FF can be added to a DPRAM slice // Return true if a FF can be added to a DPRAM slice
bool can_pack_ff_dram(CellInfo *dpram, CellInfo *ff) bool can_pack_ff_dram(CellInfo *dpram, CellInfo *ff)
{ {
if (get_net_or_empty(ff, ctx->id("M")) != nullptr)
return false; // skip PRLD FFs due to M/DI conflict
std::string wckmux = str_or_default(dpram->params, ctx->id("WCKMUX"), "WCK"); std::string wckmux = str_or_default(dpram->params, ctx->id("WCKMUX"), "WCK");
std::string clkmux = str_or_default(ff->params, ctx->id("CLKMUX"), "CLK"); std::string clkmux = str_or_default(ff->params, ctx->id("CLKMUX"), "CLK");
if (wckmux != clkmux && !(wckmux == "WCK" && clkmux == "CLK")) if (wckmux != clkmux && !(wckmux == "WCK" && clkmux == "CLK"))
@ -1178,7 +1181,8 @@ class Ecp5Packer
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_ff(ctx, ci)) { if (is_ff(ctx, ci)) {
bool pack_dense = used_slices > (dense_pack_mode_thresh * available_slices); bool pack_dense = used_slices > (dense_pack_mode_thresh * available_slices);
if (pack_dense) { bool requires_m = get_net_or_empty(ci, ctx->id("M")) != nullptr;
if (pack_dense && !requires_m) {
// If dense packing threshold exceeded; always try and pack the FF into an existing slice // If dense packing threshold exceeded; always try and pack the FF into an existing slice
// Find a SLICE with space "near" the flipflop in the netlist // Find a SLICE with space "near" the flipflop in the netlist
std::vector<CellInfo *> ltile; std::vector<CellInfo *> ltile;