ecp5: Negative clock support, general slice improvements

Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
David Shah 2018-10-02 15:50:45 +01:00
parent 8cbc92b7f3
commit bf7161d2b4
3 changed files with 41 additions and 4 deletions

View File

@ -260,6 +260,17 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
cc.tiles[tname].add_enum("LSR1.LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR"));
}
NetInfo *clknet = nullptr;
if (ci->ports.find(ctx->id("CLK")) != ci->ports.end() && ci->ports.at(ctx->id("CLK")).net != nullptr)
clknet = ci->ports.at(ctx->id("CLK")).net;
if (ctx->getBoundWireNet(ctx->getWireByName(
ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/CLK0")))) == clknet) {
cc.tiles[tname].add_enum("CLK0.CLKMUX", str_or_default(ci->params, ctx->id("CLKMUX"), "CLK"));
} else if (ctx->getBoundWireNet(ctx->getWireByName(ctx->id(
fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/CLK1")))) == clknet) {
cc.tiles[tname].add_enum("CLK1.CLKMUX", str_or_default(ci->params, ctx->id("CLKMUX"), "CLK"));
}
}
if (str_or_default(ci->params, ctx->id("MODE"), "LOGIC") == "CCU2") {
@ -267,13 +278,23 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
str_or_default(ci->params, ctx->id("INJECT1_0"), "YES"));
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_1",
str_or_default(ci->params, ctx->id("INJECT1_1"), "YES"));
} else {
// Don't interfere with cascade mux wiring
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_0",
str_or_default(ci->params, ctx->id("INJECT1_0"), "_NONE_"));
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_1",
str_or_default(ci->params, ctx->id("INJECT1_1"), "_NONE_"));
}
if (str_or_default(ci->params, ctx->id("MODE"), "LOGIC") == "DPRAM" && slice == "SLICEA") {
cc.tiles[tname].add_enum(slice + ".WREMUX", str_or_default(ci->params, ctx->id("WREMUX"), "WRE"));
// FIXME: WCKMUX
NPNR_ASSERT(str_or_default(ci->params, ctx->id("WCKMUX"), "WCK") == "WCK");
NetInfo *wcknet = nullptr;
std::string wckmux = str_or_default(ci->params, ctx->id("WCKMUX"), "WCK");
wckmux = (wckmux == "WCK") ? "CLK" : wckmux;
if (ci->ports.find(ctx->id("WCK")) != ci->ports.end() && ci->ports.at(ctx->id("WCK")).net != nullptr)
wcknet = ci->ports.at(ctx->id("WCK")).net;
cc.tiles[tname].add_enum("CLK1.CLKMUX", wckmux);
}
// Tie unused inputs high

View File

@ -185,6 +185,8 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive
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"));
set_param_safe(has_ff, lc, ctx->id("CLKMUX"), str_or_default(ff->params, ctx->id("CLKMUX"), "CLK"));
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"));

View File

@ -128,6 +128,20 @@ class Ecp5Packer
return true;
}
// Return true if a FF can be added to a DPRAM slice
bool can_pack_ff_dram(CellInfo *dpram, CellInfo *ff)
{
std::string wckmux = str_or_default(dpram->params, ctx->id("WCKMUX"), "WCK");
std::string clkmux = str_or_default(ff->params, ctx->id("CLKMUX"), "CLK");
if (wckmux != clkmux && !(wckmux == "WCK" && clkmux == "CLK"))
return false;
std::string wremux = str_or_default(dpram->params, ctx->id("WREMUX"), "WRE");
std::string lsrmux = str_or_default(ff->params, ctx->id("LSRMUX"), "LSR");
if (wremux != lsrmux && !(wremux == "WRE" && lsrmux == "LSR"))
return false;
return true;
}
// Return true if two LUTs can be paired considering FF compatibility
bool can_pack_lutff(IdString lut0, IdString lut1)
{
@ -598,7 +612,7 @@ class Ecp5Packer
if (f0net != nullptr) {
ff0 = net_only_drives(ctx, f0net, is_ff, ctx->id("DI"), false);
if (ff0 != nullptr && can_add_ff_to_tile(tile_ffs, ff0)) {
if (net_or_nullptr(ff0, ctx->id("CLK")) == net_or_nullptr(slice, ctx->id("WCK"))) {
if (can_pack_ff_dram(slice, ff0)) {
ff_packing.push_back(std::make_tuple(ff0, slice, 0));
tile_ffs.push_back(ff0);
packed_cells.insert(ff0->name);
@ -612,7 +626,7 @@ class Ecp5Packer
ff1 = net_only_drives(ctx, f1net, is_ff, ctx->id("DI"), false);
if (ff1 != nullptr && (ff0 == nullptr || can_pack_ffs(ff0, ff1)) &&
can_add_ff_to_tile(tile_ffs, ff1)) {
if (net_or_nullptr(ff1, ctx->id("CLK")) == net_or_nullptr(slice, ctx->id("WCK"))) {
if (can_pack_ff_dram(slice, ff1)) {
ff_packing.push_back(std::make_tuple(ff1, slice, 1));
tile_ffs.push_back(ff1);
packed_cells.insert(ff1->name);