diff --git a/src/cts/src/TritonCTS.cpp b/src/cts/src/TritonCTS.cpp index b0389c407b7..90cbc3dcf87 100644 --- a/src/cts/src/TritonCTS.cpp +++ b/src/cts/src/TritonCTS.cpp @@ -1931,6 +1931,13 @@ void TritonCTS::writeClockNDRsToDb(TreeBuilder* builder) odb::dbTech* tech = db_->getTech(); for (int i = 1; i <= tech->getRoutingLayerCount(); i++) { odb::dbTechLayer* layer = tech->findRoutingLayer(i); + // Backside routing layers (BPR, BM*, BRDL) are not clock-routing + // targets; clock trees live on the frontside. Skip them so we do + // not create NDR rules whose widths/spacings are derived from + // backside design rules and would never apply to a clock net. + if (layer->isBackside()) { + continue; + } odb::dbTechLayerRule* layerRule = clockNDR->getLayerRule(layer); if (!layerRule) { layerRule = odb::dbTechLayerRule::create(clockNDR, layer); diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 5a800cf2815..294c51133f6 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -914,7 +914,22 @@ double EstimateParasitics::computeAverageCutResistance(sta::Scene* scene) int max_layer = block_->getMaxRoutingLayer(); if (max_layer < 0) { - max_layer = db_->getTech()->getRoutingLayerCount() / 2; + // Fall back to roughly the middle of the frontside routing stack. + // Halving the total routing-layer count picks the wrong stack when + // backside layers (BPR, BM*, BRDL) push the midpoint below the + // frontside boundary; counting only frontside levels keeps the + // heuristic on the side that hosts the signal routes whose cut + // resistance this function averages. + odb::dbTech* tech = db_->getTech(); + const int total_levels = tech->getRoutingLayerCount(); + odb::dbTechLayer* first_front = tech->firstFrontsideRoutingLayer(); + if (first_front != nullptr) { + const int first_level = first_front->getRoutingLevel(); + const int frontside_count = total_levels - first_level + 1; + max_layer = first_level - 1 + frontside_count / 2; + } else { + max_layer = total_levels / 2; + } } odb::dbTechLayer* min_tech_layer diff --git a/src/grt/src/GlobalRouter.cpp b/src/grt/src/GlobalRouter.cpp index 9e3b4b59906..cdf8ffd7ca8 100644 --- a/src/grt/src/GlobalRouter.cpp +++ b/src/grt/src/GlobalRouter.cpp @@ -796,6 +796,13 @@ void GlobalRouter::checkAdjacentLayersDirection(int min_routing_layer, for (int l = min_routing_layer; l < max_routing_layer; l++) { odb::dbTechLayer* layer_a = tech->findRoutingLayer(l); odb::dbTechLayer* layer_b = tech->findRoutingLayer(l + 1); + // Backside and frontside routing layers sit on opposite sides of the + // substrate, so "adjacent routing level" across the side boundary is + // not a physical neighbor relationship and direction agreement there + // is not a misconfiguration. + if (layer_a->isBackside() != layer_b->isBackside()) { + continue; + } if (layer_a->getDirection() == layer_b->getDirection()) { logger_->error( GRT,