diff options
author | David Shah <davey1576@gmail.com> | 2018-10-02 15:50:45 +0100 |
---|---|---|
committer | David Shah <davey1576@gmail.com> | 2018-10-02 15:50:45 +0100 |
commit | bf7161d2b49ff5660626a0ac4af5a7eeb3fb77c1 (patch) | |
tree | e1a95a4363d9771392b62d056360c23236f7b5c9 | |
parent | 8cbc92b7f3cd106363ee115c4ec6a9f2bbaba8c8 (diff) | |
download | nextpnr-bf7161d2b49ff5660626a0ac4af5a7eeb3fb77c1.tar.gz nextpnr-bf7161d2b49ff5660626a0ac4af5a7eeb3fb77c1.tar.bz2 nextpnr-bf7161d2b49ff5660626a0ac4af5a7eeb3fb77c1.zip |
ecp5: Negative clock support, general slice improvements
Signed-off-by: David Shah <davey1576@gmail.com>
-rw-r--r-- | ecp5/bitstream.cc | 25 | ||||
-rw-r--r-- | ecp5/cells.cc | 2 | ||||
-rw-r--r-- | ecp5/pack.cc | 18 |
3 files changed, 41 insertions, 4 deletions
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 0c2d511d..296ea753 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -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 diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 815ae228..a728104d 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -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")); diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 60ac55f6..0045617b 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -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); |