From 8e26e4381be1e95479965756feba0237bd6e0582 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Jun 2018 16:16:10 +0200 Subject: [PATCH] ice40: WIP SB_CARRY packer Signed-off-by: David Shah --- ice40/cells.h | 10 +++++++++ ice40/pack.cc | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/ice40/cells.h b/ice40/cells.h index 19568ed0..36c1ba19 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -60,6 +60,16 @@ inline bool is_ff(const Context *ctx, const CellInfo *cell) cell->type == ctx->id("SB_DFFNES"); } +inline bool is_carry(const Context *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("SB_CARRY"); +} + +inline bool is_lc(const Context *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("ICESTORM_LC"); +} + // Return true if a cell is a SB_IO inline bool is_sb_io(const Context *ctx, const CellInfo *cell) { diff --git a/ice40/pack.cc b/ice40/pack.cc index d3f07118..4b470ba9 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -114,6 +114,67 @@ static void pack_nonlut_ffs(Context *ctx) } } + +// Pack carry logic +static void pack_carries(Context *ctx) +{ + log_info("Packing carries..\n"); + + std::unordered_set packed_cells; + + for (auto cell : ctx->cells) { + CellInfo *ci = cell.second; + if (is_carry(ctx, ci)) { + packed_cells.insert(cell.first); + CellInfo *carry_ci_lc = net_only_drives(ctx, ci->ports.at("CI").net, + is_lc, "I3", false); + if (!ci->ports.at("I0").net) + log_error("SB_CARRY '%s' has disconnect port I0\n", cell.first.c_str(ctx)); + if (!ci->ports.at("I1").net) + log_error("SB_CARRY '%s' has disconnect port I1\n", cell.first.c_str(ctx)); + + std::unordered_set i0_matches, i1_matches; + auto &i0_usrs = ci->ports.at("I0").net->users; + auto &i1_usrs = ci->ports.at("I1").net->users; + + for (auto usr : i0_usrs) { + if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I1")) + i0_matches.insert(usr.cell->name); + } + for (auto usr : i1_usrs) { + if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I2")) + i1_matches.insert(usr.cell->name); + } + std::set carry_lcs; + std::set_intersection(i0_matches.begin(), i0_matches.end(), i1_matches.begin(), i1_matches.end(), std::inserter(carry_lcs, carry_lcs.begin())); + CellInfo *carry_lc = nullptr; + if (carry_ci_lc) { + if (carry_lcs.find(carry_ci_lc->name) == carry_lcs.end()) + log_error("SB_CARRY '%s' cannot be packed into any logic cell (I0 and I1 connections do not match I3 connection)\n", cell.first.c_str(ctx)); + carry_lc = carry_ci_lc; + } else { + if (carry_lcs.empty()) + log_error("SB_CARRY '%s' cannot be packed into any logic cell (no logic cell connects both I0 and I1)\n", cell.first.c_str(ctx)); + carry_lc = ctx->cells.at(*carry_lcs.begin()); + } + carry_lc->attrs[ctx->id("CARRY_ENABLE")] = "1"; + replace_port(ci, "CI", carry_lc, "CIN"); + replace_port(ci, "CO", carry_lc, "COUT"); + + i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), [ci, ctx] (const PortRef &pr){ + return pr.cell == ci && pr.port == ctx->id("I0"); + })); + + i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(), [ci, ctx] (const PortRef &pr){ + return pr.cell == ci && pr.port == ctx->id("I1"); + })); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } +} + // "Pack" RAMs static void pack_ram(Context *ctx) {