From 5024a2530e3c6a1e556db5930b1f640e9ef4d749 Mon Sep 17 00:00:00 2001 From: Harrison Liew Date: Tue, 26 Sep 2023 14:55:04 -0700 Subject: [PATCH 1/7] updates for DDI221 --- hammer/par/innovus/__init__.py | 2 ++ hammer/par/innovus/defaults.yml | 10 ++++------ hammer/synthesis/genus/__init__.py | 14 ++++++-------- hammer/synthesis/genus/defaults.yml | 6 +++--- hammer/vlsi/hammer_vlsi_impl.py | 4 ++-- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/hammer/par/innovus/__init__.py b/hammer/par/innovus/__init__.py index a39422596..65ae282c5 100644 --- a/hammer/par/innovus/__init__.py +++ b/hammer/par/innovus/__init__.py @@ -153,6 +153,8 @@ def output_ilm_sdcs(self) -> List[str]: def env_vars(self) -> Dict[str, str]: v = dict(super().env_vars) v["INNOVUS_BIN"] = self.get_setting("par.innovus.innovus_bin") + if self.version() >= self.version_number("221"): # support critical region resynthesis with DDI + v["PATH"] = f'{os.environ.copy()["PATH"]}:{os.path.dirname(self.get_setting("par.innovus.innovus_bin").replace("INNOVUS", "GENUS"))}' return v @property diff --git a/hammer/par/innovus/defaults.yml b/hammer/par/innovus/defaults.yml index 5ab660c51..178ad9081 100644 --- a/hammer/par/innovus/defaults.yml +++ b/hammer/par/innovus/defaults.yml @@ -3,18 +3,16 @@ par.innovus: # Location of the binary. - innovus_bin: "${cadence.cadence_home}/INNOVUS/INNOVUS${par.innovus.version}/bin/innovus" + innovus_bin: "${cadence.cadence_home}/DDI/DDI${par.innovus.version}/INNOVUS${par.innovus.version}/bin/innovus" innovus_bin_meta: lazysubst # we want later overrides to be able to affect this # Innovus version to use. - # Used to locate the binary - e.g. the '171' in ${cadence.cadence_home}/INNOVUS/INNOVUS171/bin/innovus - # 171_ISR3 supports ILMs properly in contrast to 171. - version: "171_ISR3" + # Used to locate the binary - e.g. the '221' in ${cadence.cadence_home}/DDI/DDI221/INNOVUS2211/bin/innovus + version: "221" # Design flow effort. # Valid options: express (fastest), standard, and extreme (slowest). - # Default: express to increase turnaround speed. - design_flow_effort: "express" + design_flow_effort: "standard" # Floorplanning SDC constraints to use. # Valid options are: diff --git a/hammer/synthesis/genus/__init__.py b/hammer/synthesis/genus/__init__.py index 6b14d594e..b4cf0acf0 100644 --- a/hammer/synthesis/genus/__init__.py +++ b/hammer/synthesis/genus/__init__.py @@ -106,11 +106,7 @@ def do_pre_steps(self, first_step: HammerToolStep) -> bool: def do_between_steps(self, prev: HammerToolStep, next: HammerToolStep) -> bool: assert super().do_between_steps(prev, next) # Write a checkpoint to disk. - if self.version() >= self.version_number("221"): - # -common now enables database reading in Innovus - self.verbose_append("write_db -common -to_file pre_{step}".format(step=next.name)) - else: - self.verbose_append("write_db -to_file pre_{step}".format(step=next.name)) + self.verbose_append("write_db -to_file pre_{step}".format(step=next.name)) return True def do_post_steps(self) -> bool: @@ -198,10 +194,9 @@ def init_environment(self) -> bool: # Clock gating setup if self.get_setting("synthesis.clock_gating_mode") == "auto": verbose_append("set_db lp_clock_gating_infer_enable true") - # Innovus will create instances named CLKGATE_foo, CLKGATE_bar, etc. + # Genus will create instances named CLKGATE_foo, CLKGATE_bar, etc. verbose_append("set_db lp_clock_gating_prefix {CLKGATE}") verbose_append("set_db lp_insert_clock_gating true") - verbose_append("set_db lp_insert_clock_gating_incremental true") verbose_append("set_db lp_clock_gating_register_aware true") # Set up libraries. @@ -348,7 +343,10 @@ def write_outputs(self) -> bool: verbose_append("write_hdl > {}".format(self.mapped_v_path)) if self.hierarchical_mode.is_nonleaf_hierarchical() and self.version() >= self.version_number("191"): verbose_append("write_hdl -exclude_ilm > {}".format(self.mapped_hier_v_path)) - verbose_append("write_script > {}.mapped.scr".format(top)) + if self.version() >= self.version_number("221"): + verbose_append("write_template -full -outfile {}.mapped.scr".format(top)) + else: + verbose_append("write_script > {}.mapped.scr".format(top)) corners = self.get_mmmc_corners() if corners: # First setup corner is default view diff --git a/hammer/synthesis/genus/defaults.yml b/hammer/synthesis/genus/defaults.yml index 710bda9f6..a8c79b846 100644 --- a/hammer/synthesis/genus/defaults.yml +++ b/hammer/synthesis/genus/defaults.yml @@ -1,12 +1,12 @@ # Default settings for synthesis in Genus, for project/technology configuration and overriding. synthesis.genus: # Location of the binary. - genus_bin: "${cadence.cadence_home}/GENUS/GENUS${synthesis.genus.version}/bin/genus" + genus_bin: "${cadence.cadence_home}/DDI/DDI${synthesis.genus.version}/GENUS${synthesis.genus.version}/bin/genus" genus_bin_meta: lazysubst # we want later overrides to be able to affect this # Genus version to use. - # Used to locate the binary - e.g. the '171' in ${cadence.cadence_home}/GENUS/GENUS171/bin/genus - version: "171" + # Used to locate the binary - e.g. the '221' in ${cadence.cadence_home}/DDI/DDI221/GENUS221/bin/genus + version: "221" # Generate the TCL file but do not run it yet. generate_only: false diff --git a/hammer/vlsi/hammer_vlsi_impl.py b/hammer/vlsi/hammer_vlsi_impl.py index 490a75f93..e2e001916 100644 --- a/hammer/vlsi/hammer_vlsi_impl.py +++ b/hammer/vlsi/hammer_vlsi_impl.py @@ -2179,14 +2179,14 @@ def sdc_pin_constraints(self) -> str: # Also specify loads for specific pins. for load in self.get_output_load_constraints(): - output.append("set_load {load} [get_port \"{name}\"]".format( + output.append("set_load {load} [get_port {name}]".format( load=load.load, name=load.name )) # Also specify delays for specific pins. for delay in self.get_delay_constraints(): - output.append("set_{direction}_delay {delay} -clock {clock} [get_port \"{name}\"]".format( + output.append("set_{direction}_delay {delay} -clock {clock} [get_port {name}]".format( delay=delay.delay.value_in_units(self.get_time_unit().value_prefix + self.get_time_unit().unit), clock=delay.clock, direction=delay.direction, From 5200643393eeb68c549724083bd73c380358670f Mon Sep 17 00:00:00 2001 From: Harrison Liew Date: Tue, 26 Sep 2023 17:50:36 -0700 Subject: [PATCH 2/7] output load units should be CapacitanceValue --- hammer/config/defaults.yml | 8 ++++---- hammer/config/defaults_types.yml | 2 +- hammer/vlsi/hammer_vlsi_impl.py | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/hammer/config/defaults.yml b/hammer/config/defaults.yml index 0a2c0ed12..60c5deb78 100644 --- a/hammer/config/defaults.yml +++ b/hammer/config/defaults.yml @@ -150,7 +150,7 @@ vlsi.inputs: constraints: [] # Manual hierarchical constraints. Overrides generic constraints on a per module basis. # Should be a list along the lines of [{"module1": }]. - # For example [{"mod1": [vlsi.inputs.default_output_load: 2], "mod2": [vlsi.inputs.clocks:] }]. + # For example [{"mod1": [vlsi.inputs.default_output_load: "2 pF"], "mod2": [vlsi.inputs.clocks:] }]. ilms: [] # ILMs for hierarchical mode. # ILM struct (ILMStruct) members: @@ -188,13 +188,13 @@ vlsi.inputs: # group (str) - Optional. The name of the clock group this clock belongs to. Clocks in the same group will not be marked as asynchronous. # Clocks with no group specified will all be placed in separate groups and thus marked as asynchronous to each other and all other groups. - default_output_load: 1 # Default output pin load capacitance. - # Default: 1pF + default_output_load: "1 pF" # Default output pin load capacitance. + # type: CapacitanceValue output_loads: [] # List of output load constraints. # Each item in the list should be a struct with the following members: # name (str) - Name of the output load (e.g. io_out) - # load (float) - Output load capacitance in pF. + # load (CapacitanceValue) - Output load capacitance (e.g. "1 pF"). delays: [] # List of delay constraints. # These either constrain inputs to arrive after a certain delay relative diff --git a/hammer/config/defaults_types.yml b/hammer/config/defaults_types.yml index 0f2e76dd0..a7fee135d 100644 --- a/hammer/config/defaults_types.yml +++ b/hammer/config/defaults_types.yml @@ -117,7 +117,7 @@ vlsi.inputs: clocks: list[dict[str, Any]] # Default output pin load capacitance. - default_output_load: int + default_output_load: str # List of output load constraints. output_loads: list[dict[str, str]] diff --git a/hammer/vlsi/hammer_vlsi_impl.py b/hammer/vlsi/hammer_vlsi_impl.py index e2e001916..d32387eac 100644 --- a/hammer/vlsi/hammer_vlsi_impl.py +++ b/hammer/vlsi/hammer_vlsi_impl.py @@ -2170,7 +2170,9 @@ def sdc_pin_constraints(self) -> str: """Generate a fragment for I/O pin constraints.""" output = [] # type: List[str] - default_output_load = float(self.get_setting("vlsi.inputs.default_output_load")) + output.append("set_units -capacitance fF") + + default_output_load = CapacitanceValue(self.get_setting("vlsi.inputs.default_output_load")).value_in_units("fF", round_zeroes = True) # Specify default load. output.append("set_load {load} [all_outputs]".format( @@ -2180,7 +2182,7 @@ def sdc_pin_constraints(self) -> str: # Also specify loads for specific pins. for load in self.get_output_load_constraints(): output.append("set_load {load} [get_port {name}]".format( - load=load.load, + load=CapacitanceValue(load.load).value_in_units("fF", round_zeroes = True), name=load.name )) From a4234700d9798c0d87fcb577b90a15ad05e6f4b5 Mon Sep 17 00:00:00 2001 From: Harrison Liew Date: Tue, 26 Sep 2023 17:54:41 -0700 Subject: [PATCH 3/7] also OutputLoadConstraint --- hammer/vlsi/constraints.py | 2 +- hammer/vlsi/hammer_tool.py | 2 +- hammer/vlsi/hammer_vlsi_impl.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hammer/vlsi/constraints.py b/hammer/vlsi/constraints.py index f7cd6d40b..562fbc016 100644 --- a/hammer/vlsi/constraints.py +++ b/hammer/vlsi/constraints.py @@ -380,7 +380,7 @@ def name_bump(self, definition: BumpsDefinition, assignment: BumpAssignment) -> OutputLoadConstraint = NamedTuple('OutputLoadConstraint', [ ('name', str), - ('load', float) + ('load', CapacitanceValue) ]) diff --git a/hammer/vlsi/hammer_tool.py b/hammer/vlsi/hammer_tool.py index 532e08702..8274a9b66 100644 --- a/hammer/vlsi/hammer_tool.py +++ b/hammer/vlsi/hammer_tool.py @@ -1558,7 +1558,7 @@ def get_output_load_constraints(self) -> List[OutputLoadConstraint]: for load_src in output_loads: load = OutputLoadConstraint( name=str(load_src["name"]), - load=float(load_src["load"]) + load=CapacitanceValue(load_src["load"]) ) output.append(load) return output diff --git a/hammer/vlsi/hammer_vlsi_impl.py b/hammer/vlsi/hammer_vlsi_impl.py index d32387eac..1ebd4f757 100644 --- a/hammer/vlsi/hammer_vlsi_impl.py +++ b/hammer/vlsi/hammer_vlsi_impl.py @@ -2182,7 +2182,7 @@ def sdc_pin_constraints(self) -> str: # Also specify loads for specific pins. for load in self.get_output_load_constraints(): output.append("set_load {load} [get_port {name}]".format( - load=CapacitanceValue(load.load).value_in_units("fF", round_zeroes = True), + load=load.load.value_in_units("fF", round_zeroes = True), name=load.name )) From 52d95ba823f68347e3ab1bb7b613c4d55820439c Mon Sep 17 00:00:00 2001 From: Harrison Liew Date: Thu, 28 Sep 2023 10:30:34 -0700 Subject: [PATCH 4/7] enable clock mapping flow by adding more special cells --- hammer/par/innovus/__init__.py | 15 ++++++++++++++- hammer/synthesis/genus/__init__.py | 16 ++++++++++++++++ hammer/tech/specialcells.py | 3 +++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/hammer/par/innovus/__init__.py b/hammer/par/innovus/__init__.py index 65ae282c5..90114a378 100644 --- a/hammer/par/innovus/__init__.py +++ b/hammer/par/innovus/__init__.py @@ -364,7 +364,7 @@ def place_bumps(self) -> bool: # TODO: Fix this once the stackup supports vias ucb-bar/hammer#354 block_layer = self.get_setting("vlsi.technology.bump_block_cut_layer") # type: str for bump in bumps.assignments: - self.append("create_bump -cell {cell} -location_type cell_center -name_format \"Bump_{c}.{r}\" -orient r0 -location \"{x} {y}\"".format( + self.append("create_bump -allow_overlap_control keep_all -cell {cell} -location_type cell_center -name_format \"Bump_{c}.{r}\" -orient r0 -location \"{x} {y}\"".format( cell = bump.custom_cell if bump.custom_cell is not None else bumps.cell, c = bump.x, r = bump.y, @@ -525,6 +525,19 @@ def clock_tree(self) -> bool: '''.format(sdc=self.post_synth_sdc), clean=True) if len(self.get_clock_ports()) > 0: # Ignore clock tree when there are no clocks + # If special cells are specified, explicitly set them instead of letting tool infer from libs + buffers = self.technology.get_special_cell_by_type(CellType.CTSBuffer)[0].name + if len(buffers) > 0: + self.append(f"set_db cts_buffer_cells {{{' '.join(buffers)}}}") + inverters = self.technology.get_special_cell_by_type(CellType.CTSInverter)[0].name + if len(inverters) > 0: + self.append(f"set_db cts_inverter_cells {{{' '.join(inverters)}}}") + gates = self.technology.get_special_cell_by_type(CellType.CTSGate)[0].name + if len(gates) > 0: + self.append(f"set_db cts_clock_gating_cells {{{' '.join(gates)}}}") + logics = self.technology.get_special_cell_by_type(CellType.CTSLogic)[0].name + if len(logics) > 0: + self.append(f"set_db cts_logic_cells {{{' '.join(logics)}}}") self.verbose_append("create_clock_tree_spec") if bool(self.get_setting("par.innovus.use_cco")): # -hold is a secret flag for ccopt_design (undocumented anywhere) diff --git a/hammer/synthesis/genus/__init__.py b/hammer/synthesis/genus/__init__.py index b4cf0acf0..54efa6062 100644 --- a/hammer/synthesis/genus/__init__.py +++ b/hammer/synthesis/genus/__init__.py @@ -282,6 +282,22 @@ def retime_modules(self) -> bool: return True def syn_generic(self) -> bool: + # Add clock mapping flow if special cells are specified + if self.version() >= self.version_number("2111"): + buffers = self.technology.get_special_cell_by_type(CellType.CTSBuffer)[0].name + if len(buffers) > 0: + self.append(f"set_db cts_buffer_cells {{{' '.join(buffers)}}}") + inverters = self.technology.get_special_cell_by_type(CellType.CTSInverter)[0].name + if len(inverters) > 0: + self.append(f"set_db cts_inverter_cells {{{' '.join(inverters)}}}") + gates = self.technology.get_special_cell_by_type(CellType.CTSGate)[0].name + if len(gates) > 0: + self.append(f"set_db cts_clock_gating_cells {{{' '.join(gates)}}}") + logics = self.technology.get_special_cell_by_type(CellType.CTSLogic)[0].name + if len(logics) > 0: + self.append(f"set_db cts_logic_cells {{{' '.join(logics)}}}") + if any(c > 0 for c in [len(buffers), len(inverters), len(gates), len(logics)]): + self.append("set_db map_clock_tree true") self.verbose_append("syn_generic") return True diff --git a/hammer/tech/specialcells.py b/hammer/tech/specialcells.py index 6c566300d..0168fb6e7 100644 --- a/hammer/tech/specialcells.py +++ b/hammer/tech/specialcells.py @@ -19,6 +19,9 @@ class CellType(str, Enum): TapCell = "tapcell" Driver = "driver" CTSBuffer = "ctsbuffer" + CTSInverter = "ctsinverter" + CTSGate = "ctsgate" + CTSLogic = "ctslogic" class SpecialCell(BaseModel): From f24f83b36c76a87368dbe0ab2d299390c6d1851a Mon Sep 17 00:00:00 2001 From: kenhoberkeley <89747404+kenhoberkeley@users.noreply.github.com> Date: Thu, 28 Sep 2023 10:54:11 -0700 Subject: [PATCH 5/7] Update __init__.py Perhaps 211 not 2111? --- hammer/synthesis/genus/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hammer/synthesis/genus/__init__.py b/hammer/synthesis/genus/__init__.py index 54efa6062..ee0cfd0ac 100644 --- a/hammer/synthesis/genus/__init__.py +++ b/hammer/synthesis/genus/__init__.py @@ -283,7 +283,7 @@ def retime_modules(self) -> bool: def syn_generic(self) -> bool: # Add clock mapping flow if special cells are specified - if self.version() >= self.version_number("2111"): + if self.version() >= self.version_number("211"): buffers = self.technology.get_special_cell_by_type(CellType.CTSBuffer)[0].name if len(buffers) > 0: self.append(f"set_db cts_buffer_cells {{{' '.join(buffers)}}}") From 4f122c83bafad354bb436c3acffa9f4017a70a27 Mon Sep 17 00:00:00 2001 From: Harrison Liew Date: Thu, 28 Sep 2023 10:56:16 -0700 Subject: [PATCH 6/7] make special cell types in docs point to schema compilation output --- doc/Technology/Tech-json.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Technology/Tech-json.rst b/doc/Technology/Tech-json.rst index 8f3f38b5d..ae7b69291 100644 --- a/doc/Technology/Tech-json.rst +++ b/doc/Technology/Tech-json.rst @@ -151,7 +151,7 @@ The example below shows a subset of the ASAP7 tech plugin for 2 types of cells: {"cell_type": "tapcell", "name": ["TAPCELL_ASAP7_75t_L"]}, {"cell_type": "stdfiller", "name": ["FILLER_ASAP7_75t_R", "FILLER_ASAP7_75t_L", "FILLER_ASAP7_75t_SL", "FILLER_ASAP7_75t_SRAM", "FILLERxp5_ASAP7_75t_R", "FILLERxp5_ASAP7_75t_L", "FILLERxp5_ASAP7_75t_SL", "FILLERxp5_ASAP7_75t_SRAM"]}, -There are 8 ``cell_type`` s supported: ``tiehicell``, ``tielocell``, ``tiehilocell``, ``endcap``, ``iofiller``, ``stdfiller``, ``decap``, and ``tapcell``. Depending on the tech/tool, some of these cell types can only have 1 cell in the ``name`` list. +See the ``SpecialCell`` subsection in the :ref:`full_schema` for a list of special cell types. Depending on the tech/tool, some of these cell types can only have 1 cell in the ``name`` list. There is an optional ``size`` list. For each element in its corresponding ``name`` list, a size (type: str) can be given. An example of how this is used is for ``decap`` cells, where each listed cell has a typical capacitance, which a place and route tool can then use to place decaps to hit a target total decapacitance value. After characterizing the ASAP7 decaps using Voltus, the nominal capacitance is filled into the ``size`` list: From 92a9cbb080ab1d6aed3f379ee014f7e746b04b93 Mon Sep 17 00:00:00 2001 From: ken_ho Date: Thu, 28 Sep 2023 11:52:19 -0700 Subject: [PATCH 7/7] bring in design power key --- hammer/par/innovus/__init__.py | 3 ++- hammer/par/innovus/defaults.yml | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hammer/par/innovus/__init__.py b/hammer/par/innovus/__init__.py index 90114a378..24c59ccad 100644 --- a/hammer/par/innovus/__init__.py +++ b/hammer/par/innovus/__init__.py @@ -329,7 +329,8 @@ def init_design(self) -> bool: verbose_append(f"set_db route_design_top_layer {layers[1]}") # Set design effort. - verbose_append("set_db design_flow_effort {}".format(self.get_setting("par.innovus.design_flow_effort"))) + verbose_append(f"set_db design_flow_effort {self.get_setting('par.innovus.design_flow_effort')}") + verbose_append(f"set_db design_power_effort {self.get_setting('par.innovus.design_power_effort')}") # Set "don't use" cells. for l in self.generate_dont_use_commands(): diff --git a/hammer/par/innovus/defaults.yml b/hammer/par/innovus/defaults.yml index 178ad9081..a72d19cf3 100644 --- a/hammer/par/innovus/defaults.yml +++ b/hammer/par/innovus/defaults.yml @@ -14,6 +14,10 @@ par.innovus: # Valid options: express (fastest), standard, and extreme (slowest). design_flow_effort: "standard" + # Design power effort. + # Valid options: none, low, high. + design_power_effort: "low" + # Floorplanning SDC constraints to use. # Valid options are: # - blank - Specify no floorplanning constraints (likely won't work)