Merge pull request #391 from YosysHQ/router2-upstream

Upstreaming router2
This commit is contained in:
David Shah 2020-02-04 16:08:08 +00:00 committed by GitHub
commit 1ceffbe0bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1424 additions and 14 deletions

View File

@ -132,6 +132,12 @@ po::options_description CommandHandler::getGeneralOptions()
"; default: " + Arch::defaultPlacer)
.c_str());
general.add_options()(
"router", po::value<std::string>(),
std::string("router algorithm to use; available: " + boost::algorithm::join(Arch::availableRouters, ", ") +
"; default: " + Arch::defaultPlacer)
.c_str());
general.add_options()("slack_redist_iter", po::value<int>(), "number of iterations between slack redistribution");
general.add_options()("cstrweight", po::value<float>(), "placer weighting for relative constraint satisfaction");
general.add_options()("starttemp", po::value<float>(), "placer SA start temperature");
@ -214,6 +220,15 @@ void CommandHandler::setupContext(Context *ctx)
ctx->settings[ctx->id("placer")] = placer;
}
if (vm.count("router")) {
std::string router = vm["router"].as<std::string>();
if (std::find(Arch::availableRouters.begin(), Arch::availableRouters.end(), router) ==
Arch::availableRouters.end())
log_error("Router algorithm '%s' is not supported (available options: %s)\n", router.c_str(),
boost::algorithm::join(Arch::availableRouters, ", ").c_str());
ctx->settings[ctx->id("router")] = router;
}
if (vm.count("cstrweight")) {
ctx->settings[ctx->id("placer1/constraintWeight")] = std::to_string(vm["cstrweight"].as<float>());
}
@ -244,6 +259,8 @@ void CommandHandler::setupContext(Context *ctx)
ctx->settings[ctx->id("auto_freq")] = false;
if (ctx->settings.find(ctx->id("placer")) == ctx->settings.end())
ctx->settings[ctx->id("placer")] = Arch::defaultPlacer;
if (ctx->settings.find(ctx->id("router")) == ctx->settings.end())
ctx->settings[ctx->id("router")] = Arch::defaultRouter;
ctx->settings[ctx->id("arch.name")] = std::string(ctx->archId().c_str(ctx));
ctx->settings[ctx->id("arch.type")] = std::string(ctx->archArgsToId(ctx->archArgs()).c_str(ctx));

View File

@ -199,6 +199,28 @@ struct Loc
bool operator!=(const Loc &other) const { return (x != other.x) || (y != other.y) || (z != other.z); }
};
struct ArcBounds
{
int x0 = -1, y0 = -1, x1 = -1, y1 = -1;
ArcBounds() {}
ArcBounds(int x0, int y0, int x1, int y1) : x0(x0), y0(y0), x1(x1), y1(y1){};
int distance(Loc loc) const
{
int dist = 0;
if (loc.x < x0)
dist += x0 - loc.x;
if (loc.x > x1)
dist += loc.x - x1;
if (loc.y < y0)
dist += y0 - loc.y;
if (loc.y > y1)
dist += loc.y - y1;
return dist;
};
};
struct TimingConstrObjectId
{
int32_t index = -1;

View File

@ -609,9 +609,10 @@ class SAPlacer
std::vector<std::pair<CellInfo *, BelId>> dest_bels;
double delta = 0;
moveChange.reset(this);
#if 0
if (ctx->debug)
log_info("finding cells for chain swap %s\n", cell->name.c_str(ctx));
#endif
Loc baseLoc = ctx->getBelLocation(cell->bel);
discover_chain(baseLoc, cell, cell_rel);
Loc newBaseLoc = ctx->getBelLocation(newBase);
@ -634,8 +635,10 @@ class SAPlacer
return false;
dest_bels.emplace_back(std::make_pair(cr.first, targetBel));
}
#if 0
if (ctx->debug)
log_info("trying chain swap %s\n", cell->name.c_str(ctx));
#endif
// <cell, oldBel>
for (const auto &db : dest_bels) {
BelId oldBel = swap_cell_bels(db.first, db.second);
@ -661,8 +664,10 @@ class SAPlacer
// SA acceptance criterea
if (delta < 0 || (temp > 1e-9 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) {
n_accept++;
#if 0
if (ctx->debug)
log_info("accepted chain swap %s\n", cell->name.c_str(ctx));
#endif
} else {
goto swap_fail;
}

View File

@ -837,7 +837,7 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
std::chrono::duration<float>(rend - rstart).count());
log_info("Routing complete.\n");
ctx->yield();
log_info("Route time %.02fs\n", std::chrono::duration<float>(rend - rstart).count());
log_info("Router1 time %.02fs\n", std::chrono::duration<float>(rend - rstart).count());
#ifndef NDEBUG
router.check();

1132
common/router2.cc Normal file

File diff suppressed because it is too large Load Diff

56
common/router2.h Normal file
View File

@ -0,0 +1,56 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2019 David Shah <dave@ds0.me>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
struct Router2Cfg
{
Router2Cfg(Context *ctx);
// Maximum iterations for backwards routing attempt
int backwards_max_iter;
// Maximum iterations for backwards routing attempt for global nets
int global_backwards_max_iter;
// Padding added to bounding boxes to account for imperfect routing,
// congestion, etc
int bb_margin_x, bb_margin_y;
// Cost factor added to input pin wires; effectively reduces the
// benefit of sharing interconnect
float ipin_cost_adder;
// Cost factor for "bias" towards center location of net
float bias_cost_factor;
// Starting current and historical congestion cost factor
float init_curr_cong_weight, hist_cong_weight;
// Current congestion cost multiplier
float curr_cong_mult;
// Weight given to delay estimate in A*. Higher values
// mean faster and more directed routing, at the risk
// of choosing a less congestion/delay-optimal route
float estimate_weight;
// Print additional performance profiling information
bool perf_profile = false;
};
void router2(Context *ctx, const Router2Cfg &cfg);
NEXTPNR_NAMESPACE_END

View File

@ -237,6 +237,13 @@ Get a list of all wires on the device.
Get a list of all bel pins attached to a given wire.
### ArcBounds getRouteBoundingBox(WireId src, WireId dst) const
Get the bounding box required to route an arc, assuming an uncongested
chip. There may be significant performance impacts if routing regularly
exceeds these bounds by more than a small margin; so an over-estimate
of the bounds is almost always better than an under-estimate.
Pip Methods
-----------
@ -500,4 +507,14 @@ Name of the default placement algorithm for the architecture, if
### static const std::vector\<std::string\> availablePlacers
Name of available placer algorithms for the architecture, used
to provide help for and validate `--placer`.
to provide help for and validate `--placer`.
### static const std::string defaultRouter
Name of the default router algorithm for the architecture, if
`--router` isn't specified on the command line.
### static const std::vector\<std::string\> availableRouters
Name of available router algorithms for the architecture, used
to provide help for and validate `--router`.

View File

@ -30,6 +30,7 @@
#include "placer1.h"
#include "placer_heap.h"
#include "router1.h"
#include "router2.h"
#include "timing.h"
#include "util.h"
@ -492,6 +493,57 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const
(6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5)));
}
ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
{
ArcBounds bb;
bb.x0 = src.location.x;
bb.y0 = src.location.y;
bb.x1 = src.location.x;
bb.y1 = src.location.y;
auto extend = [&](int x, int y) {
bb.x0 = std::min(bb.x0, x);
bb.x1 = std::max(bb.x1, x);
bb.y0 = std::min(bb.y0, y);
bb.y1 = std::max(bb.y1, y);
};
auto est_location = [&](WireId w) -> std::pair<int, int> {
const auto &wire = locInfo(w)->wire_data[w.index];
if (w == gsrclk_wire) {
auto phys_wire = getPipSrcWire(*(getPipsUphill(w).begin()));
return std::make_pair(int(phys_wire.location.x), int(phys_wire.location.y));
} else if (wire.num_bel_pins > 0) {
return std::make_pair(w.location.x + wire.bel_pins[0].rel_bel_loc.x,
w.location.y + wire.bel_pins[0].rel_bel_loc.y);
} else if (wire.num_downhill > 0) {
return std::make_pair(w.location.x + wire.pips_downhill[0].rel_loc.x,
w.location.y + wire.pips_downhill[0].rel_loc.y);
} else if (wire.num_uphill > 0) {
return std::make_pair(w.location.x + wire.pips_uphill[0].rel_loc.x,
w.location.y + wire.pips_uphill[0].rel_loc.y);
} else {
return std::make_pair(int(w.location.x), int(w.location.y));
}
};
auto src_loc = est_location(src);
extend(src_loc.first, src_loc.second);
if (wire_loc_overrides.count(src)) {
extend(wire_loc_overrides.at(src).first, wire_loc_overrides.at(src).second);
}
std::pair<int, int> dst_loc;
extend(dst.location.x, dst.location.y);
if (wire_loc_overrides.count(dst)) {
dst_loc = wire_loc_overrides.at(dst);
} else {
dst_loc = est_location(dst);
}
extend(dst_loc.first, dst_loc.second);
return bb;
}
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
{
const auto &driver = net_info->driver;
@ -569,12 +621,23 @@ bool Arch::place()
bool Arch::route()
{
std::string router = str_or_default(settings, id("router"), defaultRouter);
setupWireLocations();
route_ecp5_globals(getCtx());
assignArchInfo();
assign_budget(getCtx(), true);
bool result = router1(getCtx(), Router1Cfg(getCtx()));
bool result;
if (router == "router1") {
result = router1(getCtx(), Router1Cfg(getCtx()));
} else if (router == "router2") {
router2(getCtx(), Router2Cfg(getCtx()));
result = true;
} else {
log_error("ECP5 architecture does not support router '%s'\n", router.c_str());
}
#if 0
std::vector<std::pair<WireId, int>> fanout_vector;
std::copy(wire_fanout.begin(), wire_fanout.end(), std::back_inserter(fanout_vector));
@ -1121,6 +1184,9 @@ const std::vector<std::string> Arch::availablePlacers = {"sa",
#endif
};
const std::string Arch::defaultRouter = "router1";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
// -----------------------------------------------------------------------
GroupId Arch::getGroupByName(IdString name) const

View File

@ -948,6 +948,7 @@ struct Arch : BaseCtx
// -------------------------------------------------
delay_t estimateDelay(WireId src, WireId dst) const;
ArcBounds getRouteBoundingBox(WireId src, WireId dst) const;
delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const;
delay_t getDelayEpsilon() const { return 20; }
delay_t getRipupDelayPenalty() const;
@ -1065,6 +1066,8 @@ struct Arch : BaseCtx
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
static const std::string defaultRouter;
static const std::vector<std::string> availableRouters;
};
NEXTPNR_NAMESPACE_END

View File

@ -203,17 +203,26 @@ void Arch::setupWireLocations()
CellInfo *ci = cell.second;
if (ci->bel == BelId())
continue;
if (ci->type == id_MULT18X18D || ci->type == id_DCUA) {
if (ci->type == id_MULT18X18D || ci->type == id_DCUA || ci->type == id_DDRDLL || ci->type == id_DQSBUFM ||
ci->type == id_EHXPLLL) {
for (auto &port : ci->ports) {
if (port.second.type != PORT_IN || port.second.net == nullptr)
if (port.second.net == nullptr)
continue;
WireId pw = getBelPinWire(ci->bel, port.first);
if (pw == WireId())
continue;
for (auto uh : getPipsUphill(pw)) {
WireId pip_src = getPipSrcWire(uh);
wire_loc_overrides[pw] = std::make_pair(pip_src.location.x, pip_src.location.y);
break;
if (port.second.type == PORT_OUT) {
for (auto dh : getPipsDownhill(pw)) {
WireId pip_dst = getPipDstWire(dh);
wire_loc_overrides[pw] = std::make_pair(pip_dst.location.x, pip_dst.location.y);
break;
}
} else {
for (auto uh : getPipsUphill(pw)) {
WireId pip_src = getPipSrcWire(uh);
wire_loc_overrides[pw] = std::make_pair(pip_src.location.x, pip_src.location.y);
break;
}
}
}
}

View File

@ -23,6 +23,7 @@
#include "placer1.h"
#include "placer_heap.h"
#include "router1.h"
#include "router2.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
@ -514,6 +515,30 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
{
ArcBounds bb;
int src_x = wires.at(src).x;
int src_y = wires.at(src).y;
int dst_x = wires.at(dst).x;
int dst_y = wires.at(dst).y;
bb.x0 = src_x;
bb.y0 = src_y;
bb.x1 = src_x;
bb.y1 = src_y;
auto extend = [&](int x, int y) {
bb.x0 = std::min(bb.x0, x);
bb.x1 = std::max(bb.x1, x);
bb.y0 = std::min(bb.y0, y);
bb.y1 = std::max(bb.y1, y);
};
extend(dst_x, dst_y);
return bb;
}
// ---------------------------------------------------------------
bool Arch::place()
@ -553,10 +578,19 @@ bool Arch::place()
bool Arch::route()
{
bool retVal = router1(getCtx(), Router1Cfg(getCtx()));
std::string router = str_or_default(settings, id("router"), defaultRouter);
bool result;
if (router == "router1") {
result = router1(getCtx(), Router1Cfg(getCtx()));
} else if (router == "router2") {
router2(getCtx(), Router2Cfg(getCtx()));
result = true;
} else {
log_error("iCE40 architecture does not support router '%s'\n", router.c_str());
}
getCtx()->settings[getCtx()->id("route")] = 1;
archInfoToAttributes();
return retVal;
return result;
}
// ---------------------------------------------------------------
@ -653,6 +687,10 @@ const std::vector<std::string> Arch::availablePlacers = {"sa",
"heap"
#endif
};
const std::string Arch::defaultRouter = "router1";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
void Arch::assignArchInfo()
{
for (auto &cell : getCtx()->cells) {

View File

@ -267,6 +267,8 @@ struct Arch : BaseCtx
uint32_t getDelayChecksum(delay_t v) const { return 0; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const;
ArcBounds getRouteBoundingBox(WireId src, WireId dst) const;
bool pack();
bool place();
bool route();
@ -288,6 +290,8 @@ struct Arch : BaseCtx
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
static const std::string defaultRouter;
static const std::vector<std::string> availableRouters;
// ---------------------------------------------------------------
// Internal usage

View File

@ -28,6 +28,7 @@
#include "placer1.h"
#include "placer_heap.h"
#include "router1.h"
#include "router2.h"
#include "timing_opt.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
@ -696,10 +697,19 @@ bool Arch::place()
bool Arch::route()
{
bool retVal = router1(getCtx(), Router1Cfg(getCtx()));
std::string router = str_or_default(settings, id("router"), defaultRouter);
bool result;
if (router == "router1") {
result = router1(getCtx(), Router1Cfg(getCtx()));
} else if (router == "router2") {
router2(getCtx(), Router2Cfg(getCtx()));
result = true;
} else {
log_error("iCE40 architecture does not support router '%s'\n", router.c_str());
}
getCtx()->settings[getCtx()->id("route")] = 1;
archInfoToAttributes();
return retVal;
return result;
}
// -----------------------------------------------------------------------
@ -1245,6 +1255,30 @@ void Arch::assignCellInfo(CellInfo *cell)
}
}
ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
{
ArcBounds bb;
int src_x = chip_info->wire_data[src.index].x;
int src_y = chip_info->wire_data[src.index].y;
int dst_x = chip_info->wire_data[dst.index].x;
int dst_y = chip_info->wire_data[dst.index].y;
bb.x0 = src_x;
bb.y0 = src_y;
bb.x1 = src_x;
bb.y1 = src_y;
auto extend = [&](int x, int y) {
bb.x0 = std::min(bb.x0, x);
bb.x1 = std::max(bb.x1, x);
bb.y0 = std::min(bb.y0, y);
bb.y1 = std::max(bb.y1, y);
};
extend(dst_x, dst_y);
return bb;
}
#ifdef WITH_HEAP
const std::string Arch::defaultPlacer = "heap";
#else
@ -1257,4 +1291,7 @@ const std::vector<std::string> Arch::availablePlacers = {"sa",
#endif
};
const std::string Arch::defaultRouter = "router1";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
NEXTPNR_NAMESPACE_END

View File

@ -826,6 +826,8 @@ struct Arch : BaseCtx
uint32_t getDelayChecksum(delay_t v) const { return v; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const;
ArcBounds getRouteBoundingBox(WireId src, WireId dst) const;
// -------------------------------------------------
bool pack();
@ -900,6 +902,8 @@ struct Arch : BaseCtx
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
static const std::string defaultRouter;
static const std::vector<std::string> availableRouters;
};
void ice40DelayFuzzerMain(Context *ctx);