aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-02-10 14:31:16 +0000
committergatecat <gatecat@ds0.me>2021-02-10 14:46:03 +0000
commit7dafc64f78270ec37e2155c609da7cbf2ae18028 (patch)
treedae81b9d7c3ca4fe260f2f3f08a7ffbc8a128dc1 /common
parent535723f414a77eb4aa43b794627bbd4aca56f6f0 (diff)
downloadnextpnr-7dafc64f78270ec37e2155c609da7cbf2ae18028.tar.gz
nextpnr-7dafc64f78270ec37e2155c609da7cbf2ae18028.tar.bz2
nextpnr-7dafc64f78270ec37e2155c609da7cbf2ae18028.zip
router1: Support for multiple bel pins per cell pin
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common')
-rw-r--r--common/router1.cc140
1 files changed, 78 insertions, 62 deletions
diff --git a/common/router1.cc b/common/router1.cc
index 51a356bc..efc06b06 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -32,12 +32,20 @@ USING_NEXTPNR_NAMESPACE
struct arc_key
{
NetInfo *net_info;
+ // logical user cell port index
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
{
- 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
@@ -46,6 +54,7 @@ struct arc_key
{
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.phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
@@ -142,9 +151,10 @@ struct Router1
NetInfo *net_info = arc.net_info;
int user_idx = arc.user_idx;
+ unsigned phys_idx = arc.phys_idx;
auto src_wire = ctx->getNetinfoSourceWire(net_info);
- auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], 0);
+ auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], phys_idx);
arc_queue_insert(arc, src_wire, dst_wire);
}
@@ -302,27 +312,29 @@ struct Router1
log_assert(src_wire != WireId());
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], 0);
- log_assert(dst_wire != WireId());
-
- arc_key arc;
- arc.net_info = net_info;
- arc.user_idx = user_idx;
-
- valid_arcs.insert(arc);
+ unsigned phys_idx = 0;
+ for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
+ log_assert(dst_wire != WireId());
+
+ arc_key arc;
+ arc.net_info = net_info;
+ arc.user_idx = user_idx;
+ arc.phys_idx = phys_idx++;
+ valid_arcs.insert(arc);
#if 0
- if (ctx->debug)
+ if (ctx->debug)
log("[check] arc: %s %s\n", ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire));
#endif
- for (WireId wire : arc_to_wires[arc]) {
+ for (WireId wire : arc_to_wires[arc]) {
#if 0
- if (ctx->debug)
+ if (ctx->debug)
log("[check] wire: %s\n", ctx->nameOfWire(wire));
#endif
- valid_wires_for_net.insert(wire);
- log_assert(wire_to_arcs[wire].count(arc));
- log_assert(net_info->wires.count(wire));
+ valid_wires_for_net.insert(wire);
+ log_assert(wire_to_arcs[wire].count(arc));
+ 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);
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], 0);
-
- if (dst_wire == WireId())
- log_error("No wire 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));
-
- if (dst_to_arc.count(dst_wire)) {
- if (dst_to_arc.at(dst_wire).net_info == net_info)
- 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;
+ 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_to_arc.count(dst_wire)) {
+ if (dst_to_arc.at(dst_wire).net_info == net_info)
+ 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 (net_info->wires.count(dst_wire) == 0) {
- arc_queue_insert(arc, src_wire, dst_wire);
- continue;
- }
+ 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);
- WireId cursor = dst_wire;
- wire_to_arcs[cursor].insert(arc);
- arc_to_wires[arc].insert(cursor);
+ dst_to_arc[dst_wire] = arc;
- while (src_wire != cursor) {
- auto it = net_info->wires.find(cursor);
- if (it == net_info->wires.end()) {
+ if (net_info->wires.count(dst_wire) == 0) {
arc_queue_insert(arc, src_wire, dst_wire);
- break;
+ continue;
}
- NPNR_ASSERT(it->second.pip != PipId());
- cursor = ctx->getPipSrcWire(it->second.pip);
+ 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());
+ 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;
@@ -443,7 +458,7 @@ struct Router1
int user_idx = arc.user_idx;
auto src_wire = ctx->getNetinfoSourceWire(net_info);
- auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], 0);
+ auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], arc.phys_idx);
ripup_flag = false;
if (ctx->debug) {
@@ -934,14 +949,15 @@ bool Context::checkRoutedDesign() const
std::unordered_map<WireId, int> dest_wires;
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], 0);
- log_assert(dst_wire != WireId());
- dest_wires[dst_wire] = user_idx;
+ for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
+ log_assert(dst_wire != WireId());
+ dest_wires[dst_wire] = user_idx;
- if (net_info->wires.count(dst_wire) == 0) {
- if (ctx->debug)
- log(" sink %d (%s) not bound to net\n", user_idx, ctx->nameOfWire(dst_wire));
- found_unrouted = true;
+ if (net_info->wires.count(dst_wire) == 0) {
+ if (ctx->debug)
+ log(" sink %d (%s) not bound to net\n", user_idx, ctx->nameOfWire(dst_wire));
+ found_unrouted = true;
+ }
}
}