diff --git a/hammer/config/defaults.yml b/hammer/config/defaults.yml index 2623cbeb8..6b1b5cb9b 100644 --- a/hammer/config/defaults.yml +++ b/hammer/config/defaults.yml @@ -603,6 +603,10 @@ par: # Overrideable by appending _ # type: float + antenna_trim_shape: stripe # "none" or "stripe", specifies antenna trimming strategy + # Overrideable by appending _ + # type: str + pin_layers: [] # Layers to put power pins on # type: List[str] diff --git a/hammer/config/defaults_types.yml b/hammer/config/defaults_types.yml index a7fee135d..6928e8291 100644 --- a/hammer/config/defaults_types.yml +++ b/hammer/config/defaults_types.yml @@ -310,6 +310,10 @@ par: # type: int track_spacing: int + # Specifies antenna trimming strategy. none or stripe + # type: str + antenna_trim_shape: str + # Ratio of total routing tracks to dedicate to power straps, which is used to calculate set pitch # type: float power_utilization: float diff --git a/hammer/par/innovus/__init__.py b/hammer/par/innovus/__init__.py index d0e755f8a..0746d15d1 100644 --- a/hammer/par/innovus/__init__.py +++ b/hammer/par/innovus/__init__.py @@ -1125,7 +1125,7 @@ def specify_std_cell_power_straps(self, blockage_spacing: Decimal, bbox: Optiona results.append("add_stripes " + " ".join(options) + "\n") return results - def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool) -> List[str]: + def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool, antenna_trim_shape: str) -> List[str]: """ Generate a list of TCL commands that will create power straps on a given layer. This is a low-level, cad-tool-specific API. It is designed to be called by higher-level methods, so calling this directly is not recommended. @@ -1141,6 +1141,7 @@ def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, bloc :param bbox: The optional (2N)-point bounding box of the area to generate straps. By default the entire core area is used. :param nets: A list of power nets to create (e.g. ["VDD", "VSS"], ["VDDA", "VSS", "VDDB"], ... etc.). :param add_pins: True if pins are desired on this layer; False otherwise. + :param antenna_trim_shape: Strategy for trimming strap antennae. {none/stripe} :return: A list of TCL commands that will generate power straps. """ # TODO check that this has been not been called after a higher-level metal and error if so @@ -1149,6 +1150,7 @@ def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, bloc results.extend([ "set_db add_stripes_stacked_via_top_layer {}".format(layer_name), "set_db add_stripes_stacked_via_bottom_layer {}".format(bottom_via_layer_name), + "set_db add_stripes_trim_antenna_back_to_shape {{{}}}".format(antenna_trim_shape), "set_db add_stripes_spacing_from_block {}".format(blockage_spacing) ]) layer = self.get_stackup().get_metal(layer_name) diff --git a/hammer/par/mockpar/__init__.py b/hammer/par/mockpar/__init__.py index d795f2876..16419a512 100644 --- a/hammer/par/mockpar/__init__.py +++ b/hammer/par/mockpar/__init__.py @@ -50,7 +50,7 @@ def parse_mock_power_straps_file(self) -> List[Dict[str, Any]]: output.append(json.loads(line)) return output - def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool) -> List[str]: + def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool, antenna_trim_shape: str) -> List[str]: self._power_straps_check_index(layer_name) output_dict = { "layer_name": layer_name, @@ -62,7 +62,8 @@ def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, bloc "offset": str(offset), "bbox": [] if bbox is None else list(map(str, bbox)), "nets": list(map(str, nets)), - "add_pins": add_pins + "add_pins": add_pins, + "antenna_trim_shape": antenna_trim_shape } return [json.dumps(output_dict, cls=HammerJSONEncoder)] diff --git a/hammer/par/nop/__init__.py b/hammer/par/nop/__init__.py index d2f349c74..06116a851 100644 --- a/hammer/par/nop/__init__.py +++ b/hammer/par/nop/__init__.py @@ -17,7 +17,7 @@ def fill_outputs(self) -> bool: self.hcells_list = [] return True - def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool) -> List[str]: + def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool, antenna_trim_shape: str) -> List[str]: return [] def specify_std_cell_power_straps(self, blockage_spacing: Decimal, bbox: Optional[List[Decimal]], nets: List[str]) -> List[str]: diff --git a/hammer/par/openroad/__init__.py b/hammer/par/openroad/__init__.py index 9d63e2cdc..afd90b89c 100644 --- a/hammer/par/openroad/__init__.py +++ b/hammer/par/openroad/__init__.py @@ -1882,7 +1882,7 @@ def specify_std_cell_power_straps(self, blockage_spacing: Decimal, bbox: Optiona # -pitch {pitch} return tcl - def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool) -> List[str]: + def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool, antenna_trim_shape: str) -> List[str]: """ Generate a list of TCL commands that will create power straps on a given layer. This is a low-level, cad-tool-specific API. It is designed to be called by higher-level methods, so calling this directly is not recommended. @@ -1898,6 +1898,7 @@ def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, bloc :param bbox: The optional (2N)-point bounding box of the area to generate straps. By default the entire core area is used. :param nets: A list of power nets to create (e.g. ["VDD", "VSS"], ["VDDA", "VSS", "VDDB"], ... etc.). :param add_pins: True if pins are desired on this layer; False otherwise. + :param antenna_trim_shape: Strategy for trimming strap antennae. {none/stripe} :return: A list of TCL commands that will generate power straps. """ pdn_cfg = [f" {layer_name} {{width {width} pitch {pitch} offset {offset}}}"] diff --git a/hammer/vlsi/hammer_vlsi_impl.py b/hammer/vlsi/hammer_vlsi_impl.py index 9585b4678..3f8b40b12 100644 --- a/hammer/vlsi/hammer_vlsi_impl.py +++ b/hammer/vlsi/hammer_vlsi_impl.py @@ -659,7 +659,7 @@ def get_weight(s: Supply) -> int: raise NotImplementedError("Power strap generation method %s is not implemented" % method) - def specify_power_straps_by_tracks(self, layer_name: str, bottom_via_layer: str, blockage_spacing: Decimal, track_pitch: int, track_width: int, track_spacing: int, track_start: int, track_offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool, layer_is_all_power: bool) -> List[str]: + def specify_power_straps_by_tracks(self, layer_name: str, bottom_via_layer: str, blockage_spacing: Decimal, track_pitch: int, track_width: int, track_spacing: int, track_start: int, track_offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool, layer_is_all_power: bool, antenna_trim_shape: str) -> List[str]: """ Generate a list of TCL commands that will create power straps on a given layer by specifying the desired track consumption. This method assumes that power straps are built bottom-up, starting with standard cell rails. @@ -675,6 +675,7 @@ def specify_power_straps_by_tracks(self, layer_name: str, bottom_via_layer: str, :param nets: A list of power nets to create (e.g. ["VDD", "VSS"], ["VDDA", "VSS", "VDDB"], ... etc.). :param add_pins: True if pins are desired on this layer; False otherwise. :param layer_is_all_power: True if there will be no signal wires on this layer. + :param antenna_trim_shape: Strategy for trimming strap antennae. {none/stripe} :return: A list of TCL commands that will generate power straps. """ # Note: even track_widths will be snapped to a half-track @@ -702,7 +703,7 @@ def specify_power_straps_by_tracks(self, layer_name: str, bottom_via_layer: str, if density > Decimal(85): self.logger.warning("CAUTION! Your {layer} power strap density is {density}%. Check your technology's DRM to see if this violates maximum density rules.".format(layer=layer_name, density=density)) self._get_power_straps_for_hardmacros(layer_name, pitch, width, spacing, offset, bbox, nets) - return self.specify_power_straps(layer_name, bottom_via_layer, blockage_spacing, pitch, width, spacing, offset, bbox, nets, add_pins) + return self.specify_power_straps(layer_name, bottom_via_layer, blockage_spacing, pitch, width, spacing, offset, bbox, nets, add_pins, antenna_trim_shape) def specify_all_power_straps_by_tracks(self, layer_names: List[str], ground_net: str, power_nets: List[str], power_weights: List[int], bbox: Optional[List[Decimal]], pin_layers: List[str]) -> List[str]: """ @@ -752,6 +753,7 @@ def specify_all_power_straps_by_tracks(self, layer_names: List[str], ground_net: track_start = int(self._get_by_tracks_metal_setting("track_start", layer_name)) track_pitch = self._get_by_tracks_track_pitch(layer_name) track_offset = Decimal(str(self._get_by_tracks_metal_setting("track_offset", layer_name))) + antenna_trim_shape = self._get_by_tracks_metal_setting("antenna_trim_shape", layer_name) offset = layer.offset # TODO this is relaxable if we can auto-recalculate this based on hierarchical setting add_pins = layer_name in pin_layers @@ -767,7 +769,7 @@ def specify_all_power_straps_by_tracks(self, layer_names: List[str], ground_net: nets = [ground_net, power_nets[i]] group_offset = offset + track_offset + track_pitch * i * layer.pitch group_pitch = sum_weights * track_pitch - output.extend(self.specify_power_straps_by_tracks(layer_name, last.name, blockage_spacing, group_pitch, track_width, track_spacing, track_start, group_offset, bbox, nets, add_pins, layer_is_all_power)) + output.extend(self.specify_power_straps_by_tracks(layer_name, last.name, blockage_spacing, group_pitch, track_width, track_spacing, track_start, group_offset, bbox, nets, add_pins, layer_is_all_power, antenna_trim_shape)) last = layer self._dump_power_straps_for_hardmacros() @@ -1031,7 +1033,7 @@ def _get_by_tracks_track_pitch(self, layer_name: str) -> int: return round(consumed_tracks / power_utilization) @abstractmethod - def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool) -> List[str]: + def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool, antenna_trim_shape: str) -> List[str]: """ Generate a list of TCL commands that will create power straps on a given layer. This is a low-level, cad-tool-specific API. It is designed to be called by higher-level methods, so calling this directly is not recommended. @@ -1047,6 +1049,7 @@ def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, bloc :param bbox: The optional (2N)-point bounding box of the area to generate straps. By default the entire core area is used. :param nets: A list of power nets to create (e.g. ["VDD", "VSS"], ["VDDA", "VSS", "VDDB"], ... etc.). :param add_pins: True if pins are desired on this layer; False otherwise. + :param antenna_trim_shape: Strategy for trimming strap antennae. {none/stripe} :return: A list of TCL commands that will generate power straps. """ # This should get overriden but be sure to use this check in your implementations diff --git a/hammer/vlsi/vendor/openroad.py b/hammer/vlsi/vendor/openroad.py index 599453523..b61199dfe 100644 --- a/hammer/vlsi/vendor/openroad.py +++ b/hammer/vlsi/vendor/openroad.py @@ -251,7 +251,8 @@ def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], - add_pins: bool) -> List[str]: + add_pins: bool, + antenna_trim_shape: str) -> List[str]: # TODO: currently using openroad's powerstrap script return []