aboutsummaryrefslogtreecommitdiffstats
path: root/ice40
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-06-19 16:16:10 +0200
committerDavid Shah <davey1576@gmail.com>2018-06-19 16:16:10 +0200
commit8e26e4381be1e95479965756feba0237bd6e0582 (patch)
treefc94732f86ba9500a11b8f72c4f363d1f51ad8d0 /ice40
parent3bf68753bb6b4de2a970268849752dc05cde7795 (diff)
downloadnextpnr-8e26e4381be1e95479965756feba0237bd6e0582.tar.gz
nextpnr-8e26e4381be1e95479965756feba0237bd6e0582.tar.bz2
nextpnr-8e26e4381be1e95479965756feba0237bd6e0582.zip
ice40: WIP SB_CARRY packer
Signed-off-by: David Shah <davey1576@gmail.com>
Diffstat (limited to 'ice40')
-rw-r--r--ice40/cells.h10
-rw-r--r--ice40/pack.cc61
2 files changed, 71 insertions, 0 deletions
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<IdString> 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<IdString> 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<IdString> 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)
{