diff --git a/hammer/common/cadence/__init__.py b/hammer/common/cadence/__init__.py index 3fd05ccb0..4d0702f7a 100644 --- a/hammer/common/cadence/__init__.py +++ b/hammer/common/cadence/__init__.py @@ -7,7 +7,7 @@ from hammer.vlsi import HammerTool, HasSDCSupport, HasCPFSupport, HasUPFSupport, TCLTool, ILMStruct from hammer.vlsi.constraints import MMMCCorner, MMMCCornerType -from hammer.utils import optional_map, add_dicts +from hammer.utils import optional_map, add_dicts, reduce_list_str, add_lists import hammer.tech as hammer_tech @@ -146,9 +146,16 @@ def append_mmmc(cmd: str) -> None: blank_sdc = os.path.join(self.run_dir, "blank.sdc") self.run_executable(["touch", blank_sdc]) sdc_files_arg = "-sdc_files {{ {} }}".format(blank_sdc) - append_mmmc("create_constraint_mode -name {name} {sdc_files_arg}".format( + if self.hierarchical_mode.is_nonleaf_hierarchical(): + ilm_sdcs = reduce_list_str(add_lists, list(map(lambda ilm: ilm.sdcs, self.get_input_ilms()))) # type: List[str] + ilm_sdc_files_arg = "-ilm_sdc_files [list {sdc_files}]".format( + sdc_files=" ".join(ilm_sdcs)) + else: + ilm_sdc_files_arg = "" + append_mmmc("create_constraint_mode -name {name} {sdc_files_arg} {ilm_sdc_files_arg}".format( name=constraint_mode, - sdc_files_arg=sdc_files_arg + sdc_files_arg=sdc_files_arg, + ilm_sdc_files_arg=ilm_sdc_files_arg )) corners = self.get_mmmc_corners() # type: List[MMMCCorner] diff --git a/hammer/config/defaults.yml b/hammer/config/defaults.yml index 7db0b33b8..0a2c0ed12 100644 --- a/hammer/config/defaults.yml +++ b/hammer/config/defaults.yml @@ -161,6 +161,7 @@ vlsi.inputs: # gds (str) - path to the GDS file # netlist (str) - path to the netlist file # sim_netlist (str) - Optional. If specified, this netlist is appended for hierarchical simulation + # sdcs (List(str)) - paths to the SDC file(s) needed for parent constraints mmmc_corners: [] # Multi-mode multi-corner setups, overrides supplies # MMMC struct members: diff --git a/hammer/par/innovus/__init__.py b/hammer/par/innovus/__init__.py index 8f227efed..a39422596 100644 --- a/hammer/par/innovus/__init__.py +++ b/hammer/par/innovus/__init__.py @@ -55,7 +55,8 @@ def fill_outputs(self) -> bool: lef=os.path.join(self.run_dir, "{top}ILM.lef".format(top=self.top_module)), gds=self.output_gds_filename, netlist=self.output_netlist_filename, - sim_netlist=self.output_sim_netlist_filename) + sim_netlist=self.output_sim_netlist_filename, + sdcs=self.output_ilm_sdcs) ] else: self.output_ilms = [] @@ -137,6 +138,17 @@ def output_spef_paths(self) -> List[str]: else: return [os.path.join(self.run_dir, "{top}.par.spef".format(top=self.top_module))] + @property + def output_ilm_sdcs(self) -> List[str]: + corners = self.get_mmmc_corners() + if corners: + filtered = list(filter(lambda c: c.type in [MMMCCornerType.Setup, MMMCCornerType.Hold], corners)) + ctype_map = {MMMCCornerType.Setup: "setup", MMMCCornerType.Hold: "hold"} + return list(map(lambda c: os.path.join(self.run_dir, "{top}_postRoute_{corner_name}.{corner_type}_view.core.sdc".format( + top=self.top_module, corner_name=c.name, corner_type=ctype_map[c.type])), filtered)) + else: + return [os.path.join(self.run_dir, "{top}_postRoute.core.sdc".format(top=self.top_module))] + @property def env_vars(self) -> Dict[str, str]: v = dict(super().env_vars) @@ -824,6 +836,10 @@ def write_ilm(self) -> bool: self.verbose_append("write_lef_abstract -5.8 {top}ILM.lef".format(top=self.top_module)) self.verbose_append("write_ilm -model_type all -to_dir {ilm_dir_name} -type_flex_ilm ilm".format( ilm_dir_name=self.ilm_dir_name)) + # Need to append -hierarchical after get_pins in SDCs for parent timing analysis + for sdc_out in self.output_ilm_sdcs: + self.append('gzip -d -c {ilm_dir_name}/mmmc/ilm_data/{top}/{sdc_in}.gz | sed "s/get_pins/get_pins -hierarchical/g" > {sdc_out}'.format( + ilm_dir_name=self.ilm_dir_name, top=self.top_module, sdc_in=os.path.basename(sdc_out), sdc_out=sdc_out)) self.ran_write_ilm = True return True diff --git a/hammer/par/mockpar/__init__.py b/hammer/par/mockpar/__init__.py index 952bdfa4b..d795f2876 100644 --- a/hammer/par/mockpar/__init__.py +++ b/hammer/par/mockpar/__init__.py @@ -87,12 +87,13 @@ def fill_outputs(self) -> bool: self.output_gds = "/dev/null" self.output_netlist = "/dev/null" self.output_sim_netlist = "/dev/null" + self.output_ilm_sdcs = ["/dev/null"] self.hcells_list = [] if self.hierarchical_mode in [HierarchicalMode.Leaf, HierarchicalMode.Hierarchical]: self.output_ilms = [ ILMStruct(dir="/dev/null", data_dir="/dev/null", module=self.top_module, lef="/dev/null", gds=self.output_gds, netlist=self.output_netlist, - sim_netlist=self.output_sim_netlist) + sim_netlist=self.output_sim_netlist, sdcs=self.output_ilm_sdcs) ] else: self.output_ilms = [] diff --git a/hammer/vlsi/constraints.py b/hammer/vlsi/constraints.py index dfb5fb49e..f7cd6d40b 100644 --- a/hammer/vlsi/constraints.py +++ b/hammer/vlsi/constraints.py @@ -25,7 +25,8 @@ class ILMStruct(NamedTuple('ILMStruct', [ ('lef', str), ('gds', str), ('netlist', str), - ('sim_netlist', Optional[str]) + ('sim_netlist', Optional[str]), + ('sdcs', List[str]) ])): __slots__ = () @@ -36,7 +37,8 @@ def to_setting(self) -> dict: "module": self.module, "lef": self.lef, "gds": self.gds, - "netlist": self.netlist + "netlist": self.netlist, + "sdcs": self.sdcs } if self.sim_netlist is not None: output.update({"sim_netlist": self.sim_netlist}) @@ -51,7 +53,8 @@ def from_setting(ilm: dict) -> "ILMStruct": lef=str(ilm["lef"]), gds=str(ilm["gds"]), netlist=str(ilm["netlist"]), - sim_netlist=ilm.get("sim_netlist") + sim_netlist=ilm.get("sim_netlist"), + sdcs=list(map(lambda x: str(x), ilm["sdcs"])) )