|
6 | 6 | #include <limits> |
7 | 7 | #include <map> |
8 | 8 | #include <memory> |
| 9 | +#include <optional> |
9 | 10 | #include <string> |
10 | 11 | #include <unordered_set> |
| 12 | +#include <utility> |
11 | 13 | #include <vector> |
12 | 14 |
|
13 | 15 | #include "PlacementDRC.h" |
@@ -111,6 +113,59 @@ bool bboxIntersectsOuterShell(const Rect& bbox, |
111 | 113 | }); |
112 | 114 | } |
113 | 115 |
|
| 116 | +// Look at single-row CORE masters and return a canonical R0-row (topPwr, |
| 117 | +// botPwr). Requires top != bot so the convention is unambiguous; |
| 118 | +// symmetric-power cells cannot anchor the convention. Returns (UNK, UNK) if |
| 119 | +// none found. |
| 120 | +std::pair<int, int> inferR0RowPower(const Network* network, |
| 121 | + const Grid* grid, |
| 122 | + odb::dbBlock* block) |
| 123 | +{ |
| 124 | + for (odb::dbInst* inst : block->getInsts()) { |
| 125 | + odb::dbMaster* db_master = inst->getMaster(); |
| 126 | + if (db_master->getType() != odb::dbMasterType::CORE) { |
| 127 | + continue; |
| 128 | + } |
| 129 | + if (grid->isMultiHeight(db_master)) { |
| 130 | + continue; |
| 131 | + } |
| 132 | + const Master* dpl_master |
| 133 | + = const_cast<Network*>(network)->getMaster(db_master); |
| 134 | + if (dpl_master == nullptr) { |
| 135 | + continue; |
| 136 | + } |
| 137 | + const int bot = dpl_master->getBottomPowerType(); |
| 138 | + const int top = dpl_master->getTopPowerType(); |
| 139 | + if (bot != Architecture::Row::Power_UNK |
| 140 | + && top != Architecture::Row::Power_UNK && bot != top) { |
| 141 | + return {top, bot}; |
| 142 | + } |
| 143 | + } |
| 144 | + return {Architecture::Row::Power_UNK, Architecture::Row::Power_UNK}; |
| 145 | +} |
| 146 | + |
| 147 | +// Whether the orientation flips the master's Y axis (swapping top and bottom |
| 148 | +// power rails). Only the axis-aligned orientations are expected for standard |
| 149 | +// cell rows; rotations return nullopt so row power stays unknown. |
| 150 | +std::optional<bool> orientFlipsY(const odb::dbOrientType& orient) |
| 151 | +{ |
| 152 | + using odb::dbOrientType; |
| 153 | + switch (orient.getValue()) { |
| 154 | + case dbOrientType::MX: |
| 155 | + case dbOrientType::R180: |
| 156 | + return true; |
| 157 | + case dbOrientType::R0: |
| 158 | + case dbOrientType::MY: |
| 159 | + return false; |
| 160 | + case dbOrientType::R90: |
| 161 | + case dbOrientType::R270: |
| 162 | + case dbOrientType::MXR90: |
| 163 | + case dbOrientType::MYR90: |
| 164 | + return std::nullopt; |
| 165 | + } |
| 166 | + return std::nullopt; |
| 167 | +} |
| 168 | + |
114 | 169 | } // namespace |
115 | 170 |
|
116 | 171 | void Opendp::importDb() |
@@ -292,7 +347,8 @@ void Opendp::createArchitecture() |
292 | 347 | archRow->setSiteWidth(DbuX{site->getWidth()}); |
293 | 348 | archRow->setHeight(DbuY{site->getHeight()}); |
294 | 349 |
|
295 | | - // Set defaults. Top and bottom power is set below. |
| 350 | + // Start with UNK; resolved after all rows are created using an inferred |
| 351 | + // R0 row convention. |
296 | 352 | archRow->setBottomPower(Architecture::Row::Power_UNK); |
297 | 353 | archRow->setTopPower(Architecture::Row::Power_UNK); |
298 | 354 |
|
@@ -356,6 +412,29 @@ void Opendp::createArchitecture() |
356 | 412 | arch_->setPadding(padding_.get()); |
357 | 413 | arch_->setSiteWidth(grid_->getSiteWidth()); |
358 | 414 |
|
| 415 | + // Populate each row's top/bottom power rail from an inferred R0 convention. |
| 416 | + // Without this, row power stays Power_UNK and Architecture::powerCompatible |
| 417 | + // degenerates to "always true", letting multi-row cells land on wrong-parity |
| 418 | + // rows (VDD pin on VSS stripe, etc.). |
| 419 | + const auto [ref_r0_top, ref_r0_bot] |
| 420 | + = inferR0RowPower(network_.get(), grid_.get(), block); |
| 421 | + if (ref_r0_bot != Architecture::Row::Power_UNK) { |
| 422 | + for (int r = 0; r < arch_->getNumRows(); r++) { |
| 423 | + Architecture::Row* archRow = arch_->getRow(r); |
| 424 | + const auto flipped = orientFlipsY(archRow->getOrient()); |
| 425 | + if (!flipped.has_value()) { |
| 426 | + continue; // Rotation — leave as UNK. |
| 427 | + } |
| 428 | + if (*flipped) { |
| 429 | + archRow->setBottomPower(ref_r0_top); |
| 430 | + archRow->setTopPower(ref_r0_bot); |
| 431 | + } else { |
| 432 | + archRow->setBottomPower(ref_r0_bot); |
| 433 | + archRow->setTopPower(ref_r0_top); |
| 434 | + } |
| 435 | + } |
| 436 | + } |
| 437 | + |
359 | 438 | arch_->postProcess(network_.get()); |
360 | 439 | } |
361 | 440 |
|
|
0 commit comments