diff --git a/common/place_sa.cc b/common/place_sa.cc index 22e750c2..12ca30d8 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -66,39 +66,64 @@ static float random_float_upto(rnd_state &rnd, float limit) static int random_int_between(rnd_state &rnd, int a, int b) { - return a + int(random_float_upto(rnd, b - a)); + return a + int(random_float_upto(rnd, b - a) - 0.00001); } // Initial random placement static void place_initial(Design *design, CellInfo *cell, rnd_state &rnd) { - BelId best_bel = BelId(); - float best_score = std::numeric_limits::infinity(); - Chip &chip = design->chip; - if (cell->bel != BelId()) { - chip.unbindBel(cell->bel); - cell->bel = BelId(); - } - BelType targetType = belTypeFromId(cell->type); - for (auto bel : chip.getBels()) { - if (chip.getBelType(bel) == targetType && chip.checkBelAvail(bel) && - isValidBelForCell(design, cell, bel)) { - float score = random_float_upto(rnd, 1.0); - if (score <= best_score) { - best_score = score; - best_bel = bel; + bool all_placed = false; + int iters = 25; + while (!all_placed) { + BelId best_bel = BelId(); + float best_score = std::numeric_limits::infinity(), + best_ripup_score = std::numeric_limits::infinity(); + Chip &chip = design->chip; + CellInfo *ripup_target = nullptr; + BelId ripup_bel = BelId(); + if (cell->bel != BelId()) { + chip.unbindBel(cell->bel); + cell->bel = BelId(); + } + BelType targetType = belTypeFromId(cell->type); + for (auto bel : chip.getBels()) { + if (chip.getBelType(bel) == targetType && + isValidBelForCell(design, cell, bel)) { + if (chip.checkBelAvail(bel)) { + float score = random_float_upto(rnd, 1.0); + if (score <= best_score) { + best_score = score; + best_bel = bel; + } + } else { + float score = random_float_upto(rnd, 1.0); + if (score <= best_ripup_score) { + best_ripup_score = score; + ripup_target = + design->cells.at(chip.getBelCell(bel, true)); + ripup_bel = bel; + } + } } } - } - if (best_bel == BelId()) { - log_error("failed to place cell '%s' of type '%s'\n", - cell->name.c_str(), cell->type.c_str()); - } - cell->bel = best_bel; - chip.bindBel(cell->bel, cell->name); + if (best_bel == BelId()) { + if (iters == 0 || ripup_bel == BelId()) + log_error("failed to place cell '%s' of type '%s'\n", + cell->name.c_str(), cell->type.c_str()); + --iters; + chip.unbindBel(ripup_target->bel); + ripup_target->bel = BelId(); + best_bel = ripup_bel; + } else { + all_placed = true; + } + cell->bel = best_bel; + chip.bindBel(cell->bel, cell->name); - // Back annotate location - cell->attrs["BEL"] = chip.getBelName(cell->bel).str(); + // Back annotate location + cell->attrs["BEL"] = chip.getBelName(cell->bel).str(); + cell = ripup_target; + } } // Stores the state of the SA placer @@ -268,7 +293,7 @@ BelId random_bel_for_cell(Design *design, CellInfo *cell, SAState &state, } } -void place_design_sa(Design *design) +void place_design_sa(Design *design, int seed) { SAState state; @@ -304,7 +329,7 @@ void place_design_sa(Design *design) } log_info("place_constraints placed %d\n", int(placed_cells)); rnd_state rnd; - rnd.state = 1; + rnd.state = seed; std::vector autoplaced; // Sort to-place cells for deterministic initial placement for (auto cell : design->cells) { diff --git a/common/place_sa.h b/common/place_sa.h index f320111e..944cb97e 100644 --- a/common/place_sa.h +++ b/common/place_sa.h @@ -23,7 +23,7 @@ NEXTPNR_NAMESPACE_BEGIN -extern void place_design_sa(Design *design); +extern void place_design_sa(Design *design, int seed); NEXTPNR_NAMESPACE_END diff --git a/common/route.cc b/common/route.cc index 32212c7d..247c8840 100644 --- a/common/route.cc +++ b/common/route.cc @@ -440,8 +440,8 @@ void route_design(Design *design, bool verbose) "routing.\n", int(netsQueue.size())); - ripup_pip_penalty += 5; - ripup_wire_penalty += 5; + ripup_pip_penalty *= 1.5; + ripup_wire_penalty *= 1.5; } } diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 1c6361a1..3205fb6e 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -24,8 +24,8 @@ NEXTPNR_NAMESPACE_BEGIN -static const NetInfo *get_net_or_nullptr(const CellInfo *cell, - const IdString port) +static const NetInfo *get_net_or_empty(const CellInfo *cell, + const IdString port) { auto found = cell->ports.find(port); if (found != cell->ports.end()) @@ -38,46 +38,53 @@ static bool logicCellsCompatible(const std::vector &cells) { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; - std::unordered_set locals; + static std::unordered_set locals; + locals.clear(); for (auto cell : cells) { if (bool_or_default(cell->params, "DFF_ENABLE")) { if (!dffs_exist) { dffs_exist = true; - cen = get_net_or_nullptr(cell, "CEN"); - clk = get_net_or_nullptr(cell, "CLK"); - sr = get_net_or_nullptr(cell, "SR"); + cen = get_net_or_empty(cell, "CEN"); + clk = get_net_or_empty(cell, "CLK"); + sr = get_net_or_empty(cell, "SR"); - if (!is_global_net(cen)) - locals.insert(cen); - if (!is_global_net(clk)) - locals.insert(clk); - if (!is_global_net(sr)) - locals.insert(sr); + if (!is_global_net(cen) && cen != nullptr) + locals.insert(cen->name); + if (!is_global_net(clk) && clk != nullptr) + locals.insert(clk->name); + if (!is_global_net(sr) && sr != nullptr) + locals.insert(sr->name); if (bool_or_default(cell->params, "NEG_CLK")) { dffs_neg = true; } } else { - if (cen != get_net_or_nullptr(cell, "CEN")) + if (cen != get_net_or_empty(cell, "CEN")) return false; - if (clk != get_net_or_nullptr(cell, "CLK")) + if (clk != get_net_or_empty(cell, "CLK")) return false; - if (sr != get_net_or_nullptr(cell, "SR")) + if (sr != get_net_or_empty(cell, "SR")) return false; if (dffs_neg != bool_or_default(cell->params, "NEG_CLK")) return false; } } - locals.insert(get_net_or_nullptr(cell, "I0")); - locals.insert(get_net_or_nullptr(cell, "I1")); - locals.insert(get_net_or_nullptr(cell, "I2")); - locals.insert(get_net_or_nullptr(cell, "I3")); + const NetInfo *i0 = get_net_or_empty(cell, "I0"), + *i1 = get_net_or_empty(cell, "I1"), + *i2 = get_net_or_empty(cell, "I2"), + *i3 = get_net_or_empty(cell, "I3"); + if (i0 != nullptr) + locals.insert(i0->name); + if (i1 != nullptr) + locals.insert(i1->name); + if (i2 != nullptr) + locals.insert(i2->name); + if (i3 != nullptr) + locals.insert(i3->name); } - locals.erase(nullptr); // disconnected signals don't use local tracks - return locals.size() <= 32; } diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index c207f08c..4991df5e 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -19,6 +19,7 @@ */ #include "bitstream.h" #include +#include "log.h" NEXTPNR_NAMESPACE_BEGIN @@ -59,11 +60,16 @@ void set_config(const TileInfoPOD &ti, if (index == -1) { for (int i = 0; i < cfg.num_bits; i++) { int8_t &cbit = tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col); + if (cbit && !value) + log_error("clearing already set config bit %s", name.c_str()); cbit = value; } } else { int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col); cbit = value; + if (cbit && !value) + log_error("clearing already set config bit %s[%d]", name.c_str(), + index); } } @@ -179,7 +185,8 @@ void write_asc(const Design &design, std::ostream &out) for (int i = 0; i < 20; i++) set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), lc.at(i), i); - set_config(ti, config.at(y).at(x), "NegClk", neg_clk); + if (dff_enable) + set_config(ti, config.at(y).at(x), "NegClk", neg_clk); } else if (cell.second->type == "SB_IO") { const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; unsigned pin_type = get_param_or_def(cell.second, "PIN_TYPE"); diff --git a/ice40/main.cc b/ice40/main.cc index eb92d92f..c43bffa7 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -82,6 +82,8 @@ int main(int argc, char *argv[]) "PCF constraints file to ingest"); options.add_options()("asc", po::value(), "asc bitstream file to write"); + options.add_options()("seed", po::value(), + "seed value for random number generator"); options.add_options()("version,V", "show version"); options.add_options()("lp384", "set device type to iCE40LP384"); options.add_options()("lp1k", "set device type to iCE40LP1K"); @@ -223,8 +225,16 @@ int main(int argc, char *argv[]) pack_design(&design); print_utilisation(&design); + + int seed = 1; + if (vm.count("seed")) { + seed = vm["seed"].as(); + if (seed == 0) + log_error("seed must be non-zero value"); + } + if (!vm.count("pack-only")) { - place_design_sa(&design); + place_design_sa(&design, seed); route_design(&design, verbose); } } diff --git a/ice40/pack.cc b/ice40/pack.cc index 0b76f3f3..3e852a91 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -279,7 +279,9 @@ static void pack_io(Design *design) static void insert_global(Design *design, NetInfo *net, bool is_reset, bool is_cen) { - CellInfo *gb = create_ice_cell(design, "SB_GB"); + std::string glb_name = net->name.str() + std::string("_$glb_") + + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); + CellInfo *gb = create_ice_cell(design, "SB_GB", "$gbuf_" + glb_name); gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = net; PortRef pr; pr.cell = gb; @@ -289,8 +291,7 @@ static void insert_global(Design *design, NetInfo *net, bool is_reset, pr.cell = gb; pr.port = "GLOBAL_BUFFER_OUTPUT"; NetInfo *glbnet = new NetInfo(); - glbnet->name = net->name.str() + std::string("_glb_") + - (is_reset ? "sr" : (is_cen ? "ce" : "clk")); + glbnet->name = glb_name; glbnet->driver = pr; design->nets[glbnet->name] = glbnet; gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet; @@ -363,19 +364,22 @@ static void promote_globals(Design *design) ++prom_resets; clock_count.erase(rstnet->name); reset_count.erase(rstnet->name); - + cen_count.erase(rstnet->name); } else if (global_cen->second > global_clock->second && prom_cens < 4) { NetInfo *cennet = design->nets[global_cen->first]; insert_global(design, cennet, false, true); ++prom_globals; ++prom_cens; - cen_count.erase(cennet->name); clock_count.erase(cennet->name); + reset_count.erase(cennet->name); + cen_count.erase(cennet->name); } else if (global_clock->second != 0) { NetInfo *clknet = design->nets[global_clock->first]; insert_global(design, clknet, false, false); ++prom_globals; clock_count.erase(clknet->name); + reset_count.erase(clknet->name); + cen_count.erase(clknet->name); } else { break; }