Skip to content

Commit 814048c

Browse files
authored
Merge pull request #7904 from gadfort/pdn-check-setup
pdn: add error checking to connect rules to prevent rules with no actual target
2 parents 0b14e07 + 82ef091 commit 814048c

16 files changed

+166
-9
lines changed

src/pdn/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Build a power grid in accordance with the information specified.
2121

2222
```tcl
2323
pdngen
24+
[-check_only]
2425
[-dont_add_pins]
2526
[-failed_via_report file]
2627
[-report_only]
@@ -36,6 +37,7 @@ pdngen
3637
| `[-dont_add_pins]` | Prevent the creation of block pins. |
3738
| `[-failed_via_report]` | Generate a report file which can be viewed in the DRC viewer for all the failed vias (ie. those that did not get built or were removed). |
3839
| `[-report_only]` | Print the current specifications. |
40+
| `[-check_only]` | Check the current setup for errors. |
3941
| `[-reset]` | Reset the grid and domain specifications. |
4042
| `[-ripup]` | Ripup the existing power grid, as specified by the voltage domains. |
4143
| `[-skip_trim]` | Skip the metal trim step, which attempts to remove metal stubs. |

src/pdn/include/pdn/PdnGen.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class PdnGen
7171
odb::dbMTerm* switched_power,
7272
odb::dbMTerm* alwayson_power,
7373
odb::dbMTerm* ground);
74+
const std::vector<std::unique_ptr<PowerCell>>& getSwitchedPowerCells() const
75+
{
76+
return switched_power_cells_;
77+
}
7478

7579
// Domains
7680
std::vector<VoltageDomain*> getDomains() const;

src/pdn/src/grid.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,101 @@ void Grid::checkSetup() const
647647
}
648648
}
649649
}
650+
651+
// Check connectivity
652+
std::set<odb::dbTechLayer*> check_layers;
653+
for (const auto& ring : rings_) {
654+
for (auto* layer : ring->getLayers()) {
655+
check_layers.insert(layer);
656+
}
657+
}
658+
for (const auto& strap : straps_) {
659+
check_layers.insert(strap->getLayer());
660+
}
661+
662+
// Check that pin layers actually exists in stack
663+
for (auto* layer : pin_layers_) {
664+
if (check_layers.find(layer) == check_layers.end()) {
665+
getLogger()->error(utl::PDN,
666+
111,
667+
"Pin layer {} is not a valid shape in {}",
668+
layer->getName(),
669+
name_);
670+
}
671+
}
672+
673+
// add instance layers
674+
const auto nets_vec = getNets();
675+
const std::set<odb::dbNet*> nets(nets_vec.begin(), nets_vec.end());
676+
677+
for (auto* inst : getInstances()) {
678+
if (!inst->isFixed()) {
679+
continue;
680+
}
681+
for (auto* iterm : inst->getITerms()) {
682+
if (nets.find(iterm->getNet()) != nets.end()) {
683+
for (const auto& [layer, shape] : iterm->getGeometries()) {
684+
check_layers.insert(layer);
685+
}
686+
}
687+
}
688+
}
689+
if (domain_->hasSwitchedPower()) {
690+
for (const auto& powercell :
691+
domain_->getPDNGen()->getSwitchedPowerCells()) {
692+
for (auto* mterm : powercell->getMaster()->getMTerms()) {
693+
for (auto* mpin : mterm->getMPins()) {
694+
for (auto* box : mpin->getGeometry()) {
695+
auto* layer = box->getTechLayer();
696+
if (layer) {
697+
check_layers.insert(layer);
698+
}
699+
}
700+
}
701+
}
702+
}
703+
}
704+
705+
// add bterms and exisiting routing
706+
for (auto* net : nets) {
707+
for (auto* swire : net->getSWires()) {
708+
for (auto* box : swire->getWires()) {
709+
auto* layer = box->getTechLayer();
710+
if (layer) {
711+
check_layers.insert(layer);
712+
}
713+
}
714+
}
715+
for (auto* bterm : net->getBTerms()) {
716+
for (auto* bpin : bterm->getBPins()) {
717+
if (!bpin->getPlacementStatus().isFixed()) {
718+
continue;
719+
}
720+
for (auto* box : bpin->getBoxes()) {
721+
auto* layer = box->getTechLayer();
722+
if (layer) {
723+
check_layers.insert(layer);
724+
}
725+
}
726+
}
727+
}
728+
}
729+
730+
// Check that connect statement actually point to something
731+
for (const auto& connect : connect_) {
732+
if (check_layers.find(connect->getLowerLayer()) == check_layers.end()) {
733+
getLogger()->error(utl::PDN,
734+
112,
735+
"Cannot find shapes to connect to on {}",
736+
connect->getLowerLayer()->getName());
737+
}
738+
if (check_layers.find(connect->getUpperLayer()) == check_layers.end()) {
739+
getLogger()->error(utl::PDN,
740+
113,
741+
"Cannot find shapes to connect to on {}",
742+
connect->getUpperLayer()->getName());
743+
}
744+
}
650745
}
651746

652747
void Grid::getObstructions(Shape::ObstructionTreeMap& obstructions) const

src/pdn/src/pdn.tcl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ sta::define_cmd_args "pdngen" {[-skip_trim] \
66
[-reset] \
77
[-ripup] \
88
[-report_only] \
9+
[-check_only] \
910
[-failed_via_report file] \
1011
[-verbose]
1112
} ;#checker off
1213

1314
proc pdngen { args } {
1415
sta::parse_key_args "pdngen" args \
15-
keys {-failed_via_report} flags {-skip_trim -dont_add_pins -reset -ripup -report_only -verbose}
16+
keys {-failed_via_report} \
17+
flags {-skip_trim -dont_add_pins -reset -ripup -report_only -verbose -check_only}
1618

1719
sta::check_argc_eq0 "pdngen" $args
1820

@@ -43,6 +45,13 @@ proc pdngen { args } {
4345
pdn::report
4446
return
4547
}
48+
if { [info exists flags(-check_only)] } {
49+
if { [array size flags] != 1 } {
50+
utl::error PDN 1040 "-check_only flag is mutually exclusive to all other flags"
51+
}
52+
pdn::check_setup
53+
return
54+
}
4655

4756
set trim [expr [info exists flags(-skip_trim)] == 0]
4857
set add_pins [expr [info exists flags(-dont_add_pins)] == 0]

src/pdn/test/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ COMPULSORY_TESTS = [
2525
"core_grid_auto_domain_multiple_nets",
2626
"core_grid_bad_metal_specs",
2727
"core_grid_check_connect_layers",
28+
"core_grid_check_connect_layers_at_setup",
2829
"core_grid_cut_pitch",
2930
"core_grid_dual_followpins",
3031
"core_grid_dual_followpins_error",

src/pdn/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ or_integration_tests(
2424
core_grid_auto_domain_multiple_nets
2525
core_grid_bad_metal_specs
2626
core_grid_check_connect_layers
27+
core_grid_check_connect_layers_at_setup
2728
core_grid_cut_pitch
2829
core_grid_dual_followpins
2930
core_grid_dual_followpins_error
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells
2+
[INFO ODB-0128] Design: gcd
3+
[INFO ODB-0130] Created 54 pins.
4+
[INFO ODB-0131] Created 482 components and 2074 component-terminals.
5+
[INFO ODB-0133] Created 385 nets and 1110 connections.
6+
[ERROR PDN-0111] Pin layer metal6 is not a valid shape in Core
7+
PDN-0111
8+
[ERROR PDN-0113] Cannot find shapes to connect to on metal5
9+
PDN-0113
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# test for rejesting incorrect layers at runtime
2+
source "helpers.tcl"
3+
4+
read_lef Nangate45/Nangate45.lef
5+
read_def nangate_gcd/floorplan.def
6+
7+
add_global_connection -net VDD -pin_pattern VDD -power
8+
add_global_connection -net VSS -pin_pattern VSS -ground
9+
10+
set_voltage_domain -power VDD -ground VSS
11+
12+
define_pdn_grid -name "Core" -pins metal6
13+
add_pdn_stripe -followpins -layer metal1
14+
add_pdn_stripe -followpins -layer metal2
15+
16+
add_pdn_stripe -layer metal4 -width 0.48 -pitch 15.0 -offset 2.0
17+
add_pdn_stripe -layer metal7 -width 1.40 -pitch 20.0 -offset 2.0
18+
19+
add_pdn_connect -layers {metal1 metal2}
20+
add_pdn_connect -layers {metal2 metal4}
21+
add_pdn_connect -layers {metal4 metal7}
22+
23+
# Check pin layer
24+
catch { pdngen -check_only } err
25+
puts $err
26+
27+
pdngen -reset
28+
29+
set_voltage_domain -power VDD -ground VSS
30+
31+
define_pdn_grid -name "Core" -pins metal7
32+
add_pdn_stripe -followpins -layer metal1
33+
add_pdn_stripe -followpins -layer metal2
34+
35+
add_pdn_stripe -layer metal4 -width 0.48 -pitch 15.0 -offset 2.0
36+
add_pdn_stripe -layer metal7 -width 1.40 -pitch 20.0 -offset 2.0
37+
38+
add_pdn_connect -layers {metal1 metal2}
39+
add_pdn_connect -layers {metal2 metal5}
40+
add_pdn_connect -layers {metal4 metal7}
41+
42+
# Check connect layer metal5 invalid
43+
catch { pdngen -check_only } err
44+
puts $err

src/pdn/test/power_switch.ok

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ Straps:
4141
Snap to grid: false
4242
Connect:
4343
Connect layers met1 -> met4
44-
Connect layers met2 -> met4
4544
Connect layers met4 -> met5
4645
Switched power cell: POWER_SWITCH
4746
Control net: nPWRUP

src/pdn/test/power_switch.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
pdn_aux.add_pdn_stripe(design, layer="met5", width=1.600, pitch=27.200, offset=13.600)
4545

4646
pdn_aux.add_pdn_connect(design, layers=["met1", "met4"])
47-
pdn_aux.add_pdn_connect(design, layers=["met2", "met4"])
4847
pdn_aux.add_pdn_connect(design, layers=["met4", "met5"])
4948

5049
design.getPdnGen().report()

0 commit comments

Comments
 (0)