diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 4465d4e4..4a83bb30 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -211,4 +211,31 @@ void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index) replace_port(lut, ctx->id("Z"), lc, ctx->id("F" + std::to_string(index))); } +void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc) +{ + lc->params[ctx->id("MODE")] = "CCU2C"; + lc->params[ctx->id("LUT0_INITVAL")] = str_or_default(ccu->params, ctx->id("INIT0"), "0"); + lc->params[ctx->id("LUT1_INITVAL")] = str_or_default(ccu->params, ctx->id("INIT1"), "0"); + + lc->params[ctx->id("INJECT1_0")] = str_or_default(ccu->params, ctx->id("INJECT1_0"), "YES"); + lc->params[ctx->id("INJECT1_1")] = str_or_default(ccu->params, ctx->id("INJECT1_1"), "YES"); + + replace_port(ccu, ctx->id("CIN"), lc, ctx->id("FCI")); + + replace_port(ccu, ctx->id("A0"), lc, ctx->id("A0")); + replace_port(ccu, ctx->id("B0"), lc, ctx->id("B0")); + replace_port(ccu, ctx->id("C0"), lc, ctx->id("C0")); + replace_port(ccu, ctx->id("D0"), lc, ctx->id("D0")); + + replace_port(ccu, ctx->id("A1"), lc, ctx->id("A1")); + replace_port(ccu, ctx->id("B1"), lc, ctx->id("B1")); + replace_port(ccu, ctx->id("C1"), lc, ctx->id("C1")); + replace_port(ccu, ctx->id("D1"), lc, ctx->id("D1")); + + replace_port(ccu, ctx->id("S0"), lc, ctx->id("F0")); + replace_port(ccu, ctx->id("S1"), lc, ctx->id("F1")); + + replace_port(ccu, ctx->id("COUT"), lc, ctx->id("FCO")); +} + NEXTPNR_NAMESPACE_END diff --git a/ecp5/cells.h b/ecp5/cells.h index b0c74ca9..d2ea5490 100644 --- a/ecp5/cells.h +++ b/ecp5/cells.h @@ -48,6 +48,7 @@ inline bool is_l6mux(const BaseCtx *ctx, const CellInfo *cell) { return cell->ty void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool driven_by_lut); void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index); +void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc); NEXTPNR_NAMESPACE_END diff --git a/ecp5/pack.cc b/ecp5/pack.cc index d2c0085b..b17f8f20 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -108,7 +108,8 @@ class Ecp5Packer } // Return whether or not an FF can be added to a tile (pairing checks must also be done using the fn above) - bool can_add_ff_to_file(const std::vector &tile_ffs, CellInfo *ff0) { + bool can_add_ff_to_file(const std::vector &tile_ffs, CellInfo *ff0) + { for (const auto &existing : tile_ffs) { if (net_or_nullptr(existing, ctx->id("CLK")) != net_or_nullptr(ff0, ctx->id("CLK"))) return false; @@ -459,19 +460,19 @@ class Ecp5Packer return chains; } - // Pack carries and set up appropriate relative constraints - void pack_carries() { + void pack_carries() + { log_info("Packing carries...\n"); - auto chains = find_chains(ctx, [](const Context *ctx, const CellInfo *cell) { - return is_carry(ctx, cell); - }, [](const Context *ctx, const CellInfo *cell) { - return net_driven_by(ctx, cell->ports.at(ctx->id("CIN")).net, is_carry, ctx->id("COUT")); - }, [](const Context *ctx, const CellInfo *cell) { - return net_only_drives(ctx, cell->ports.at(ctx->id("COUT")).net, is_carry, - ctx->id("CIN"), false); - }, 1); - + auto chains = find_chains( + ctx, [](const Context *ctx, const CellInfo *cell) { return is_carry(ctx, cell); }, + [](const Context *ctx, const CellInfo *cell) { + return net_driven_by(ctx, cell->ports.at(ctx->id("CIN")).net, is_carry, ctx->id("COUT")); + }, + [](const Context *ctx, const CellInfo *cell) { + return net_only_drives(ctx, cell->ports.at(ctx->id("COUT")).net, is_carry, ctx->id("CIN"), false); + }, + 1); } // Pack LUTs that have been paired together