Merge pull request #575 from YosysHQ/gatecat/belpin-2
Support for cell pin to bel pin mappings
This commit is contained in:
commit
1b6cdce925
@ -354,19 +354,59 @@ WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const
|
|||||||
if (src_bel == BelId())
|
if (src_bel == BelId())
|
||||||
return WireId();
|
return WireId();
|
||||||
|
|
||||||
IdString driver_port = net_info->driver.port;
|
auto bel_pins = getBelPinsForCellPin(net_info->driver.cell, net_info->driver.port);
|
||||||
return getBelPinWire(src_bel, driver_port);
|
auto iter = bel_pins.begin();
|
||||||
|
if (iter == bel_pins.end())
|
||||||
|
return WireId();
|
||||||
|
WireId driver = getBelPinWire(src_bel, *iter);
|
||||||
|
++iter;
|
||||||
|
NPNR_ASSERT(iter == bel_pins.end()); // assert there is only one driver bel pin;
|
||||||
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &user_info) const
|
SSOArray<WireId, 2> Context::getNetinfoSinkWires(const NetInfo *net_info, const PortRef &user_info) const
|
||||||
{
|
{
|
||||||
auto dst_bel = user_info.cell->bel;
|
auto dst_bel = user_info.cell->bel;
|
||||||
|
|
||||||
if (dst_bel == BelId())
|
if (dst_bel == BelId())
|
||||||
return WireId();
|
return SSOArray<WireId, 2>(0, WireId());
|
||||||
|
size_t bel_pin_count = 0;
|
||||||
|
// We use an SSOArray here because it avoids any heap allocation for the 99.9% case of 1 or 2 sink wires
|
||||||
|
// but as SSOArray doesn't (currently) support resizing to keep things simple it does mean we have to do
|
||||||
|
// two loops
|
||||||
|
for (auto s : getBelPinsForCellPin(user_info.cell, user_info.port)) {
|
||||||
|
(void)s; // unused
|
||||||
|
++bel_pin_count;
|
||||||
|
}
|
||||||
|
SSOArray<WireId, 2> result(bel_pin_count, WireId());
|
||||||
|
bel_pin_count = 0;
|
||||||
|
for (auto pin : getBelPinsForCellPin(user_info.cell, user_info.port)) {
|
||||||
|
result[bel_pin_count++] = getBelPinWire(dst_bel, pin);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
IdString user_port = user_info.port;
|
size_t Context::getNetinfoSinkWireCount(const NetInfo *net_info, const PortRef &sink) const
|
||||||
return getBelPinWire(dst_bel, user_port);
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto s : getNetinfoSinkWires(net_info, sink)) {
|
||||||
|
(void)s; // unused
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink, size_t phys_idx) const
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto s : getNetinfoSinkWires(net_info, sink)) {
|
||||||
|
if (count == phys_idx)
|
||||||
|
return s;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
/* TODO: This should be an assertion failure, but for the zero-wire case of unplaced sinks; legacy code currently
|
||||||
|
assumes WireId Remove once the refactoring process is complete.
|
||||||
|
*/
|
||||||
|
return WireId();
|
||||||
}
|
}
|
||||||
|
|
||||||
delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const
|
delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const
|
||||||
@ -383,29 +423,33 @@ delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &us
|
|||||||
if (src_wire == WireId())
|
if (src_wire == WireId())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
WireId dst_wire = getNetinfoSinkWire(net_info, user_info);
|
delay_t max_delay = 0;
|
||||||
WireId cursor = dst_wire;
|
|
||||||
delay_t delay = 0;
|
|
||||||
|
|
||||||
while (cursor != WireId() && cursor != src_wire) {
|
for (auto dst_wire : getNetinfoSinkWires(net_info, user_info)) {
|
||||||
auto it = net_info->wires.find(cursor);
|
WireId cursor = dst_wire;
|
||||||
|
delay_t delay = 0;
|
||||||
|
|
||||||
if (it == net_info->wires.end())
|
while (cursor != WireId() && cursor != src_wire) {
|
||||||
break;
|
auto it = net_info->wires.find(cursor);
|
||||||
|
|
||||||
PipId pip = it->second.pip;
|
if (it == net_info->wires.end())
|
||||||
if (pip == PipId())
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
delay += getPipDelay(pip).maxDelay();
|
PipId pip = it->second.pip;
|
||||||
delay += getWireDelay(cursor).maxDelay();
|
if (pip == PipId())
|
||||||
cursor = getPipSrcWire(pip);
|
break;
|
||||||
|
|
||||||
|
delay += getPipDelay(pip).maxDelay();
|
||||||
|
delay += getWireDelay(cursor).maxDelay();
|
||||||
|
cursor = getPipSrcWire(pip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor == src_wire)
|
||||||
|
max_delay = std::max(max_delay, delay + getWireDelay(src_wire).maxDelay()); // routed
|
||||||
|
else
|
||||||
|
max_delay = std::max(max_delay, predictDelay(net_info, user_info)); // unrouted
|
||||||
}
|
}
|
||||||
|
return max_delay;
|
||||||
if (cursor == src_wire)
|
|
||||||
return delay + getWireDelay(src_wire).maxDelay();
|
|
||||||
|
|
||||||
return predictDelay(net_info, user_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t xorshift32(uint32_t x)
|
static uint32_t xorshift32(uint32_t x)
|
||||||
|
@ -1100,6 +1100,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
|||||||
virtual WireId getBelPinWire(BelId bel, IdString pin) const = 0;
|
virtual WireId getBelPinWire(BelId bel, IdString pin) const = 0;
|
||||||
virtual PortType getBelPinType(BelId bel, IdString pin) const = 0;
|
virtual PortType getBelPinType(BelId bel, IdString pin) const = 0;
|
||||||
virtual typename R::BelPinsRangeT getBelPins(BelId bel) const = 0;
|
virtual typename R::BelPinsRangeT getBelPins(BelId bel) const = 0;
|
||||||
|
virtual typename R::CellBelPinRangeT getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const = 0;
|
||||||
// Wire methods
|
// Wire methods
|
||||||
virtual typename R::AllWiresRangeT getWires() const = 0;
|
virtual typename R::AllWiresRangeT getWires() const = 0;
|
||||||
virtual WireId getWireByName(IdStringList name) const = 0;
|
virtual WireId getWireByName(IdStringList name) const = 0;
|
||||||
@ -1183,6 +1184,8 @@ template <typename R> struct ArchAPI : BaseCtx
|
|||||||
// This contains the relevant range types for the default implementations of Arch functions
|
// This contains the relevant range types for the default implementations of Arch functions
|
||||||
struct BaseArchRanges
|
struct BaseArchRanges
|
||||||
{
|
{
|
||||||
|
// Bels
|
||||||
|
using CellBelPinRangeT = std::array<IdString, 1>;
|
||||||
// Attributes
|
// Attributes
|
||||||
using BelAttrsRangeT = std::vector<std::pair<IdString, std::string>>;
|
using BelAttrsRangeT = std::vector<std::pair<IdString, std::string>>;
|
||||||
using WireAttrsRangeT = std::vector<std::pair<IdString, std::string>>;
|
using WireAttrsRangeT = std::vector<std::pair<IdString, std::string>>;
|
||||||
@ -1250,6 +1253,11 @@ template <typename R> struct BaseArch : ArchAPI<R>
|
|||||||
return empty_if_possible<typename R::BelAttrsRangeT>();
|
return empty_if_possible<typename R::BelAttrsRangeT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual typename R::CellBelPinRangeT getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override
|
||||||
|
{
|
||||||
|
return return_if_match<std::array<IdString, 1>, typename R::CellBelPinRangeT>({pin});
|
||||||
|
}
|
||||||
|
|
||||||
// Wire methods
|
// Wire methods
|
||||||
virtual IdString getWireType(WireId wire) const override { return IdString(); }
|
virtual IdString getWireType(WireId wire) const override { return IdString(); }
|
||||||
virtual typename R::WireAttrsRangeT getWireAttrs(WireId) const override
|
virtual typename R::WireAttrsRangeT getWireAttrs(WireId) const override
|
||||||
@ -1495,7 +1503,9 @@ struct Context : Arch, DeterministicRNG
|
|||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
WireId getNetinfoSourceWire(const NetInfo *net_info) const;
|
WireId getNetinfoSourceWire(const NetInfo *net_info) const;
|
||||||
WireId getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink) const;
|
SSOArray<WireId, 2> getNetinfoSinkWires(const NetInfo *net_info, const PortRef &sink) const;
|
||||||
|
size_t getNetinfoSinkWireCount(const NetInfo *net_info, const PortRef &sink) const;
|
||||||
|
WireId getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink, size_t phys_idx) const;
|
||||||
delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const;
|
delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const;
|
||||||
|
|
||||||
// provided by router1.cc
|
// provided by router1.cc
|
||||||
|
@ -32,12 +32,20 @@ USING_NEXTPNR_NAMESPACE
|
|||||||
struct arc_key
|
struct arc_key
|
||||||
{
|
{
|
||||||
NetInfo *net_info;
|
NetInfo *net_info;
|
||||||
|
// logical user cell port index
|
||||||
int user_idx;
|
int user_idx;
|
||||||
|
// physical index into cell->bel pin mapping (usually 0)
|
||||||
|
unsigned phys_idx;
|
||||||
|
|
||||||
bool operator==(const arc_key &other) const { return (net_info == other.net_info) && (user_idx == other.user_idx); }
|
bool operator==(const arc_key &other) const
|
||||||
|
{
|
||||||
|
return (net_info == other.net_info) && (user_idx == other.user_idx) && (phys_idx == other.phys_idx);
|
||||||
|
}
|
||||||
bool operator<(const arc_key &other) const
|
bool operator<(const arc_key &other) const
|
||||||
{
|
{
|
||||||
return net_info == other.net_info ? user_idx < other.user_idx : net_info->name < other.net_info->name;
|
return net_info == other.net_info
|
||||||
|
? (user_idx == other.user_idx ? phys_idx < other.phys_idx : user_idx < other.user_idx)
|
||||||
|
: net_info->name < other.net_info->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Hash
|
struct Hash
|
||||||
@ -46,6 +54,7 @@ struct arc_key
|
|||||||
{
|
{
|
||||||
std::size_t seed = std::hash<NetInfo *>()(arg.net_info);
|
std::size_t seed = std::hash<NetInfo *>()(arg.net_info);
|
||||||
seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
seed ^= std::hash<int>()(arg.phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -142,9 +151,10 @@ struct Router1
|
|||||||
|
|
||||||
NetInfo *net_info = arc.net_info;
|
NetInfo *net_info = arc.net_info;
|
||||||
int user_idx = arc.user_idx;
|
int user_idx = arc.user_idx;
|
||||||
|
unsigned phys_idx = arc.phys_idx;
|
||||||
|
|
||||||
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
||||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], phys_idx);
|
||||||
|
|
||||||
arc_queue_insert(arc, src_wire, dst_wire);
|
arc_queue_insert(arc, src_wire, dst_wire);
|
||||||
}
|
}
|
||||||
@ -302,27 +312,29 @@ struct Router1
|
|||||||
log_assert(src_wire != WireId());
|
log_assert(src_wire != WireId());
|
||||||
|
|
||||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
unsigned phys_idx = 0;
|
||||||
log_assert(dst_wire != WireId());
|
for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
|
||||||
|
log_assert(dst_wire != WireId());
|
||||||
|
|
||||||
arc_key arc;
|
arc_key arc;
|
||||||
arc.net_info = net_info;
|
arc.net_info = net_info;
|
||||||
arc.user_idx = user_idx;
|
arc.user_idx = user_idx;
|
||||||
|
arc.phys_idx = phys_idx++;
|
||||||
valid_arcs.insert(arc);
|
valid_arcs.insert(arc);
|
||||||
#if 0
|
#if 0
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log("[check] arc: %s %s\n", ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire));
|
log("[check] arc: %s %s\n", ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (WireId wire : arc_to_wires[arc]) {
|
for (WireId wire : arc_to_wires[arc]) {
|
||||||
#if 0
|
#if 0
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log("[check] wire: %s\n", ctx->nameOfWire(wire));
|
log("[check] wire: %s\n", ctx->nameOfWire(wire));
|
||||||
#endif
|
#endif
|
||||||
valid_wires_for_net.insert(wire);
|
valid_wires_for_net.insert(wire);
|
||||||
log_assert(wire_to_arcs[wire].count(arc));
|
log_assert(wire_to_arcs[wire].count(arc));
|
||||||
log_assert(net_info->wires.count(wire));
|
log_assert(net_info->wires.count(wire));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,52 +387,55 @@ struct Router1
|
|||||||
ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx);
|
ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx);
|
||||||
|
|
||||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
unsigned phys_idx = 0;
|
||||||
|
for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
|
||||||
|
arc_key arc;
|
||||||
|
arc.net_info = net_info;
|
||||||
|
arc.user_idx = user_idx;
|
||||||
|
arc.phys_idx = phys_idx++;
|
||||||
|
|
||||||
if (dst_wire == WireId())
|
if (dst_to_arc.count(dst_wire)) {
|
||||||
log_error("No wire found for port %s on destination cell %s.\n",
|
if (dst_to_arc.at(dst_wire).net_info == net_info)
|
||||||
ctx->nameOf(net_info->users[user_idx].port), ctx->nameOf(net_info->users[user_idx].cell));
|
continue;
|
||||||
|
log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n",
|
||||||
if (dst_to_arc.count(dst_wire)) {
|
ctx->nameOfWire(dst_wire), ctx->nameOf(net_info), user_idx,
|
||||||
if (dst_to_arc.at(dst_wire).net_info == net_info)
|
ctx->nameOf(dst_to_arc.at(dst_wire).net_info), dst_to_arc.at(dst_wire).user_idx);
|
||||||
continue;
|
|
||||||
log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n", ctx->nameOfWire(dst_wire),
|
|
||||||
ctx->nameOf(net_info), user_idx, ctx->nameOf(dst_to_arc.at(dst_wire).net_info),
|
|
||||||
dst_to_arc.at(dst_wire).user_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src_to_net.count(dst_wire))
|
|
||||||
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n",
|
|
||||||
ctx->nameOfWire(dst_wire), ctx->nameOf(src_to_net.at(dst_wire)), ctx->nameOf(net_info),
|
|
||||||
user_idx);
|
|
||||||
|
|
||||||
arc_key arc;
|
|
||||||
arc.net_info = net_info;
|
|
||||||
arc.user_idx = user_idx;
|
|
||||||
|
|
||||||
dst_to_arc[dst_wire] = arc;
|
|
||||||
|
|
||||||
if (net_info->wires.count(dst_wire) == 0) {
|
|
||||||
arc_queue_insert(arc, src_wire, dst_wire);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
WireId cursor = dst_wire;
|
|
||||||
wire_to_arcs[cursor].insert(arc);
|
|
||||||
arc_to_wires[arc].insert(cursor);
|
|
||||||
|
|
||||||
while (src_wire != cursor) {
|
|
||||||
auto it = net_info->wires.find(cursor);
|
|
||||||
if (it == net_info->wires.end()) {
|
|
||||||
arc_queue_insert(arc, src_wire, dst_wire);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NPNR_ASSERT(it->second.pip != PipId());
|
if (src_to_net.count(dst_wire))
|
||||||
cursor = ctx->getPipSrcWire(it->second.pip);
|
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n",
|
||||||
|
ctx->nameOfWire(dst_wire), ctx->nameOf(src_to_net.at(dst_wire)),
|
||||||
|
ctx->nameOf(net_info), user_idx);
|
||||||
|
|
||||||
|
dst_to_arc[dst_wire] = arc;
|
||||||
|
|
||||||
|
if (net_info->wires.count(dst_wire) == 0) {
|
||||||
|
arc_queue_insert(arc, src_wire, dst_wire);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WireId cursor = dst_wire;
|
||||||
wire_to_arcs[cursor].insert(arc);
|
wire_to_arcs[cursor].insert(arc);
|
||||||
arc_to_wires[arc].insert(cursor);
|
arc_to_wires[arc].insert(cursor);
|
||||||
|
|
||||||
|
while (src_wire != cursor) {
|
||||||
|
auto it = net_info->wires.find(cursor);
|
||||||
|
if (it == net_info->wires.end()) {
|
||||||
|
arc_queue_insert(arc, src_wire, dst_wire);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NPNR_ASSERT(it->second.pip != PipId());
|
||||||
|
cursor = ctx->getPipSrcWire(it->second.pip);
|
||||||
|
wire_to_arcs[cursor].insert(arc);
|
||||||
|
arc_to_wires[arc].insert(cursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: this matches the situation before supporting multiple cell->bel pins, but do we want to keep
|
||||||
|
// this invariant?
|
||||||
|
if (phys_idx == 0)
|
||||||
|
log_error("No wires found for port %s on destination cell %s.\n",
|
||||||
|
ctx->nameOf(net_info->users[user_idx].port), ctx->nameOf(net_info->users[user_idx].cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
src_to_net[src_wire] = net_info;
|
src_to_net[src_wire] = net_info;
|
||||||
@ -443,7 +458,7 @@ struct Router1
|
|||||||
int user_idx = arc.user_idx;
|
int user_idx = arc.user_idx;
|
||||||
|
|
||||||
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
||||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], arc.phys_idx);
|
||||||
ripup_flag = false;
|
ripup_flag = false;
|
||||||
|
|
||||||
if (ctx->debug) {
|
if (ctx->debug) {
|
||||||
@ -934,14 +949,15 @@ bool Context::checkRoutedDesign() const
|
|||||||
|
|
||||||
std::unordered_map<WireId, int> dest_wires;
|
std::unordered_map<WireId, int> dest_wires;
|
||||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
|
||||||
log_assert(dst_wire != WireId());
|
log_assert(dst_wire != WireId());
|
||||||
dest_wires[dst_wire] = user_idx;
|
dest_wires[dst_wire] = user_idx;
|
||||||
|
|
||||||
if (net_info->wires.count(dst_wire) == 0) {
|
if (net_info->wires.count(dst_wire) == 0) {
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log(" sink %d (%s) not bound to net\n", user_idx, ctx->nameOfWire(dst_wire));
|
log(" sink %d (%s) not bound to net\n", user_idx, ctx->nameOfWire(dst_wire));
|
||||||
found_unrouted = true;
|
found_unrouted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ struct Router2
|
|||||||
struct PerNetData
|
struct PerNetData
|
||||||
{
|
{
|
||||||
WireId src_wire;
|
WireId src_wire;
|
||||||
std::vector<PerArcData> arcs;
|
std::vector<std::vector<PerArcData>> arcs;
|
||||||
ArcBounds bb;
|
ArcBounds bb;
|
||||||
// Coordinates of the center of the net, used for the weight-to-average
|
// Coordinates of the center of the net, used for the weight-to-average
|
||||||
int cx, cy, hpwl;
|
int cx, cy, hpwl;
|
||||||
@ -150,26 +150,30 @@ struct Router2
|
|||||||
|
|
||||||
for (size_t j = 0; j < ni->users.size(); j++) {
|
for (size_t j = 0; j < ni->users.size(); j++) {
|
||||||
auto &usr = ni->users.at(j);
|
auto &usr = ni->users.at(j);
|
||||||
WireId src_wire = ctx->getNetinfoSourceWire(ni), dst_wire = ctx->getNetinfoSinkWire(ni, usr);
|
WireId src_wire = ctx->getNetinfoSourceWire(ni);
|
||||||
nets.at(i).src_wire = src_wire;
|
for (auto &dst_wire : ctx->getNetinfoSinkWires(ni, usr)) {
|
||||||
if (ni->driver.cell == nullptr)
|
nets.at(i).src_wire = src_wire;
|
||||||
src_wire = dst_wire;
|
if (ni->driver.cell == nullptr)
|
||||||
if (ni->driver.cell == nullptr && dst_wire == WireId())
|
src_wire = dst_wire;
|
||||||
continue;
|
if (ni->driver.cell == nullptr && dst_wire == WireId())
|
||||||
if (src_wire == WireId())
|
continue;
|
||||||
log_error("No wire found for port %s on source cell %s.\n", ctx->nameOf(ni->driver.port),
|
if (src_wire == WireId())
|
||||||
ctx->nameOf(ni->driver.cell));
|
log_error("No wire found for port %s on source cell %s.\n", ctx->nameOf(ni->driver.port),
|
||||||
if (dst_wire == WireId())
|
ctx->nameOf(ni->driver.cell));
|
||||||
log_error("No wire found for port %s on destination cell %s.\n", ctx->nameOf(usr.port),
|
if (dst_wire == WireId())
|
||||||
ctx->nameOf(usr.cell));
|
log_error("No wire found for port %s on destination cell %s.\n", ctx->nameOf(usr.port),
|
||||||
nets.at(i).arcs.at(j).sink_wire = dst_wire;
|
ctx->nameOf(usr.cell));
|
||||||
// Set bounding box for this arc
|
nets.at(i).arcs.at(j).emplace_back();
|
||||||
nets.at(i).arcs.at(j).bb = ctx->getRouteBoundingBox(src_wire, dst_wire);
|
auto &ad = nets.at(i).arcs.at(j).back();
|
||||||
// Expand net bounding box to include this arc
|
ad.sink_wire = dst_wire;
|
||||||
nets.at(i).bb.x0 = std::min(nets.at(i).bb.x0, nets.at(i).arcs.at(j).bb.x0);
|
// Set bounding box for this arc
|
||||||
nets.at(i).bb.x1 = std::max(nets.at(i).bb.x1, nets.at(i).arcs.at(j).bb.x1);
|
ad.bb = ctx->getRouteBoundingBox(src_wire, dst_wire);
|
||||||
nets.at(i).bb.y0 = std::min(nets.at(i).bb.y0, nets.at(i).arcs.at(j).bb.y0);
|
// Expand net bounding box to include this arc
|
||||||
nets.at(i).bb.y1 = std::max(nets.at(i).bb.y1, nets.at(i).arcs.at(j).bb.y1);
|
nets.at(i).bb.x0 = std::min(nets.at(i).bb.x0, ad.bb.x0);
|
||||||
|
nets.at(i).bb.x1 = std::max(nets.at(i).bb.x1, ad.bb.x1);
|
||||||
|
nets.at(i).bb.y0 = std::min(nets.at(i).bb.y0, ad.bb.y0);
|
||||||
|
nets.at(i).bb.y1 = std::max(nets.at(i).bb.x1, ad.bb.y1);
|
||||||
|
}
|
||||||
// Add location to centroid sum
|
// Add location to centroid sum
|
||||||
Loc usr_loc = ctx->getBelLocation(usr.cell->bel);
|
Loc usr_loc = ctx->getBelLocation(usr.cell->bel);
|
||||||
nets.at(i).cx += usr_loc.x;
|
nets.at(i).cx += usr_loc.x;
|
||||||
@ -254,7 +258,7 @@ struct Router2
|
|||||||
// Nets that failed routing
|
// Nets that failed routing
|
||||||
std::vector<NetInfo *> failed_nets;
|
std::vector<NetInfo *> failed_nets;
|
||||||
|
|
||||||
std::vector<int> route_arcs;
|
std::vector<std::pair<size_t, size_t>> route_arcs;
|
||||||
|
|
||||||
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
|
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
|
||||||
// Special case where one net has multiple logical arcs to the same physical sink
|
// Special case where one net has multiple logical arcs to the same physical sink
|
||||||
@ -317,9 +321,9 @@ struct Router2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ripup_arc(NetInfo *net, size_t user)
|
void ripup_arc(NetInfo *net, size_t user, size_t phys_pin)
|
||||||
{
|
{
|
||||||
auto &ad = nets.at(net->udata).arcs.at(user);
|
auto &ad = nets.at(net->udata).arcs.at(user).at(phys_pin);
|
||||||
if (!ad.routed)
|
if (!ad.routed)
|
||||||
return;
|
return;
|
||||||
WireId src = nets.at(net->udata).src_wire;
|
WireId src = nets.at(net->udata).src_wire;
|
||||||
@ -333,7 +337,7 @@ struct Router2
|
|||||||
ad.routed = false;
|
ad.routed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float score_wire_for_arc(NetInfo *net, size_t user, WireId wire, PipId pip)
|
float score_wire_for_arc(NetInfo *net, size_t user, size_t phys_pin, WireId wire, PipId pip)
|
||||||
{
|
{
|
||||||
auto &wd = wire_data(wire);
|
auto &wd = wire_data(wire);
|
||||||
auto &nd = nets.at(net->udata);
|
auto &nd = nets.at(net->udata);
|
||||||
@ -350,7 +354,7 @@ struct Router2
|
|||||||
for (auto &bound : wd.bound_nets)
|
for (auto &bound : wd.bound_nets)
|
||||||
if (bound.first != net->udata)
|
if (bound.first != net->udata)
|
||||||
max_bound_crit = std::max(max_bound_crit, nets.at(bound.first).max_crit);
|
max_bound_crit = std::max(max_bound_crit, nets.at(bound.first).max_crit);
|
||||||
if (max_bound_crit >= 0.8 && nd.arcs.at(user).arc_crit < (max_bound_crit + 0.01)) {
|
if (max_bound_crit >= 0.8 && nd.arcs.at(user).at(phys_pin).arc_crit < (max_bound_crit + 0.01)) {
|
||||||
present_cost *= 1.5;
|
present_cost *= 1.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,9 +376,9 @@ struct Router2
|
|||||||
return (ctx->getDelayNS(ctx->estimateDelay(wd.w, sink)) / (1 + source_uses)) + cfg.ipin_cost_adder;
|
return (ctx->getDelayNS(ctx->estimateDelay(wd.w, sink)) / (1 + source_uses)) + cfg.ipin_cost_adder;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_arc_routing(NetInfo *net, size_t usr)
|
bool check_arc_routing(NetInfo *net, size_t usr, size_t phys_pin)
|
||||||
{
|
{
|
||||||
auto &ad = nets.at(net->udata).arcs.at(usr);
|
auto &ad = nets.at(net->udata).arcs.at(usr).at(phys_pin);
|
||||||
WireId src_wire = nets.at(net->udata).src_wire;
|
WireId src_wire = nets.at(net->udata).src_wire;
|
||||||
WireId cursor = ad.sink_wire;
|
WireId cursor = ad.sink_wire;
|
||||||
while (wire_data(cursor).bound_nets.count(net->udata)) {
|
while (wire_data(cursor).bound_nets.count(net->udata)) {
|
||||||
@ -405,35 +409,34 @@ struct Router2
|
|||||||
void reserve_wires_for_arc(NetInfo *net, size_t i)
|
void reserve_wires_for_arc(NetInfo *net, size_t i)
|
||||||
{
|
{
|
||||||
WireId src = ctx->getNetinfoSourceWire(net);
|
WireId src = ctx->getNetinfoSourceWire(net);
|
||||||
WireId sink = ctx->getNetinfoSinkWire(net, net->users.at(i));
|
for (auto sink : ctx->getNetinfoSinkWires(net, net->users.at(i))) {
|
||||||
if (sink == WireId())
|
std::unordered_set<WireId> rsv;
|
||||||
return;
|
WireId cursor = sink;
|
||||||
std::unordered_set<WireId> rsv;
|
bool done = false;
|
||||||
WireId cursor = sink;
|
|
||||||
bool done = false;
|
|
||||||
if (ctx->debug)
|
|
||||||
log("reserving wires for arc %d of net %s\n", int(i), ctx->nameOf(net));
|
|
||||||
while (!done) {
|
|
||||||
auto &wd = wire_data(cursor);
|
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log(" %s\n", ctx->nameOfWire(cursor));
|
log("reserving wires for arc %d of net %s\n", int(i), ctx->nameOf(net));
|
||||||
wd.reserved_net = net->udata;
|
while (!done) {
|
||||||
if (cursor == src)
|
auto &wd = wire_data(cursor);
|
||||||
break;
|
if (ctx->debug)
|
||||||
WireId next_cursor;
|
log(" %s\n", ctx->nameOfWire(cursor));
|
||||||
for (auto uh : ctx->getPipsUphill(cursor)) {
|
wd.reserved_net = net->udata;
|
||||||
WireId w = ctx->getPipSrcWire(uh);
|
if (cursor == src)
|
||||||
if (is_wire_undriveable(w))
|
|
||||||
continue;
|
|
||||||
if (next_cursor != WireId()) {
|
|
||||||
done = true;
|
|
||||||
break;
|
break;
|
||||||
|
WireId next_cursor;
|
||||||
|
for (auto uh : ctx->getPipsUphill(cursor)) {
|
||||||
|
WireId w = ctx->getPipSrcWire(uh);
|
||||||
|
if (is_wire_undriveable(w))
|
||||||
|
continue;
|
||||||
|
if (next_cursor != WireId()) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_cursor = w;
|
||||||
}
|
}
|
||||||
next_cursor = w;
|
if (next_cursor == WireId())
|
||||||
|
break;
|
||||||
|
cursor = next_cursor;
|
||||||
}
|
}
|
||||||
if (next_cursor == WireId())
|
|
||||||
break;
|
|
||||||
cursor = next_cursor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,15 +474,15 @@ struct Router2
|
|||||||
}
|
}
|
||||||
bool was_visited(int wire) { return flat_wires.at(wire).visit.visited; }
|
bool was_visited(int wire) { return flat_wires.at(wire).visit.visited; }
|
||||||
|
|
||||||
ArcRouteResult route_arc(ThreadContext &t, NetInfo *net, size_t i, bool is_mt, bool is_bb = true)
|
ArcRouteResult route_arc(ThreadContext &t, NetInfo *net, size_t i, size_t phys_pin, bool is_mt, bool is_bb = true)
|
||||||
{
|
{
|
||||||
|
|
||||||
auto &nd = nets[net->udata];
|
auto &nd = nets[net->udata];
|
||||||
auto &ad = nd.arcs[i];
|
auto &ad = nd.arcs.at(i).at(phys_pin);
|
||||||
auto &usr = net->users.at(i);
|
auto &usr = net->users.at(i);
|
||||||
ROUTE_LOG_DBG("Routing arc %d of net '%s' (%d, %d) -> (%d, %d)\n", int(i), ctx->nameOf(net), ad.bb.x0, ad.bb.y0,
|
ROUTE_LOG_DBG("Routing arc %d of net '%s' (%d, %d) -> (%d, %d)\n", int(i), ctx->nameOf(net), ad.bb.x0, ad.bb.y0,
|
||||||
ad.bb.x1, ad.bb.y1);
|
ad.bb.x1, ad.bb.y1);
|
||||||
WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr);
|
WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr, phys_pin);
|
||||||
if (src_wire == WireId())
|
if (src_wire == WireId())
|
||||||
ARC_LOG_ERR("No wire found for port %s on source cell %s.\n", ctx->nameOf(net->driver.port),
|
ARC_LOG_ERR("No wire found for port %s on source cell %s.\n", ctx->nameOf(net->driver.port),
|
||||||
ctx->nameOf(net->driver.cell));
|
ctx->nameOf(net->driver.cell));
|
||||||
@ -650,7 +653,7 @@ struct Router2
|
|||||||
if (!thread_test_wire(t, nwd))
|
if (!thread_test_wire(t, nwd))
|
||||||
continue; // thread safety issue
|
continue; // thread safety issue
|
||||||
WireScore next_score;
|
WireScore next_score;
|
||||||
next_score.cost = curr.score.cost + score_wire_for_arc(net, i, next, dh);
|
next_score.cost = curr.score.cost + score_wire_for_arc(net, i, phys_pin, next, dh);
|
||||||
next_score.delay =
|
next_score.delay =
|
||||||
curr.score.delay + ctx->getPipDelay(dh).maxDelay() + ctx->getWireDelay(next).maxDelay();
|
curr.score.delay + ctx->getPipDelay(dh).maxDelay() + ctx->getWireDelay(next).maxDelay();
|
||||||
next_score.togo_cost = cfg.estimate_weight * get_togo_cost(net, i, next_idx, dst_wire);
|
next_score.togo_cost = cfg.estimate_weight * get_togo_cost(net, i, next_idx, dst_wire);
|
||||||
@ -720,22 +723,26 @@ struct Router2
|
|||||||
bool have_failures = false;
|
bool have_failures = false;
|
||||||
t.processed_sinks.clear();
|
t.processed_sinks.clear();
|
||||||
t.route_arcs.clear();
|
t.route_arcs.clear();
|
||||||
|
auto &nd = nets.at(net->udata);
|
||||||
for (size_t i = 0; i < net->users.size(); i++) {
|
for (size_t i = 0; i < net->users.size(); i++) {
|
||||||
// Ripup failed arcs to start with
|
auto &ad = nd.arcs.at(i);
|
||||||
// Check if arc is already legally routed
|
for (size_t j = 0; j < ad.size(); j++) {
|
||||||
if (check_arc_routing(net, i))
|
// Ripup failed arcs to start with
|
||||||
continue;
|
// Check if arc is already legally routed
|
||||||
auto &usr = net->users.at(i);
|
if (check_arc_routing(net, i, j))
|
||||||
WireId dst_wire = ctx->getNetinfoSinkWire(net, usr);
|
continue;
|
||||||
// Case of arcs that were pre-routed strongly (e.g. clocks)
|
auto &usr = net->users.at(i);
|
||||||
if (net->wires.count(dst_wire) && net->wires.at(dst_wire).strength > STRENGTH_STRONG)
|
WireId dst_wire = ctx->getNetinfoSinkWire(net, usr, j);
|
||||||
return ARC_SUCCESS;
|
// Case of arcs that were pre-routed strongly (e.g. clocks)
|
||||||
// Ripup arc to start with
|
if (net->wires.count(dst_wire) && net->wires.at(dst_wire).strength > STRENGTH_STRONG)
|
||||||
ripup_arc(net, i);
|
return ARC_SUCCESS;
|
||||||
t.route_arcs.push_back(i);
|
// Ripup arc to start with
|
||||||
|
ripup_arc(net, i, j);
|
||||||
|
t.route_arcs.emplace_back(i, j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (auto i : t.route_arcs) {
|
for (auto a : t.route_arcs) {
|
||||||
auto res1 = route_arc(t, net, i, is_mt, true);
|
auto res1 = route_arc(t, net, a.first, a.second, is_mt, true);
|
||||||
if (res1 == ARC_FATAL)
|
if (res1 == ARC_FATAL)
|
||||||
return false; // Arc failed irrecoverably
|
return false; // Arc failed irrecoverably
|
||||||
else if (res1 == ARC_RETRY_WITHOUT_BB) {
|
else if (res1 == ARC_RETRY_WITHOUT_BB) {
|
||||||
@ -744,14 +751,14 @@ struct Router2
|
|||||||
have_failures = true;
|
have_failures = true;
|
||||||
} else {
|
} else {
|
||||||
// Attempt a re-route without the bounding box constraint
|
// Attempt a re-route without the bounding box constraint
|
||||||
ROUTE_LOG_DBG("Rerouting arc %d of net '%s' without bounding box, possible tricky routing...\n",
|
ROUTE_LOG_DBG("Rerouting arc %d.%d of net '%s' without bounding box, possible tricky routing...\n",
|
||||||
int(i), ctx->nameOf(net));
|
int(a.first), int(a.second), ctx->nameOf(net));
|
||||||
auto res2 = route_arc(t, net, i, is_mt, false);
|
auto res2 = route_arc(t, net, a.first, a.second, is_mt, false);
|
||||||
// If this also fails, no choice but to give up
|
// If this also fails, no choice but to give up
|
||||||
if (res2 != ARC_SUCCESS)
|
if (res2 != ARC_SUCCESS)
|
||||||
log_error("Failed to route arc %d of net '%s', from %s to %s.\n", int(i), ctx->nameOf(net),
|
log_error("Failed to route arc %d.%d of net '%s', from %s to %s.\n", int(a.first),
|
||||||
ctx->nameOfWire(ctx->getNetinfoSourceWire(net)),
|
int(a.second), ctx->nameOf(net), ctx->nameOfWire(ctx->getNetinfoSourceWire(net)),
|
||||||
ctx->nameOfWire(ctx->getNetinfoSinkWire(net, net->users.at(i))));
|
ctx->nameOfWire(ctx->getNetinfoSinkWire(net, net->users.at(a.first), a.second)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -789,7 +796,7 @@ struct Router2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bind_and_check(NetInfo *net, int usr_idx)
|
bool bind_and_check(NetInfo *net, int usr_idx, int phys_pin)
|
||||||
{
|
{
|
||||||
#ifdef ARCH_ECP5
|
#ifdef ARCH_ECP5
|
||||||
if (net->is_global)
|
if (net->is_global)
|
||||||
@ -797,13 +804,13 @@ struct Router2
|
|||||||
#endif
|
#endif
|
||||||
bool success = true;
|
bool success = true;
|
||||||
auto &nd = nets.at(net->udata);
|
auto &nd = nets.at(net->udata);
|
||||||
auto &ad = nd.arcs.at(usr_idx);
|
auto &ad = nd.arcs.at(usr_idx).at(phys_pin);
|
||||||
auto &usr = net->users.at(usr_idx);
|
auto &usr = net->users.at(usr_idx);
|
||||||
WireId src = ctx->getNetinfoSourceWire(net);
|
WireId src = ctx->getNetinfoSourceWire(net);
|
||||||
// Skip routes with no source
|
// Skip routes with no source
|
||||||
if (src == WireId())
|
if (src == WireId())
|
||||||
return true;
|
return true;
|
||||||
WireId dst = ctx->getNetinfoSinkWire(net, usr);
|
WireId dst = ctx->getNetinfoSinkWire(net, usr, phys_pin);
|
||||||
// Skip routes where the destination is already bound
|
// Skip routes where the destination is already bound
|
||||||
if (dst == WireId() || ctx->getBoundWireNet(dst) == net)
|
if (dst == WireId() || ctx->getBoundWireNet(dst) == net)
|
||||||
return true;
|
return true;
|
||||||
@ -849,7 +856,7 @@ struct Router2
|
|||||||
for (auto tb : to_bind)
|
for (auto tb : to_bind)
|
||||||
ctx->bindPip(tb, net, STRENGTH_WEAK);
|
ctx->bindPip(tb, net, STRENGTH_WEAK);
|
||||||
} else {
|
} else {
|
||||||
ripup_arc(net, usr_idx);
|
ripup_arc(net, usr_idx, phys_pin);
|
||||||
failed_nets.insert(net->udata);
|
failed_nets.insert(net->udata);
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
@ -875,9 +882,11 @@ struct Router2
|
|||||||
ctx->unbindWire(w);
|
ctx->unbindWire(w);
|
||||||
// Bind the arcs using the routes we have discovered
|
// Bind the arcs using the routes we have discovered
|
||||||
for (size_t i = 0; i < net->users.size(); i++) {
|
for (size_t i = 0; i < net->users.size(); i++) {
|
||||||
if (!bind_and_check(net, i)) {
|
for (size_t phys_pin = 0; phys_pin < nets.at(net->udata).arcs.at(i).size(); phys_pin++) {
|
||||||
++arch_fail;
|
if (!bind_and_check(net, i, phys_pin)) {
|
||||||
success = false;
|
++arch_fail;
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1123,7 +1132,8 @@ struct Router2
|
|||||||
continue;
|
continue;
|
||||||
for (int i = 0; i < int(fnd->second.criticality.size()); i++) {
|
for (int i = 0; i < int(fnd->second.criticality.size()); i++) {
|
||||||
float c = fnd->second.criticality.at(i);
|
float c = fnd->second.criticality.at(i);
|
||||||
net.arcs.at(i).arc_crit = c;
|
for (auto &a : net.arcs.at(i))
|
||||||
|
a.arc_crit = c;
|
||||||
net.max_crit = std::max(net.max_crit, c);
|
net.max_crit = std::max(net.max_crit, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -869,7 +869,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
|
|||||||
log_info(" Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx));
|
log_info(" Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx));
|
||||||
if (ctx->verbose) {
|
if (ctx->verbose) {
|
||||||
auto driver_wire = ctx->getNetinfoSourceWire(net);
|
auto driver_wire = ctx->getNetinfoSourceWire(net);
|
||||||
auto sink_wire = ctx->getNetinfoSinkWire(net, *sink);
|
auto sink_wire = ctx->getNetinfoSinkWire(net, *sink, 0);
|
||||||
log_info(" prediction: %f ns estimate: %f ns\n",
|
log_info(" prediction: %f ns estimate: %f ns\n",
|
||||||
ctx->getDelayNS(ctx->predictDelay(net, *sink)),
|
ctx->getDelayNS(ctx->predictDelay(net, *sink)),
|
||||||
ctx->getDelayNS(ctx->estimateDelay(driver_wire, sink_wire)));
|
ctx->getDelayNS(ctx->estimateDelay(driver_wire, sink_wire)));
|
||||||
|
@ -13,6 +13,7 @@ The contents of `ArchRanges` is as follows:
|
|||||||
|`TileBelsRangeT` | `BelId` |
|
|`TileBelsRangeT` | `BelId` |
|
||||||
|`BelAttrsRangeT` | std::pair<IdString, std::string> |
|
|`BelAttrsRangeT` | std::pair<IdString, std::string> |
|
||||||
|`BelPinsRangeT` | `IdString` |
|
|`BelPinsRangeT` | `IdString` |
|
||||||
|
|`CellBelPinRangeT` | `IdString` |
|
||||||
|`AllWiresRangeT` | `WireId` |
|
|`AllWiresRangeT` | `WireId` |
|
||||||
|`DownhillPipRangeT` | `PipId` |
|
|`DownhillPipRangeT` | `PipId` |
|
||||||
|`UphillPipRangeT` | `PipId` |
|
|`UphillPipRangeT` | `PipId` |
|
||||||
@ -250,6 +251,12 @@ Return the type (input/output/inout) of the given bel pin.
|
|||||||
|
|
||||||
Return a list of all pins on that bel.
|
Return a list of all pins on that bel.
|
||||||
|
|
||||||
|
### CellBelPinRangeT getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const
|
||||||
|
|
||||||
|
Return the list of bel pin names that a given cell pin should be routed to. In most cases there will be a single bel pin for each cell pin; and output pins must _always_ have only one bel pin associated with them.
|
||||||
|
|
||||||
|
*BaseArch default: returns a one-element array containing `pin`*
|
||||||
|
|
||||||
Wire Methods
|
Wire Methods
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -661,6 +661,7 @@ struct ArchRanges
|
|||||||
using TileBelsRangeT = BelRange;
|
using TileBelsRangeT = BelRange;
|
||||||
using BelAttrsRangeT = std::vector<std::pair<IdString, std::string>>;
|
using BelAttrsRangeT = std::vector<std::pair<IdString, std::string>>;
|
||||||
using BelPinsRangeT = IdStringRange;
|
using BelPinsRangeT = IdStringRange;
|
||||||
|
using CellBelPinRangeT = std::array<IdString, 1>;
|
||||||
// Wires
|
// Wires
|
||||||
using AllWiresRangeT = WireRange;
|
using AllWiresRangeT = WireRange;
|
||||||
using DownhillPipRangeT = DownhillPipRange;
|
using DownhillPipRangeT = DownhillPipRange;
|
||||||
@ -866,6 +867,8 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
return str_range;
|
return str_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<IdString, 1> getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override { return {pin}; }
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
WireId getWireByName(IdStringList name) const override;
|
WireId getWireByName(IdStringList name) const override;
|
||||||
|
@ -342,6 +342,8 @@ std::vector<IdString> Arch::getBelPins(BelId bel) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<IdString, 1> Arch::getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const { return {pin}; }
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
WireId Arch::getWireByName(IdStringList name) const
|
WireId Arch::getWireByName(IdStringList name) const
|
||||||
|
@ -125,6 +125,7 @@ struct ArchRanges
|
|||||||
using TileBelsRangeT = const std::vector<BelId> &;
|
using TileBelsRangeT = const std::vector<BelId> &;
|
||||||
using BelAttrsRangeT = const std::map<IdString, std::string> &;
|
using BelAttrsRangeT = const std::map<IdString, std::string> &;
|
||||||
using BelPinsRangeT = std::vector<IdString>;
|
using BelPinsRangeT = std::vector<IdString>;
|
||||||
|
using CellBelPinRangeT = std::array<IdString, 1>;
|
||||||
// Wires
|
// Wires
|
||||||
using AllWiresRangeT = const std::vector<WireId> &;
|
using AllWiresRangeT = const std::vector<WireId> &;
|
||||||
using DownhillPipRangeT = const std::vector<PipId> &;
|
using DownhillPipRangeT = const std::vector<PipId> &;
|
||||||
@ -243,6 +244,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
WireId getBelPinWire(BelId bel, IdString pin) const override;
|
WireId getBelPinWire(BelId bel, IdString pin) const override;
|
||||||
PortType getBelPinType(BelId bel, IdString pin) const override;
|
PortType getBelPinType(BelId bel, IdString pin) const override;
|
||||||
std::vector<IdString> getBelPins(BelId bel) const override;
|
std::vector<IdString> getBelPins(BelId bel) const override;
|
||||||
|
std::array<IdString, 1> getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override;
|
||||||
|
|
||||||
WireId getWireByName(IdStringList name) const override;
|
WireId getWireByName(IdStringList name) const override;
|
||||||
IdStringList getWireName(WireId wire) const override;
|
IdStringList getWireName(WireId wire) const override;
|
||||||
|
@ -822,6 +822,8 @@ std::vector<IdString> Arch::getBelPins(BelId bel) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<IdString, 1> Arch::getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const { return {pin}; }
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
WireId Arch::getWireByName(IdStringList name) const
|
WireId Arch::getWireByName(IdStringList name) const
|
||||||
|
@ -251,6 +251,7 @@ struct ArchRanges
|
|||||||
using TileBelsRangeT = const std::vector<BelId> &;
|
using TileBelsRangeT = const std::vector<BelId> &;
|
||||||
using BelAttrsRangeT = const std::map<IdString, std::string> &;
|
using BelAttrsRangeT = const std::map<IdString, std::string> &;
|
||||||
using BelPinsRangeT = std::vector<IdString>;
|
using BelPinsRangeT = std::vector<IdString>;
|
||||||
|
using CellBelPinRangeT = std::array<IdString, 1>;
|
||||||
// Wires
|
// Wires
|
||||||
using AllWiresRangeT = const std::vector<WireId> &;
|
using AllWiresRangeT = const std::vector<WireId> &;
|
||||||
using DownhillPipRangeT = const std::vector<PipId> &;
|
using DownhillPipRangeT = const std::vector<PipId> &;
|
||||||
@ -375,6 +376,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
WireId getBelPinWire(BelId bel, IdString pin) const override;
|
WireId getBelPinWire(BelId bel, IdString pin) const override;
|
||||||
PortType getBelPinType(BelId bel, IdString pin) const override;
|
PortType getBelPinType(BelId bel, IdString pin) const override;
|
||||||
std::vector<IdString> getBelPins(BelId bel) const override;
|
std::vector<IdString> getBelPins(BelId bel) const override;
|
||||||
|
std::array<IdString, 1> getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override;
|
||||||
|
|
||||||
WireId getWireByName(IdStringList name) const override;
|
WireId getWireByName(IdStringList name) const override;
|
||||||
IdStringList getWireName(WireId wire) const override;
|
IdStringList getWireName(WireId wire) const override;
|
||||||
|
@ -53,7 +53,7 @@ struct NexusGlobalRouter
|
|||||||
|
|
||||||
// Lookup source and destination wires
|
// Lookup source and destination wires
|
||||||
WireId src = ctx->getNetinfoSourceWire(net);
|
WireId src = ctx->getNetinfoSourceWire(net);
|
||||||
WireId dst = ctx->getNetinfoSinkWire(net, net->users.at(user_idx));
|
WireId dst = ctx->getNetinfoSinkWire(net, net->users.at(user_idx), 0);
|
||||||
|
|
||||||
if (src == WireId())
|
if (src == WireId())
|
||||||
log_error("Net '%s' has an invalid source port %s.%s\n", ctx->nameOf(net), ctx->nameOf(net->driver.cell),
|
log_error("Net '%s' has an invalid source port %s.%s\n", ctx->nameOf(net), ctx->nameOf(net->driver.cell),
|
||||||
|
Loading…
Reference in New Issue
Block a user