Improving the SA+legalisation flow
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
d908928b56
commit
27e7bc3b4b
@ -230,7 +230,7 @@ struct Context : Arch
|
|||||||
bool debug = false;
|
bool debug = false;
|
||||||
bool force = false;
|
bool force = false;
|
||||||
bool timing_driven = true;
|
bool timing_driven = true;
|
||||||
|
float target_freq = 12e6;
|
||||||
Context(ArchArgs args) : Arch(args) {}
|
Context(ArchArgs args) : Arch(args) {}
|
||||||
|
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
@ -91,7 +91,7 @@ wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell)
|
|||||||
return wirelength;
|
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;
|
BelId oldBel = cell->bel;
|
||||||
cell->bel = bel;
|
cell->bel = bel;
|
||||||
|
@ -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
|
// Return the wirelength of all nets connected to a cell
|
||||||
wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *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
|
// 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);
|
bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality);
|
||||||
|
|
||||||
|
@ -207,7 +207,8 @@ class SAPlacer
|
|||||||
temp *= 0.8;
|
temp *= 0.8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Once cooled below legalise threshold, run legalisation and start requiring
|
||||||
|
// legal moves only
|
||||||
if (temp < legalise_temp && !require_legal) {
|
if (temp < legalise_temp && !require_legal) {
|
||||||
legalise_design(ctx);
|
legalise_design(ctx);
|
||||||
require_legal = true;
|
require_legal = true;
|
||||||
@ -219,6 +220,7 @@ class SAPlacer
|
|||||||
temp = post_legalise_temp;
|
temp = post_legalise_temp;
|
||||||
diameter *= post_legalise_dia_scale;
|
diameter *= post_legalise_dia_scale;
|
||||||
ctx->shuffle(autoplaced);
|
ctx->shuffle(autoplaced);
|
||||||
|
assign_budget(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate total wirelength entirely to avoid rounding errors
|
// Recalculate total wirelength entirely to avoid rounding errors
|
||||||
|
@ -70,12 +70,12 @@ static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t s
|
|||||||
return net_budget;
|
return net_budget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign_budget(Context *ctx, float default_clock)
|
void assign_budget(Context *ctx)
|
||||||
{
|
{
|
||||||
log_break();
|
log_break();
|
||||||
log_info("Annotating ports with timing budgets\n");
|
log_info("Annotating ports with timing budgets\n");
|
||||||
// Clear delays to a very high value first
|
// 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 &net : ctx->nets) {
|
||||||
for (auto &usr : net.second->users) {
|
for (auto &usr : net.second->users) {
|
||||||
usr.budget = default_slack;
|
usr.budget = default_slack;
|
||||||
@ -87,7 +87,7 @@ void assign_budget(Context *ctx, float default_clock)
|
|||||||
if (port.second.type == PORT_OUT) {
|
if (port.second.type == PORT_OUT) {
|
||||||
IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first);
|
IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first);
|
||||||
if (clock_domain != IdString()) {
|
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)
|
if (port.second.net)
|
||||||
follow_net(ctx, port.second.net, 0, slack);
|
follow_net(ctx, port.second.net, 0, slack);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// Assign "budget" values for all user ports in the design
|
// 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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -111,7 +111,8 @@ void Worker::budget(double freq)
|
|||||||
{
|
{
|
||||||
Q_EMIT taskStarted();
|
Q_EMIT taskStarted();
|
||||||
try {
|
try {
|
||||||
assign_budget(ctx, freq);
|
ctx->target_freq = freq;
|
||||||
|
assign_budget(ctx);
|
||||||
Q_EMIT budget_finish(true);
|
Q_EMIT budget_finish(true);
|
||||||
} catch (WorkerInterruptionRequested) {
|
} catch (WorkerInterruptionRequested) {
|
||||||
Q_EMIT taskCanceled();
|
Q_EMIT taskCanceled();
|
||||||
|
@ -360,10 +360,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (!pack_design(&ctx) && !ctx.force)
|
if (!pack_design(&ctx) && !ctx.force)
|
||||||
log_error("Packing design failed.\n");
|
log_error("Packing design failed.\n");
|
||||||
double freq = 50e6;
|
|
||||||
if (vm.count("freq"))
|
if (vm.count("freq"))
|
||||||
freq = vm["freq"].as<double>() * 1e6;
|
ctx.target_freq = vm["freq"].as<double>() * 1e6;
|
||||||
assign_budget(&ctx, freq);
|
assign_budget(&ctx);
|
||||||
ctx.check();
|
ctx.check();
|
||||||
print_utilisation(&ctx);
|
print_utilisation(&ctx);
|
||||||
ctx.timing_driven = true;
|
ctx.timing_driven = true;
|
||||||
|
@ -216,7 +216,7 @@ class PlacementLegaliser
|
|||||||
log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx));
|
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);
|
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>
|
// 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()));
|
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),
|
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);
|
place_z = std::get<2>(chain_origin_bel);
|
||||||
if (place_x == -1) {
|
if (place_x == -1) {
|
||||||
@ -243,27 +243,29 @@ class PlacementLegaliser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find Bel closest to a location, meeting chain requirements
|
// Find Bel closest to a location, meeting chain requirements
|
||||||
std::tuple<int, int, int> find_closest_bel(float target_x, float target_y, int chain_size)
|
std::tuple<int, int, int> find_closest_bel(float target_x, float target_y, CellChain &chain)
|
||||||
{
|
{
|
||||||
std::tuple<int, int, int> best_origin = std::make_tuple(-1, -1, -1);
|
std::tuple<int, int, int> best_origin = std::make_tuple(-1, -1, -1);
|
||||||
float smallest_distance = std::numeric_limits<float>::infinity();
|
wirelen_t best_wirelength = std::numeric_limits<wirelen_t>::max();
|
||||||
int width = ctx->chip_info->width, height = ctx->chip_info->height;
|
int width = ctx->chip_info->width, height = ctx->chip_info->height;
|
||||||
// Slow, should radiate outwards from target position - TODO
|
// Slow, should radiate outwards from target position - TODO
|
||||||
|
int chain_size = int(chain.cells.size());
|
||||||
for (int x = 1; x < width; x++) {
|
for (int x = 1; x < width; x++) {
|
||||||
for (int y = 1; y < (height - (chain_size / 8)); y++) {
|
for (int y = 1; y < (height - (chain_size / 8)); y++) {
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
|
wirelen_t wirelen = 0;
|
||||||
for (int k = 0; k < chain_size; k++) {
|
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;
|
valid = false;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (valid) {
|
if (valid && wirelen < best_wirelength) {
|
||||||
float distance = (x - target_x) * (x - target_x) + (y - target_y) * (y - target_y);
|
best_wirelength = wirelen;
|
||||||
if (distance < smallest_distance) {
|
best_origin = std::make_tuple(x, y, 0);
|
||||||
smallest_distance = distance;
|
|
||||||
best_origin = std::make_tuple(x, y, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user