From d34074a50ea3ba00affbb5ce8cb498072ceffc8f Mon Sep 17 00:00:00 2001 From: Naveen Venkat Date: Sun, 5 Jul 2026 15:34:15 +0000 Subject: [PATCH] dbSta: check LEF pins against Liberty Signed-off-by: Naveen Venkat --- src/dbSta/BUILD | 2 + src/dbSta/include/db_sta/IpChecker.hh | 4 ++ src/dbSta/src/IpChecker.cc | 35 ++++++++++ src/dbSta/test/BUILD | 10 ++- src/dbSta/test/CMakeLists.txt | 2 + src/dbSta/test/check_ip_liberty_pins.lef | 83 ++++++++++++++++++++++++ src/dbSta/test/check_ip_liberty_pins.lib | 36 ++++++++++ src/dbSta/test/check_ip_liberty_pins.tcl | 26 ++++++++ 8 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 src/dbSta/test/check_ip_liberty_pins.lef create mode 100644 src/dbSta/test/check_ip_liberty_pins.lib create mode 100644 src/dbSta/test/check_ip_liberty_pins.tcl diff --git a/src/dbSta/BUILD b/src/dbSta/BUILD index 3e44147c4cd..bb76195fd0e 100644 --- a/src/dbSta/BUILD +++ b/src/dbSta/BUILD @@ -105,8 +105,10 @@ cc_library( "include", ], deps = [ + ":dbNetwork", ":dbSta", "//src/odb/src/db", + "//src/sta:opensta_lib", "//src/utl", ], ) diff --git a/src/dbSta/include/db_sta/IpChecker.hh b/src/dbSta/include/db_sta/IpChecker.hh index d7e9127f2d0..8ae7b13df7c 100644 --- a/src/dbSta/include/db_sta/IpChecker.hh +++ b/src/dbSta/include/db_sta/IpChecker.hh @@ -30,6 +30,7 @@ namespace sta { // LEF-CHK-009: Pin geometry presence // LEF-CHK-010a: Pin minimum width (perpendicular to routing direction) // LEF-CHK-010b: Pin minimum area +// LEF/LIB-CHK-012: LEF signal pins exist in Liberty class IpChecker { @@ -88,6 +89,9 @@ class IpChecker // LEF-CHK-010b: Pin minimum area void checkPinMinArea(odb::dbMaster* master); + // LEF/LIB-CHK-012: LEF signal pins exist in Liberty + void checkLibertyPinPresence(odb::dbMaster* master); + // Helper: Check if a pin shape has at least one accessible edge bool hasAccessibleEdge(odb::dbMaster* master, const odb::Rect& pin_rect, diff --git a/src/dbSta/src/IpChecker.cc b/src/dbSta/src/IpChecker.cc index 2376d8a1ce2..d7dfec5c70b 100644 --- a/src/dbSta/src/IpChecker.cc +++ b/src/dbSta/src/IpChecker.cc @@ -11,13 +11,16 @@ #include #include #include +#include #include +#include "db_sta/dbNetwork.hh" #include "db_sta/dbSta.hh" #include "odb/PtrSetMap.h" #include "odb/db.h" #include "odb/dbTypes.h" #include "odb/geom.h" +#include "sta/Liberty.hh" #include "utl/Logger.h" namespace sta { @@ -121,6 +124,7 @@ void IpChecker::checkLefMaster(odb::dbMaster* master) checkPinGeometryPresence(master); // LEF-CHK-009 checkPinMinDimensions(master); // LEF-CHK-010a checkPinMinArea(master); // LEF-CHK-010b + checkLibertyPinPresence(master); // LEF/LIB-CHK-012 } // LEF-CHK-001: Macro dimensions aligned to manufacturing grid @@ -693,4 +697,35 @@ void IpChecker::checkPinMinArea(odb::dbMaster* master) } } +// LEF/LIB-CHK-012: LEF signal pins exist in Liberty. +void IpChecker::checkLibertyPinPresence(odb::dbMaster* master) +{ + if (sta_ == nullptr || sta_->getDbNetwork() == nullptr) { + return; + } + + LibertyCell* liberty_cell = sta_->getDbNetwork()->findLibertyCell( + std::string_view(master->getName())); + if (liberty_cell == nullptr) { + return; + } + + const std::string master_name = master->getName(); + for (odb::dbMTerm* mterm : master->getMTerms()) { + if (mterm->getSigType().isSupply()) { + continue; + } + + if (liberty_cell->findLibertyPort(mterm->getName()) == nullptr) { + logger_->warn(utl::CHK, + 121, + "Pin {}/{} missing from Liberty cell {}", + master_name, + mterm->getName(), + liberty_cell->name()); + warning_count_++; + } + } +} + } // namespace sta diff --git a/src/dbSta/test/BUILD b/src/dbSta/test/BUILD index c4c3f277999..0b221dd03e3 100644 --- a/src/dbSta/test/BUILD +++ b/src/dbSta/test/BUILD @@ -83,6 +83,10 @@ ALL_TESTS = [ "write_verilog9_hier", ] +PASSFAIL_TESTS = [ + "check_ip_liberty_pins", +] + filegroup( name = "regression_resources", srcs = [ @@ -288,16 +292,18 @@ filegroup( ], }.get(test_name, []), ) - for test_name in ALL_TESTS + for test_name in ALL_TESTS + PASSFAIL_TESTS ] [ regression_test( name = test_name, + check_log = False if test_name in PASSFAIL_TESTS else True, + check_passfail = True if test_name in PASSFAIL_TESTS else False, data = [":" + test_name + "_resources"], visibility = ["//visibility:public"], ) - for test_name in ALL_TESTS + for test_name in ALL_TESTS + PASSFAIL_TESTS ] cc_test( diff --git a/src/dbSta/test/CMakeLists.txt b/src/dbSta/test/CMakeLists.txt index d3f659ed13c..bdd418a67d6 100644 --- a/src/dbSta/test/CMakeLists.txt +++ b/src/dbSta/test/CMakeLists.txt @@ -71,6 +71,8 @@ or_integration_tests( write_verilog8 write_verilog9 write_verilog9_hier + PASSFAIL_TESTS + check_ip_liberty_pins ) if(ENABLE_TESTS) diff --git a/src/dbSta/test/check_ip_liberty_pins.lef b/src/dbSta/test/check_ip_liberty_pins.lef new file mode 100644 index 00000000000..191d3c2f893 --- /dev/null +++ b/src/dbSta/test/check_ip_liberty_pins.lef @@ -0,0 +1,83 @@ +VERSION 5.8 ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; + +UNITS + DATABASE MICRONS 1000 ; +END UNITS + +MANUFACTURINGGRID 0.005 ; + +LAYER M1 + TYPE ROUTING ; + DIRECTION HORIZONTAL ; + PITCH 0.200 ; + WIDTH 0.100 ; + AREA 0.020 ; +END M1 + +MACRO lef_lib_pins_match + CLASS BLOCK ; + ORIGIN 0 0 ; + SIZE 1.000 BY 1.000 ; + PIN A + DIRECTION INPUT ; + USE SIGNAL ; + ANTENNAMODEL OXIDE1 ; + PORT + LAYER M1 ; + RECT 0.100 0.100 0.300 0.300 ; + END + END A + PIN Z + DIRECTION OUTPUT ; + USE SIGNAL ; + ANTENNAMODEL OXIDE1 ; + PORT + LAYER M1 ; + RECT 0.500 0.500 0.700 0.700 ; + END + END Z + PIN VDD + DIRECTION INOUT ; + USE POWER ; + PORT + LAYER M1 ; + RECT 0.000 0.000 1.000 0.200 ; + END + END VDD +END lef_lib_pins_match + +MACRO lef_lib_pin_missing + CLASS BLOCK ; + ORIGIN 0 0 ; + SIZE 1.000 BY 1.000 ; + PIN A + DIRECTION INPUT ; + USE SIGNAL ; + ANTENNAMODEL OXIDE1 ; + PORT + LAYER M1 ; + RECT 0.100 0.100 0.300 0.300 ; + END + END A + PIN Z + DIRECTION OUTPUT ; + USE SIGNAL ; + ANTENNAMODEL OXIDE1 ; + PORT + LAYER M1 ; + RECT 0.500 0.500 0.700 0.700 ; + END + END Z + PIN VDD + DIRECTION INOUT ; + USE POWER ; + PORT + LAYER M1 ; + RECT 0.000 0.000 1.000 0.200 ; + END + END VDD +END lef_lib_pin_missing + +END LIBRARY diff --git a/src/dbSta/test/check_ip_liberty_pins.lib b/src/dbSta/test/check_ip_liberty_pins.lib new file mode 100644 index 00000000000..84faf7db033 --- /dev/null +++ b/src/dbSta/test/check_ip_liberty_pins.lib @@ -0,0 +1,36 @@ +library (check_ip_liberty_pins) { + delay_model : table_lookup; + capacitive_load_unit (1,pf); + current_unit : "1A"; + pulling_resistance_unit : "1kohm"; + time_unit : "1ns"; + voltage_unit : "1V"; + + cell (lef_lib_pins_match) { + area : 1; + pin (A) { + capacitance : 0.001; + direction : input; + } + pin (Z) { + direction : output; + function : "A"; + } + pg_pin (VDD) { + pg_type : primary_power; + voltage_name : VDD; + } + } + + cell (lef_lib_pin_missing) { + area : 1; + pin (A) { + capacitance : 0.001; + direction : input; + } + pg_pin (VDD) { + pg_type : primary_power; + voltage_name : VDD; + } + } +} diff --git a/src/dbSta/test/check_ip_liberty_pins.tcl b/src/dbSta/test/check_ip_liberty_pins.tcl new file mode 100644 index 00000000000..5757fe83c31 --- /dev/null +++ b/src/dbSta/test/check_ip_liberty_pins.tcl @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026, The OpenROAD Authors + +source "helpers.tcl" + +read_lef check_ip_liberty_pins.lef +read_liberty check_ip_liberty_pins.lib + +proc expect_check_ip_pass { master_name } { + if { [catch { check_ip -master $master_name } err] } { + puts "FAIL: expected $master_name to pass: $err" + exit 1 + } +} + +proc expect_check_ip_fail { master_name } { + if { ![catch { check_ip -master $master_name } err] } { + puts "FAIL: expected $master_name to fail" + exit 1 + } +} + +expect_check_ip_pass lef_lib_pins_match +expect_check_ip_fail lef_lib_pin_missing + +puts "pass"