From 6f12f2b7e8c58a0b14c6f1f3df2112b8860a6e4f Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 26 Jun 2018 15:06:59 +0200 Subject: [PATCH] Working on debugging the carry legaliser Signed-off-by: David Shah --- common/util.h | 10 ++++++++++ ice40/carry_tests/test.sh | 22 +++++++++++----------- ice40/main.cc | 2 ++ ice40/pack.cc | 8 ++++---- ice40/place_legaliser.cc | 38 +++++++++++++++++++++++++++++++++++++- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/common/util.h b/common/util.h index c888c8b8..a9ad2172 100644 --- a/common/util.h +++ b/common/util.h @@ -21,6 +21,7 @@ #define UTIL_H #include +#include #include #include "nextpnr.h" @@ -65,6 +66,15 @@ template std::map sorted(const std::unordered_m return retVal; }; +// Wrap an unordered_set, and allow it to be iterated over sorted by key +template std::set sorted(const std::unordered_set &orig) +{ + std::set retVal; + for (auto &item : orig) + retVal.insert(item); + return retVal; +}; + NEXTPNR_NAMESPACE_END #endif diff --git a/ice40/carry_tests/test.sh b/ice40/carry_tests/test.sh index 47a9e5ef..9f6b00b2 100755 --- a/ice40/carry_tests/test.sh +++ b/ice40/carry_tests/test.sh @@ -2,15 +2,15 @@ set -ex NAME=${1%.v} yosys -p "synth_ice40 -top top; write_json ${NAME}.json" $1 -../../nextpnr-ice40 --json ${NAME}.json --pcf test.pcf --asc ${NAME}.asc --verbose -icebox_vlog -p test.pcf ${NAME}.asc > ${NAME}_out.v +../../nextpnr-ice40 --force --json ${NAME}.json --pcf test.pcf --asc ${NAME}.asc --verbose ../../python/dump_design.py +#icebox_vlog -p test.pcf ${NAME}.asc > ${NAME}_out.v -yosys -p "read_verilog +/ice40/cells_sim.v;\ - rename chip gate;\ - read_verilog $1;\ - rename top gold;\ - hierarchy;\ - proc;\ - clk2fflogic;\ - miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter;\ - sat -dump_vcd equiv_${NAME}.vcd -verify-no-timeout -timeout 60 -seq 50 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter" ${NAME}_out.v +#yosys -p "read_verilog +/ice40/cells_sim.v;\ +# rename chip gate;\ +# read_verilog $1;\ +# rename top gold;\ +# hierarchy;\ +# proc;\ +# clk2fflogic;\ +# miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter;\ +# sat -dump_vcd equiv_${NAME}.vcd -verify-no-timeout -timeout 60 -seq 50 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter" ${NAME}_out.v diff --git a/ice40/main.cc b/ice40/main.cc index 8babf8b9..7f913bb3 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -45,6 +45,7 @@ #include "route.h" #include "timing.h" #include "version.h" +#include "place_legaliser.h" USING_NEXTPNR_NAMESPACE @@ -375,6 +376,7 @@ int main(int argc, char *argv[]) if (!vm.count("pack-only")) { if (!place_design_sa(&ctx, timing_driven) && !ctx.force) log_error("Placing design failed.\n"); + legalise_design(&ctx); if (!route_design(&ctx) && !ctx.force) log_error("Routing design failed.\n"); } diff --git a/ice40/pack.cc b/ice40/pack.cc index 3a255257..0d48d58c 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -126,7 +126,6 @@ static void pack_carries(Context *ctx) packed_cells.insert(cell.first); CellInfo *carry_ci_lc = net_only_drives(ctx, ci->ports.at(ctx->id("CI")).net, is_lc, ctx->id("I3"), false); - std::set i0_matches, i1_matches; NetInfo *i0_net = ci->ports.at(ctx->id("I0")).net; NetInfo *i1_net = ci->ports.at(ctx->id("I1")).net; @@ -161,9 +160,9 @@ static void pack_carries(Context *ctx) if (carry_ci_lc) { if (carry_lcs.find(carry_ci_lc->name) == carry_lcs.end()) { if (ctx->verbose) { - for(auto i0 : i0_matches) + for (auto i0 : i0_matches) log_info("I0 candidate: '%s'\n", i0.c_str(ctx)); - for(auto i1 : i1_matches) + for (auto i1 : i1_matches) log_info("I1 candidate: '%s'\n", i1.c_str(ctx)); log_info("I3 connects to: '%s'\n", carry_ci_lc->name.c_str(ctx)); } @@ -275,7 +274,8 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne CellInfo *uc = user.cell; if (ctx->verbose) log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); - if ((is_lut(ctx, uc) || is_lc(ctx, uc) || is_carry(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && !constval) { + if ((is_lut(ctx, uc) || is_lc(ctx, uc) || is_carry(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && + !constval) { uc->ports[user.port].net = nullptr; } else { uc->ports[user.port].net = constnet; diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 29dab0a0..8f5680bf 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -93,11 +93,13 @@ class PlacementLegaliser bool legalise() { + log_info("Legalising design..\n"); init_logic_cells(); bool legalised_carries = legalise_carries(); if (!legalised_carries && !ctx->force) return false; - return legalised_carries; + bool replaced_cells = replace_cells(); + return legalised_carries && replaced_cells; } private: @@ -313,6 +315,40 @@ class PlacementLegaliser return ctx->cells[name].get(); } + // Replace ripped-up cells + bool replace_cells() + { + bool success = true; + for (auto cell : sorted(rippedCells)) { + CellInfo *ci = ctx->cells.at(cell).get(); + 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)); + success = false; + } else { + log_error("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), + ci->type.c_str(ctx)); + } + } + } + return success; + } + + // Place a single cell in the first valid location + bool place_single_cell(CellInfo *cell) + { + BelType tgtType = ctx->belTypeFromId(cell->type); + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) == tgtType && ctx->checkBelAvail(bel) && ctx->isValidBelForCell(cell, bel)) { + ctx->bindBel(bel, cell->name, STRENGTH_WEAK); + return true; + } + } + return false; + } + Context *ctx; std::unordered_set rippedCells; std::unordered_set createdCells;