ecp5: Fix placement of DCCs to guarantee routeability
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
be50947fa6
commit
43fd9e6779
@ -291,11 +291,12 @@ class Ecp5GlobalRouter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get DCC wirelength based on source
|
// Get DCC wirelength based on source
|
||||||
wirelen_t get_dcc_wirelen(CellInfo *dcc)
|
wirelen_t get_dcc_wirelen(CellInfo *dcc, bool &dedicated_routing)
|
||||||
{
|
{
|
||||||
NetInfo *clki = dcc->ports.at(id_CLKI).net;
|
NetInfo *clki = dcc->ports.at(id_CLKI).net;
|
||||||
BelId drv_bel;
|
BelId drv_bel;
|
||||||
const PortRef &drv = clki->driver;
|
const PortRef &drv = clki->driver;
|
||||||
|
dedicated_routing = false;
|
||||||
if (drv.cell == nullptr) {
|
if (drv.cell == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (drv.cell->attrs.count(ctx->id("BEL"))) {
|
} else if (drv.cell->attrs.count(ctx->id("BEL"))) {
|
||||||
@ -326,6 +327,7 @@ class Ecp5GlobalRouter
|
|||||||
if (has_short_route(ctx->getBelPinWire(drv_bel, drv.port), ctx->getBelPinWire(dcc->bel, id_CLKI))) {
|
if (has_short_route(ctx->getBelPinWire(drv_bel, drv.port), ctx->getBelPinWire(dcc->bel, id_CLKI))) {
|
||||||
// log_info("dedicated route %s -> %s\n", ctx->getWireName(ctx->getBelPinWire(drv_bel,
|
// log_info("dedicated route %s -> %s\n", ctx->getWireName(ctx->getBelPinWire(drv_bel,
|
||||||
// drv.port)).c_str(ctx), ctx->getBelName(dcc->bel).c_str(ctx));
|
// drv.port)).c_str(ctx), ctx->getBelName(dcc->bel).c_str(ctx));
|
||||||
|
dedicated_routing = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Driver is locked
|
// Driver is locked
|
||||||
@ -375,12 +377,31 @@ class Ecp5GlobalRouter
|
|||||||
return length < thresh;
|
return length < thresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_set<WireId> used_pclkcib;
|
||||||
|
|
||||||
|
std::set<WireId> get_candidate_pclkcibs(BelId dcc)
|
||||||
|
{
|
||||||
|
std::set<WireId> candidates;
|
||||||
|
WireId dcc_i = ctx->getBelPinWire(dcc, id_CLKI);
|
||||||
|
WireId dcc_mux = ctx->getPipSrcWire(*(ctx->getPipsUphill(dcc_i).begin()));
|
||||||
|
for (auto pip : ctx->getPipsUphill(dcc_mux)) {
|
||||||
|
WireId src = ctx->getPipSrcWire(pip);
|
||||||
|
std::string basename = ctx->nameOf(ctx->getWireBasename(src));
|
||||||
|
if (basename.find("QPCLKCIB") == std::string::npos)
|
||||||
|
continue;
|
||||||
|
candidates.insert(src);
|
||||||
|
}
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to place a DCC
|
// Attempt to place a DCC
|
||||||
void place_dcc(CellInfo *dcc)
|
void place_dcc(CellInfo *dcc)
|
||||||
{
|
{
|
||||||
BelId best_bel;
|
BelId best_bel;
|
||||||
|
WireId best_bel_pclkcib;
|
||||||
bool using_ce = get_net_or_empty(dcc, ctx->id("CE")) != nullptr;
|
bool using_ce = get_net_or_empty(dcc, ctx->id("CE")) != nullptr;
|
||||||
wirelen_t best_wirelen = 9999999;
|
wirelen_t best_wirelen = 9999999;
|
||||||
|
bool dedicated_routing = false;
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->getBelType(bel) == id_DCCA && ctx->checkBelAvail(bel)) {
|
if (ctx->getBelType(bel) == id_DCCA && ctx->checkBelAvail(bel)) {
|
||||||
if (ctx->isValidBelForCell(dcc, bel)) {
|
if (ctx->isValidBelForCell(dcc, bel)) {
|
||||||
@ -388,17 +409,38 @@ class Ecp5GlobalRouter
|
|||||||
if (belname.at(0) == 'D' && using_ce)
|
if (belname.at(0) == 'D' && using_ce)
|
||||||
continue; // don't allow DCCs with CE at center
|
continue; // don't allow DCCs with CE at center
|
||||||
ctx->bindBel(bel, dcc, STRENGTH_LOCKED);
|
ctx->bindBel(bel, dcc, STRENGTH_LOCKED);
|
||||||
wirelen_t wirelen = get_dcc_wirelen(dcc);
|
wirelen_t wirelen = get_dcc_wirelen(dcc, dedicated_routing);
|
||||||
if (wirelen < best_wirelen) {
|
if (wirelen < best_wirelen) {
|
||||||
|
if (dedicated_routing) {
|
||||||
|
best_bel_pclkcib = WireId();
|
||||||
|
} else {
|
||||||
|
bool found_pclkcib = false;
|
||||||
|
for (WireId pclkcib : get_candidate_pclkcibs(bel)) {
|
||||||
|
if (used_pclkcib.count(pclkcib))
|
||||||
|
continue;
|
||||||
|
found_pclkcib = true;
|
||||||
|
best_bel_pclkcib = pclkcib;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found_pclkcib)
|
||||||
|
goto pclkcib_fail;
|
||||||
|
}
|
||||||
best_bel = bel;
|
best_bel = bel;
|
||||||
best_wirelen = wirelen;
|
best_wirelen = wirelen;
|
||||||
}
|
}
|
||||||
|
pclkcib_fail:
|
||||||
ctx->unbindBel(bel);
|
ctx->unbindBel(bel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NPNR_ASSERT(best_bel != BelId());
|
NPNR_ASSERT(best_bel != BelId());
|
||||||
ctx->bindBel(best_bel, dcc, STRENGTH_LOCKED);
|
ctx->bindBel(best_bel, dcc, STRENGTH_LOCKED);
|
||||||
|
if (best_bel_pclkcib != WireId()) {
|
||||||
|
used_pclkcib.insert(best_bel_pclkcib);
|
||||||
|
if (ctx->verbose)
|
||||||
|
log_info(" preliminary allocation of PCLKCIB '%s' to DCC '%s' at '%s'\n",
|
||||||
|
ctx->nameOfWire(best_bel_pclkcib), ctx->nameOf(dcc), ctx->nameOfBel(best_bel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert a DCC into a net to promote it to a global
|
// Insert a DCC into a net to promote it to a global
|
||||||
|
Loading…
Reference in New Issue
Block a user