diff --git a/common/nextpnr.h b/common/nextpnr.h index 8d4714bf..b647d44c 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -230,7 +230,7 @@ struct Context : Arch bool debug = false; bool force = false; bool timing_driven = true; - + float target_freq = 12e6; Context(ArchArgs args) : Arch(args) {} // -------------------------------------------------------------- diff --git a/common/place_common.cc b/common/place_common.cc index 95faf67f..60735890 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -91,7 +91,7 @@ wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell) return wirelength; } -static wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel) +wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel) { BelId oldBel = cell->bel; cell->bel = bel; diff --git a/common/place_common.h b/common/place_common.h index f58da450..67956072 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -32,6 +32,9 @@ wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) // Return the wirelength of all nets connected to a cell wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell); +// Return the wirelength of all nets connected to a cell, when the cell is at a given bel +wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel); + // Place a single cell in the lowest wirelength Bel available, optionally requiring validity check bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality); diff --git a/common/place_sa.cc b/common/place_sa.cc index c0c1b180..b773bb68 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -207,7 +207,8 @@ class SAPlacer temp *= 0.8; } } - + // Once cooled below legalise threshold, run legalisation and start requiring + // legal moves only if (temp < legalise_temp && !require_legal) { legalise_design(ctx); require_legal = true; @@ -219,6 +220,7 @@ class SAPlacer temp = post_legalise_temp; diameter *= post_legalise_dia_scale; ctx->shuffle(autoplaced); + assign_budget(ctx); } // Recalculate total wirelength entirely to avoid rounding errors diff --git a/common/timing.cc b/common/timing.cc index 9b10068e..3a48935f 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -70,12 +70,12 @@ static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t s return net_budget; } -void assign_budget(Context *ctx, float default_clock) +void assign_budget(Context *ctx) { log_break(); log_info("Annotating ports with timing budgets\n"); // Clear delays to a very high value first - delay_t default_slack = delay_t(1.0e12 / default_clock); + delay_t default_slack = delay_t(1.0e12 / ctx->target_freq); for (auto &net : ctx->nets) { for (auto &usr : net.second->users) { usr.budget = default_slack; @@ -87,7 +87,7 @@ void assign_budget(Context *ctx, float default_clock) if (port.second.type == PORT_OUT) { IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first); if (clock_domain != IdString()) { - delay_t slack = delay_t(1.0e12 / default_clock); // TODO: clock constraints + delay_t slack = delay_t(1.0e12 / ctx->target_freq); // TODO: clock constraints if (port.second.net) follow_net(ctx, port.second.net, 0, slack); } diff --git a/common/timing.h b/common/timing.h index 03ae048d..025e4a76 100644 --- a/common/timing.h +++ b/common/timing.h @@ -25,7 +25,7 @@ NEXTPNR_NAMESPACE_BEGIN // Assign "budget" values for all user ports in the design -void assign_budget(Context *ctx, float default_clock = 12e6); +void assign_budget(Context *ctx); NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index acf32554..ab82b6bb 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -111,7 +111,8 @@ void Worker::budget(double freq) { Q_EMIT taskStarted(); try { - assign_budget(ctx, freq); + ctx->target_freq = freq; + assign_budget(ctx); Q_EMIT budget_finish(true); } catch (WorkerInterruptionRequested) { Q_EMIT taskCanceled(); diff --git a/ice40/main.cc b/ice40/main.cc index 26b0affa..87a32ded 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -360,10 +360,9 @@ int main(int argc, char *argv[]) if (!pack_design(&ctx) && !ctx.force) log_error("Packing design failed.\n"); - double freq = 50e6; if (vm.count("freq")) - freq = vm["freq"].as() * 1e6; - assign_budget(&ctx, freq); + ctx.target_freq = vm["freq"].as() * 1e6; + assign_budget(&ctx); ctx.check(); print_utilisation(&ctx); ctx.timing_driven = true; diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index ec7a53d3..9e279f25 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -216,7 +216,7 @@ class PlacementLegaliser 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 - auto chain_origin_bel = find_closest_bel(base_x, base_y, int(chain.cells.size())); + auto chain_origin_bel = find_closest_bel(base_x, base_y, chain); int place_x = std::get<0>(chain_origin_bel), place_y = std::get<1>(chain_origin_bel), place_z = std::get<2>(chain_origin_bel); if (place_x == -1) { @@ -243,27 +243,29 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple find_closest_bel(float target_x, float target_y, int chain_size) + std::tuple find_closest_bel(float target_x, float target_y, CellChain &chain) { std::tuple best_origin = std::make_tuple(-1, -1, -1); - float smallest_distance = std::numeric_limits::infinity(); + wirelen_t best_wirelength = std::numeric_limits::max(); int width = ctx->chip_info->width, height = ctx->chip_info->height; // Slow, should radiate outwards from target position - TODO + int chain_size = int(chain.cells.size()); for (int x = 1; x < width; x++) { for (int y = 1; y < (height - (chain_size / 8)); y++) { bool valid = true; + wirelen_t wirelen = 0; for (int k = 0; k < chain_size; k++) { - if (logic_bels.at(x).at(y + k / 8).at(k % 8).second) { + auto &lb = logic_bels.at(x).at(y + k / 8).at(k % 8); + if (lb.second) { valid = false; break; + } else { + wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first); } } - if (valid) { - float distance = (x - target_x) * (x - target_x) + (y - target_y) * (y - target_y); - if (distance < smallest_distance) { - smallest_distance = distance; - best_origin = std::make_tuple(x, y, 0); - } + if (valid && wirelen < best_wirelength) { + best_wirelength = wirelen; + best_origin = std::make_tuple(x, y, 0); } } }