From 41f585431f99422666a6859ed262b4cad7f1eee6 Mon Sep 17 00:00:00 2001 From: Ruohan Yan Date: Fri, 7 Aug 2026 15:32:17 -0700 Subject: [PATCH] add SOCV derate library support --- hammer/common/cadence/__init__.py | 31 +++++++++++++++++++++++++++---- hammer/par/innovus/__init__.py | 6 ++++++ hammer/tech/__init__.py | 20 ++++++++++++++++++++ hammer/timing/tempus/__init__.py | 6 ++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/hammer/common/cadence/__init__.py b/hammer/common/cadence/__init__.py index 3215c5ae1..5c93dc0ed 100644 --- a/hammer/common/cadence/__init__.py +++ b/hammer/common/cadence/__init__.py @@ -88,6 +88,25 @@ def get_mmmc_qrc(self, corner: MMMCCorner) -> str: self.filter_for_mmmc(voltage=corner.voltage, temp=corner.temp)]) return " ".join(lib_args) + def get_socv_libs(self, corner: Optional[MMMCCorner] = None) -> str: + """ + Helper function to get the list of SOCV derate files in space separated format. + Returns an empty string if no SOCV files are present. + + :param corner: Optional corner to consider. If supplied, filters SOCV files matching the corner. + :return: List of SOCV files separated by spaces + """ + pre_filters = optional_map(corner, lambda c: [self.filter_for_mmmc(voltage=c.voltage, temp=c.temp)]) + lib_args = self.technology.read_libs([hammer_tech.filters.socv_filter], + hammer_tech.HammerTechnologyUtils.to_plain_item, + extra_pre_filters=pre_filters) + return " ".join(lib_args) + + @property + def has_socv(self) -> bool: + """True if any library provides SOCV derate files.""" + return self.get_socv_libs() != "" + def get_qrc_tech(self) -> str: """ Helper function to get the list of rc corner tech files in space separated format. @@ -186,9 +205,11 @@ def append_mmmc(cmd: str) -> None: raise ValueError("Unsupported MMMCCornerType") # First, create Innovus library sets - append_mmmc("create_library_set -name {name}_set -timing [list {list}]".format( + socv = self.get_socv_libs(corner) + append_mmmc("create_library_set -name {name}_set -timing [list {list}]{socv}".format( name=corner_name, - list=self.get_timing_libs(corner) + list=self.get_timing_libs(corner), + socv=" -socv [list {}]".format(socv) if socv else "" )) # Skip opconds for now # Next, create Innovus timing conditions @@ -227,9 +248,11 @@ def append_mmmc(cmd: str) -> None: else: # First, create an Innovus library set. library_set_name = "my_lib_set" - append_mmmc("create_library_set -name {name} -timing [list {list}]".format( + socv = self.get_socv_libs() + append_mmmc("create_library_set -name {name} -timing [list {list}]{socv}".format( name=library_set_name, - list=self.get_timing_libs() + list=self.get_timing_libs(), + socv=" -socv [list {}]".format(socv) if socv else "" )) # Next, create an Innovus timing condition. timing_condition_name = "my_timing_condition" diff --git a/hammer/par/innovus/__init__.py b/hammer/par/innovus/__init__.py index 4d61623e5..a2845412b 100644 --- a/hammer/par/innovus/__init__.py +++ b/hammer/par/innovus/__init__.py @@ -280,6 +280,12 @@ def init_design(self) -> bool: verbose_append("set_db timing_analysis_cppr both") # Use OCV mode for timing analysis by default verbose_append("set_db timing_analysis_type ocv") + # Enable SOCV analysis if any library provides SOCV derate files + if self.has_socv: + verbose_append("set_db timing_analysis_socv true") + verbose_append("set_db timing_socv_rc_variation_mode true") + verbose_append("set_db timing_enable_socv_skewness_propagation_mode true") + verbose_append("set_db delaycal_socv_accuracy_mode medium") # Read LEF layouts. lef_files = self.technology.read_libs([ diff --git a/hammer/tech/__init__.py b/hammer/tech/__init__.py index b4e844252..d924200ef 100644 --- a/hammer/tech/__init__.py +++ b/hammer/tech/__init__.py @@ -119,6 +119,7 @@ class Library(BaseModel): openaccess_techfile: Optional[str] = None provides: Optional[List[Provide]] = None qrc_techfile: Optional[str] = None + socv_file: Optional[str] = None supplies: Optional[Supplies] = None tluplus_files: Optional[MinMaxCap] = None tluplus_map_file: Optional[TLUPlusMapFile] = None @@ -1334,6 +1335,25 @@ def paths_func(lib: Library) -> List[str]: is_file=True ) + @property + def socv_filter(self) -> LibraryFilter: + """ + Selecting SOCV (Statistical On-Chip Variation) derate files. + """ + + def paths_func(lib: Library) -> List[str]: + if lib.socv_file is not None: + return [lib.socv_file] + else: + return [] + + return LibraryFilter( + tag="socv", + description="SOCV derate file", + paths_func=paths_func, + is_file=True + ) + @property def verilog_synth_filter(self) -> LibraryFilter: """ diff --git a/hammer/timing/tempus/__init__.py b/hammer/timing/tempus/__init__.py index a5b24ee6e..24a5bffbe 100644 --- a/hammer/timing/tempus/__init__.py +++ b/hammer/timing/tempus/__init__.py @@ -180,6 +180,12 @@ def init_design(self) -> bool: verbose_append("set_db timing_analysis_cppr both") # On-chip variation analysis verbose_append("set_db timing_analysis_type ocv") + # Enable SOCV analysis if any library provides SOCV derate files + if self.has_socv: + verbose_append("set_db timing_analysis_socv true") + verbose_append("set_db timing_socv_rc_variation_mode true") + verbose_append("set_db timing_enable_socv_skewness_propagation_mode true") + verbose_append("set_db delaycal_socv_accuracy_mode medium") # Partial path-based analysis even in graph-based analysis mode verbose_append("set_db timing_analysis_graph_pba_mode true") # Equivalent waveform model w/ waveform propagation