aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/globals.cc
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-07-29 10:35:05 +0200
committerDavid Shah <davey1576@gmail.com>2018-09-29 16:06:30 +0100
commitd43138b022c84efc01895f51f15244d8a42a5156 (patch)
tree3d4e8e2dca4f644640021d149491eee31ae9021f /ecp5/globals.cc
parent7d48acff52cfa31cf7873d7462a3a4e6395ee520 (diff)
downloadnextpnr-d43138b022c84efc01895f51f15244d8a42a5156.tar.gz
nextpnr-d43138b022c84efc01895f51f15244d8a42a5156.tar.bz2
nextpnr-d43138b022c84efc01895f51f15244d8a42a5156.zip
ecp5: Global routing algorithm up to TAPs
Signed-off-by: David Shah <davey1576@gmail.com>
Diffstat (limited to 'ecp5/globals.cc')
-rw-r--r--ecp5/globals.cc85
1 files changed, 75 insertions, 10 deletions
diff --git a/ecp5/globals.cc b/ecp5/globals.cc
index 770eb7e2..9d51316c 100644
--- a/ecp5/globals.cc
+++ b/ecp5/globals.cc
@@ -17,8 +17,14 @@
*
*/
-#include "nextpnr.h"
#include <algorithm>
+#include <iomanip>
+#include <queue>
+#include "nextpnr.h"
+
+#include "log.h"
+
+#define fmt_str(x) (static_cast<const std::ostringstream &>(std::ostringstream() << x).str())
NEXTPNR_NAMESPACE_BEGIN
@@ -26,15 +32,16 @@ class Ecp5GlobalRouter
{
public:
Ecp5GlobalRouter(Context *ctx) : ctx(ctx){};
- private:
- bool is_clock_port(const PortRef &user) {
+ private:
+ bool is_clock_port(const PortRef &user)
+ {
if (user.cell->type == ctx->id("TRELLIS_LC") && user.port == ctx->id("CLK"))
return true;
return false;
}
- std::vector<NetInfo*> get_clocks()
+ std::vector<NetInfo *> get_clocks()
{
std::unordered_map<IdString, int> clockCount;
for (auto &net : ctx->nets) {
@@ -45,13 +52,11 @@ class Ecp5GlobalRouter
clockCount[ni->name]++;
}
}
- std::vector<NetInfo*> clocks;
+ std::vector<NetInfo *> clocks;
while (clocks.size() < 16) {
- auto max = std::max_element(clockCount.begin(), clockCount.end(), [](
- const decltype(clockCount)::value_type &a, const decltype(clockCount)::value_type &b
- ) {
- return a.second < b.second;
- });
+ auto max = std::max_element(clockCount.begin(), clockCount.end(),
+ [](const decltype(clockCount)::value_type &a,
+ const decltype(clockCount)::value_type &b) { return a.second < b.second; });
if (max == clockCount.end() || max->second < 3)
break;
clocks.push_back(ctx->nets.at(max->first).get());
@@ -77,6 +82,66 @@ class Ecp5GlobalRouter
return *(ctx->getPipsUphill(tap_wire).begin());
}
+ void route_logic_tile_global(IdString net, int global_index, PortRef user)
+ {
+ WireId userWire = ctx->getBelPinWire(user.cell->bel, ctx->portPinFromId(user.port));
+ WireId globalWire;
+ IdString global_name = ctx->id(fmt_str("G_HPBX" << std::setw(2) << std::setfill('0') << global_index << "00"));
+ std::queue<WireId> upstream;
+ std::unordered_map<WireId, PipId> backtrace;
+ upstream.push(userWire);
+ bool already_routed = false;
+ // Search back from the pin until we reach the global network
+ while (true) {
+ WireId next = upstream.front();
+ upstream.pop();
+
+ if (ctx->getBoundWireNet(next) == net) {
+ already_routed = true;
+ globalWire = next;
+ break;
+ }
+
+ if (ctx->getWireBasename(next) == global_name) {
+ globalWire = next;
+ break;
+ }
+ if (ctx->checkWireAvail(next)) {
+ for (auto pip : ctx->getPipsUphill(next)) {
+ WireId src = ctx->getPipSrcWire(pip);
+ backtrace[src] = pip;
+ upstream.push(src);
+ }
+ }
+ if (upstream.size() > 3000) {
+ log_error("failed to route HPBX%02d00 to %s.%s\n", global_index,
+ ctx->getBelName(user.cell->bel).c_str(ctx), user.port.c_str(ctx));
+ }
+ }
+ // Set all the pips we found along the way
+ WireId cursor = userWire;
+ while (true) {
+ auto fnd = backtrace.find(cursor);
+ if (fnd == backtrace.end())
+ break;
+ ctx->bindPip(fnd->second, net, STRENGTH_LOCKED);
+ cursor = ctx->getPipSrcWire(fnd->second);
+ }
+ // If the global network inside the tile isn't already set up,
+ // we also need to bind the buffers along the way
+ if (!already_routed) {
+ ctx->bindWire(cursor, net, STRENGTH_LOCKED);
+ PipId tap_pip = find_tap_pip(cursor);
+ IdString tap_net = ctx->getBoundPipNet(tap_pip);
+ if (tap_net == IdString()) {
+ ctx->bindPip(tap_pip, net, STRENGTH_LOCKED);
+ // TODO: SPINE
+ } else {
+ NPNR_ASSERT(tap_net == net);
+ }
+ }
+ }
+
Context *ctx;
};