diff options
author | David Shah <davey1576@gmail.com> | 2018-06-26 15:55:50 +0200 |
---|---|---|
committer | David Shah <davey1576@gmail.com> | 2018-06-26 15:55:50 +0200 |
commit | 21d5a04501e411b8c1391606c1eafba5d4789c41 (patch) | |
tree | 874a37f8746845a37b492a259ae3c3a116a1c2b0 | |
parent | 6f12f2b7e8c58a0b14c6f1f3df2112b8860a6e4f (diff) | |
download | nextpnr-21d5a04501e411b8c1391606c1eafba5d4789c41.tar.gz nextpnr-21d5a04501e411b8c1391606c1eafba5d4789c41.tar.bz2 nextpnr-21d5a04501e411b8c1391606c1eafba5d4789c41.zip |
Carry chains now routable
Signed-off-by: David Shah <davey1576@gmail.com>
-rw-r--r-- | ice40/carry_tests/counter.v | 4 | ||||
-rw-r--r-- | ice40/main.cc | 2 | ||||
-rw-r--r-- | ice40/pack.cc | 21 | ||||
-rw-r--r-- | ice40/place_legaliser.cc | 52 |
4 files changed, 63 insertions, 16 deletions
diff --git a/ice40/carry_tests/counter.v b/ice40/carry_tests/counter.v index 8906ff45..1379a330 100644 --- a/ice40/carry_tests/counter.v +++ b/ice40/carry_tests/counter.v @@ -1,9 +1,9 @@ module top(input clk, cen, rst, ina, inb, output outa, outb, outc, outd); - reg [3:0] ctr = 0; + reg [15:0] ctr = 0; always @(posedge clk) ctr <= ctr + 1'b1; - assign {outa, outb, outc, outd} = ctr; + assign {outa, outb, outc, outd} = ctr[15:12]; endmodule diff --git a/ice40/main.cc b/ice40/main.cc index 7f913bb3..4fd16099 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -41,11 +41,11 @@ #include "nextpnr.h" #include "pack.h" #include "pcf.h" +#include "place_legaliser.h" #include "place_sa.h" #include "route.h" #include "timing.h" #include "version.h" -#include "place_legaliser.h" USING_NEXTPNR_NAMESPACE diff --git a/ice40/pack.cc b/ice40/pack.cc index 0d48d58c..6e4eade1 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -178,12 +178,27 @@ static void pack_carries(Context *ctx) std::unique_ptr<CellInfo> created_lc = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), cell.first.str(ctx) + "$CARRY"); carry_lc = created_lc.get(); + created_lc->ports.at(ctx->id("I1")).net = i0_net; + if (i0_net) { + PortRef pr; + pr.cell = created_lc.get(); + pr.port = ctx->id("I1"); + i0_net->users.push_back(pr); + } + created_lc->ports.at(ctx->id("I2")).net = i1_net; + if (i1_net) { + PortRef pr; + pr.cell = created_lc.get(); + pr.port = ctx->id("I2"); + i1_net->users.push_back(pr); + } new_cells.push_back(std::move(created_lc)); + } else { carry_lc = ctx->cells.at(*carry_lcs.begin()).get(); } } - carry_lc->attrs[ctx->id("CARRY_ENABLE")] = "1"; + carry_lc->params[ctx->id("CARRY_ENABLE")] = "1"; replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN")); replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT")); if (i0_net) { @@ -203,8 +218,8 @@ static void pack_carries(Context *ctx) if (carry_lc->ports.at(ctx->id("CIN")).net != nullptr) { IdString cin_net = carry_lc->ports.at(ctx->id("CIN")).net->name; if (cin_net == ctx->id("$PACKER_GND_NET") || cin_net == ctx->id("$PACKER_VCC_NET")) { - carry_lc->attrs[ctx->id("CIN_CONST")] = "1"; - carry_lc->attrs[ctx->id("CIN_SET")] = cin_net == ctx->id("$PACKER_VCC_NET") ? "1" : "0"; + carry_lc->params[ctx->id("CIN_CONST")] = "1"; + carry_lc->params[ctx->id("CIN_SET")] = cin_net == ctx->id("$PACKER_VCC_NET") ? "1" : "0"; carry_lc->ports.at(ctx->id("CIN")).net = nullptr; auto cin_users = ctx->nets.at(cin_net)->users; cin_users.erase( diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 8f5680bf..c783dd0f 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -129,15 +129,36 @@ class PlacementLegaliser std::vector<CellChain> carry_chains = find_chains( ctx, is_lc, [](const Context *ctx, const CellInfo *cell) { - return net_driven_by(ctx, cell->ports.at(ctx->id("CIN")).net, is_lc, ctx->id("COUT")); + CellInfo *carry_prev = + net_driven_by(ctx, cell->ports.at(ctx->id("CIN")).net, is_lc, ctx->id("COUT")); + if (carry_prev != nullptr) + return carry_prev; + CellInfo *i3_prev = net_driven_by(ctx, cell->ports.at(ctx->id("I3")).net, is_lc, ctx->id("COUT")); + if (i3_prev != nullptr) + return i3_prev; + return (CellInfo *)nullptr; }, [](const Context *ctx, const CellInfo *cell) { - return net_only_drives(ctx, cell->ports.at(ctx->id("COUT")).net, is_lc, ctx->id("CIN"), false); + CellInfo *carry_next = + net_only_drives(ctx, cell->ports.at(ctx->id("COUT")).net, is_lc, ctx->id("CIN"), false); + if (carry_next != nullptr) + return carry_next; + CellInfo *i3_next = + net_only_drives(ctx, cell->ports.at(ctx->id("COUT")).net, is_lc, ctx->id("I3"), false); + if (i3_next != nullptr) + return i3_next; + return (CellInfo *)nullptr; }); bool success = true; // Find midpoints for all chains, before we start tearing them up std::vector<CellChain> all_chains; for (auto &base_chain : carry_chains) { + if (ctx->verbose) { + log_info("Found carry chain: \n"); + for (auto entry : base_chain.cells) + log_info(" %s\n", entry->name.c_str(ctx)); + log_info("\n"); + } std::vector<CellChain> split_chains = split_carry_chain(base_chain); for (auto &chain : split_chains) { get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); @@ -146,6 +167,8 @@ class PlacementLegaliser } // Actual chain placement for (auto &chain : all_chains) { + if (ctx->verbose) + log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx)); float base_x = chain.mid_x, base_y = chain.mid_y - (chain.cells.size() / 16.0f); // Find Bel meeting requirements closest to the target base, returning location as <x, y, z> auto chain_origin_bel = find_closest_bel(base_x, base_y, int(chain.cells.size())); @@ -166,6 +189,9 @@ class PlacementLegaliser for (int i = 0; i < int(chain.cells.size()); i++) { int target_z = place_y * 8 + place_z + i; place_lc(chain.cells.at(i), place_x, target_z / 8, target_z % 8); + if (ctx->verbose) + log_info(" Cell '%s' placed at (%d, %d, %d)\n", chain.cells.at(i)->name.c_str(ctx), place_x, + target_z / 8, target_z % 8); } } return success; @@ -234,9 +260,13 @@ class PlacementLegaliser } else { NetInfo *carry_net = cell->ports.at(ctx->id("COUT")).net; if (carry_net != nullptr && carry_net->users.size() > 1) { - CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); - chains.back().cells.push_back(passout); - tile.push_back(passout); + if (carry_net->users.size() > 2 || + (net_only_drives(ctx, carry_net, is_lc, ctx->id("I3"), false) != + net_only_drives(ctx, carry_net, is_lc, ctx->id("CIN"), false))) { + CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); + chains.back().cells.push_back(passout); + tile.push_back(passout); + } } ++curr_cell; } @@ -257,8 +287,12 @@ class PlacementLegaliser rippedCells.insert(existing); ctx->unbindBel(bel); } + if (cell->bel != BelId()) { + ctx->unbindBel(cell->bel); + } ctx->bindBel(bel, cell->name, STRENGTH_LOCKED); - loc.second = true; // Bel is now unavailable for further use + rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place + loc.second = true; // Bel is now unavailable for further use } // Insert a logic cell to legalise a COUT->fabric connection @@ -324,12 +358,10 @@ class PlacementLegaliser bool placed = place_single_cell(ci); if (!placed) { if (ctx->force) { - log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), - ci->type.c_str(ctx)); + log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx)); success = false; } else { - log_error("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), - ci->type.c_str(ctx)); + log_error("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx)); } } } |