ecp5: Global routing algorithm up to TAPs

Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
David Shah 2018-07-29 10:35:05 +02:00
parent 7d48acff52
commit d43138b022

View File

@ -17,8 +17,14 @@
* *
*/ */
#include "nextpnr.h"
#include <algorithm> #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 NEXTPNR_NAMESPACE_BEGIN
@ -26,15 +32,16 @@ class Ecp5GlobalRouter
{ {
public: public:
Ecp5GlobalRouter(Context *ctx) : ctx(ctx){}; 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")) if (user.cell->type == ctx->id("TRELLIS_LC") && user.port == ctx->id("CLK"))
return true; return true;
return false; return false;
} }
std::vector<NetInfo*> get_clocks() std::vector<NetInfo *> get_clocks()
{ {
std::unordered_map<IdString, int> clockCount; std::unordered_map<IdString, int> clockCount;
for (auto &net : ctx->nets) { for (auto &net : ctx->nets) {
@ -45,13 +52,11 @@ class Ecp5GlobalRouter
clockCount[ni->name]++; clockCount[ni->name]++;
} }
} }
std::vector<NetInfo*> clocks; std::vector<NetInfo *> clocks;
while (clocks.size() < 16) { while (clocks.size() < 16) {
auto max = std::max_element(clockCount.begin(), clockCount.end(), []( auto max = std::max_element(clockCount.begin(), clockCount.end(),
const decltype(clockCount)::value_type &a, const decltype(clockCount)::value_type &b [](const decltype(clockCount)::value_type &a,
) { const decltype(clockCount)::value_type &b) { return a.second < b.second; });
return a.second < b.second;
});
if (max == clockCount.end() || max->second < 3) if (max == clockCount.end() || max->second < 3)
break; break;
clocks.push_back(ctx->nets.at(max->first).get()); clocks.push_back(ctx->nets.at(max->first).get());
@ -77,6 +82,66 @@ class Ecp5GlobalRouter
return *(ctx->getPipsUphill(tap_wire).begin()); 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; Context *ctx;
}; };