Merge pull request #391 from YosysHQ/router2-upstream
Upstreaming router2
This commit is contained in:
commit
1ceffbe0bc
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
1132
common/router2.cc
Normal file
File diff suppressed because it is too large
Load Diff
56
common/router2.h
Normal file
56
common/router2.h
Normal 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
|
@ -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
|
||||
-----------
|
||||
|
||||
@ -501,3 +508,13 @@ Name of the default placement algorithm for the architecture, if
|
||||
|
||||
Name of available placer algorithms for the architecture, used
|
||||
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`.
|
68
ecp5/arch.cc
68
ecp5/arch.cc
@ -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
|
||||
|
@ -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
|
||||
|
@ -203,13 +203,21 @@ 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;
|
||||
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);
|
||||
@ -219,5 +227,6 @@ void Arch::setupWireLocations()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user