|
3 | 3 |
|
4 | 4 | #include "MakeWireParasitics.h" |
5 | 5 |
|
| 6 | +#include <algorithm> |
6 | 7 | #include <cmath> |
7 | 8 | #include <cstddef> |
| 9 | +#include <iterator> |
| 10 | +#include <map> |
8 | 11 | #include <string> |
| 12 | +#include <utility> |
9 | 13 | #include <vector> |
10 | 14 |
|
11 | 15 | #include "db_sta/SpefWriter.hh" |
@@ -242,6 +246,67 @@ void MakeWireParasitics::makeRouteParasitics(sta::Parasitics* parasitics, |
242 | 246 | parasitics->makeResistor(parasitic, resistor_id_++, res, n1, n2); |
243 | 247 | parasitics->incrCap(n2, cap / 2.0); |
244 | 248 | } |
| 249 | + |
| 250 | + // Workaround: implicit-via post-pass. |
| 251 | + // |
| 252 | + // GRT does not always emit an explicit isVia=true segment at every |
| 253 | + // layer transition along a route; coincident endpoints on adjacent |
| 254 | + // routing levels are treated as implicitly connected. EST has historically |
| 255 | + // taken GRoute literally, so any layer transition without an explicit via |
| 256 | + // segment ends up as two distinct ParasiticNodes at the same (x, y) with |
| 257 | + // no resistor between them -- a disconnected island in the parasitic |
| 258 | + // network. That goes unnoticed by pi-Elmore-based delay calculators but |
| 259 | + // produces a singular conductance matrix in Prima/CCS. |
| 260 | + // |
| 261 | + // Close the contract gap here: scan node_map for coincident endpoints on |
| 262 | + // adjacent routing levels and, when no resistor already bridges them, |
| 263 | + // insert one with the appropriate cut-layer resistance. |
| 264 | + std::vector<std::pair<sta::ParasiticNode*, sta::ParasiticNode*>> |
| 265 | + connected_pairs; |
| 266 | + for (sta::ParasiticResistor* r : parasitics->resistors(parasitic)) { |
| 267 | + sta::ParasiticNode* a = parasitics->node1(r); |
| 268 | + sta::ParasiticNode* b = parasitics->node2(r); |
| 269 | + connected_pairs.emplace_back(std::minmax(a, b)); |
| 270 | + } |
| 271 | + std::ranges::sort(connected_pairs); |
| 272 | + |
| 273 | + if (!node_map.empty()) { |
| 274 | + auto prev_it = node_map.begin(); |
| 275 | + for (auto it = std::next(prev_it); it != node_map.end(); |
| 276 | + prev_it = it, ++it) { |
| 277 | + const auto& prev_pt = prev_it->first; |
| 278 | + const auto& curr_pt = it->first; |
| 279 | + if (prev_pt.x() != curr_pt.x() || prev_pt.y() != curr_pt.y()) { |
| 280 | + continue; |
| 281 | + } |
| 282 | + if (curr_pt.layer() != prev_pt.layer() + 1) { |
| 283 | + // Not adjacent routing levels -- skipping signals that an |
| 284 | + // intermediate routing-level node is missing entirely, which is a |
| 285 | + // different bug worth surfacing rather than silently bridging. |
| 286 | + continue; |
| 287 | + } |
| 288 | + sta::ParasiticNode* lo_node = prev_it->second; |
| 289 | + sta::ParasiticNode* hi_node = it->second; |
| 290 | + const std::pair<sta::ParasiticNode*, sta::ParasiticNode*> pair |
| 291 | + = std::minmax(lo_node, hi_node); |
| 292 | + auto bound_it = std::ranges::lower_bound(connected_pairs, pair); |
| 293 | + if (bound_it != connected_pairs.end() && *bound_it == pair) { |
| 294 | + continue; |
| 295 | + } |
| 296 | + odb::dbTechLayer* lower_routing |
| 297 | + = tech_->findRoutingLayer(prev_pt.layer()); |
| 298 | + odb::dbTechLayer* cut_layer |
| 299 | + = lower_routing ? lower_routing->getUpperLayer() : nullptr; |
| 300 | + if (cut_layer == nullptr) { |
| 301 | + // Top of stack or unresolved -- do not silently invent a resistor. |
| 302 | + continue; |
| 303 | + } |
| 304 | + const float via_R = getCutLayerRes(cut_layer, corner); |
| 305 | + parasitics->makeResistor( |
| 306 | + parasitic, resistor_id_++, via_R, lo_node, hi_node); |
| 307 | + connected_pairs.insert(bound_it, pair); |
| 308 | + } |
| 309 | + } |
245 | 310 | } |
246 | 311 |
|
247 | 312 | void MakeWireParasitics::makeParasiticsToPins( |
|
0 commit comments