diff options
-rw-r--r-- | nexus/arch_place.cc | 2 | ||||
-rw-r--r-- | nexus/constids.inc | 2 | ||||
-rw-r--r-- | nexus/fasm.cc | 6 | ||||
-rw-r--r-- | nexus/pack.cc | 96 |
4 files changed, 103 insertions, 3 deletions
diff --git a/nexus/arch_place.cc b/nexus/arch_place.cc index feec75ad..35b14caf 100644 --- a/nexus/arch_place.cc +++ b/nexus/arch_place.cc @@ -59,6 +59,8 @@ bool Arch::nexus_logic_tile_valid(LogicTileStatus <s) const // If LUT1 is carry then LUT0 must be carry too if (lut1->lutInfo.is_carry && (lut0 == nullptr || !lut0->lutInfo.is_carry)) return false; + if (!lut1->lutInfo.is_carry && lut0 != nullptr && lut0->lutInfo.is_carry) + return false; } // Check for correct use of FF1 DI if (ff1 != nullptr && ff1->ffInfo.di != nullptr && (lut1 == nullptr || ff1->ffInfo.di != lut1->lutInfo.f)) diff --git a/nexus/constids.inc b/nexus/constids.inc index 0c01b577..8b1d2c89 100644 --- a/nexus/constids.inc +++ b/nexus/constids.inc @@ -205,3 +205,5 @@ X(CER) X(RST) X(WEAMUX) + +X(VCC_DRV) diff --git a/nexus/fasm.cc b/nexus/fasm.cc index bd710ae4..72efa5da 100644 --- a/nexus/fasm.cc +++ b/nexus/fasm.cc @@ -22,6 +22,8 @@ #include "nextpnr.h" #include "util.h" +#include <queue> + NEXTPNR_NAMESPACE_BEGIN namespace { struct NexusFasmWriter @@ -291,12 +293,10 @@ struct NexusFasmWriter push(stringf("SLICE%c", slice)); if (cell->params.count(id_INIT)) write_int_vector(stringf("K%d.INIT[15:0]", k), int_or_default(cell->params, id_INIT, 0), 16); -#if 0 if (cell->lutInfo.is_carry) { write_bit("MODE.CCU2"); - write_enum(cell, "INJECT", "NO"); + write_enum(cell, "CCU2.INJECT", "NO"); } -#endif pop(2); } // Write config for an OXIDE_FF cell diff --git a/nexus/pack.cc b/nexus/pack.cc index ea3b4aca..8ba986b5 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -448,6 +448,14 @@ struct NexusPacker // Pin is tied to a constant // If there is a hard constant option; use it if ((pin_style & int(req_mux)) == req_mux) { + + if (cell->type == id_OXIDE_COMB) { + // Due to potentially overlapping routing, explicitly keep the one-driver + // until can correctly use the dedicated Vcc route + if (str_or_default(cell->params, id_MODE, "LOGIC") != "LOGIC") + continue; + } + disconnect_port(ctx, cell, port_name); ctx->set_cell_pinmux(cell, port_name, req_mux); } else if (port.second.net == nullptr) { @@ -1120,6 +1128,93 @@ struct NexusPacker } } + void pack_carries() + { + // Find root carry cells + log_info("Packing carries...\n"); + std::vector<CellInfo *> roots; + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ci->type != id_CCU2) + continue; + if (get_net_or_empty(ci, id_CIN) != nullptr) + continue; + roots.push_back(ci); + } + for (CellInfo *root : roots) { + CellInfo *ci = root; + CellInfo *constr_base = nullptr; + int idx = 0; + do { + if (ci->type != id_CCU2) + log_error("Found non-carry cell '%s' in carry chain!\n", ctx->nameOf(ci)); + // Split the carry into two COMB cells + std::vector<CellInfo *> combs; + for (int i = 0; i < 2; i++) + combs.push_back( + ctx->createCell(ctx->id(stringf("%s$ccu2_comb[%d]$", ctx->nameOf(ci), i)), id_OXIDE_COMB)); + // Rewire LUT ports + for (int i = 0; i < 2; i++) { + combs[i]->params[id_MODE] = std::string("CCU2"); + replace_port(ci, bus_flat("A", i), combs[i], id_A); + replace_port(ci, bus_flat("B", i), combs[i], id_B); + replace_port(ci, bus_flat("C", i), combs[i], id_C); + replace_port(ci, bus_flat("D", i), combs[i], id_D); + replace_port(ci, bus_flat("S", i), combs[i], id_F); + } + + // External carry chain + replace_port(ci, id_CIN, combs[0], id_FCI); + replace_port(ci, id_COUT, combs[1], id_FCO); + + // Copy parameters + if (ci->params.count(id_INJECT)) + combs[0]->params[id_INJECT] = ci->params[id_INJECT]; + combs[0]->params[id_INIT] = ctx->parse_lattice_param(ci, id_INIT0, 16, 0); + combs[1]->params[id_INIT] = ctx->parse_lattice_param(ci, id_INIT1, 16, 0); + + // Internal carry net between the two split COMB cells + NetInfo *int_cy = ctx->createNet(ctx->id(stringf("%s$widefn_int_cy$", ctx->nameOf(ci)))); + combs[0]->addOutput(id_FCO); + combs[1]->addInput(id_FCI); + connect_port(ctx, int_cy, combs[0], id_FCO); + connect_port(ctx, int_cy, combs[1], id_FCI); + + // Relative constraints + for (int i = 0; i < 2; i++) { + int z = (idx % 8); + combs[i]->constr_z = ((z / 2) << 3) | (z % 2); + combs[i]->constr_abs_z = true; + if (constr_base == nullptr) { + // This is the very first cell in the chain + constr_base = combs[i]; + } else { + combs[i]->constr_x = (idx / 8); + combs[i]->constr_y = 0; + combs[i]->constr_parent = constr_base; + constr_base->constr_children.push_back(combs[i]); + } + + ++idx; + } + + ctx->cells.erase(ci->name); + + // Find next cell in chain, if it exists + NetInfo *fco = get_net_or_empty(combs[1], id_FCO); + ci = nullptr; + if (fco != nullptr) { + if (fco->users.size() > 1) + log_error("Carry cell '%s' has multiple fanout on FCO\n", ctx->nameOf(combs[1])); + else if (fco->users.size() == 1) { + NPNR_ASSERT(fco->users.at(0).port == id_CIN); + ci = fco->users.at(0).cell; + } + } + } while (ci != nullptr); + } + } + explicit NexusPacker(Context *ctx) : ctx(ctx) {} void operator()() @@ -1128,6 +1223,7 @@ struct NexusPacker convert_prims(); pack_bram(); pack_lutram(); + pack_carries(); pack_widefn(); pack_ffs(); pack_constants(); |