From f7e5f17828ae867a0ca4b78335f0d25f47d22abf Mon Sep 17 00:00:00 2001 From: Di Wang Date: Fri, 12 Jul 2024 17:11:43 -0700 Subject: [PATCH 1/4] bugfix: fixed floating metal in do_power_fill API --- src/bag/layout/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bag/layout/template.py b/src/bag/layout/template.py index 69b4a09..904a4aa 100755 --- a/src/bag/layout/template.py +++ b/src/bag/layout/template.py @@ -2782,7 +2782,7 @@ def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, cl, cu = bound_box.xl + fill_w2, bound_box.xh - fill_w2 lower, upper = bound_box.yl, bound_box.yh sep_margin = tr_manager.get_sep(layer_id, ('sup', '')) - tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER_EQ) + tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER) tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS_EQ) trs = self.get_available_tracks(layer_id, tid_lo=tr_bot, tid_hi=tr_top, lower=lower, upper=upper, width=fill_width, sep=fill_space, sep_margin=sep_margin, From 6f705db18b1b636523013aa88d31c99982e27f2d Mon Sep 17 00:00:00 2001 From: Di Wang Date: Fri, 12 Jul 2024 17:43:53 -0700 Subject: [PATCH 2/4] feat: added 'touch_edge' arguments for both do_power_fill and do_multi_power_fill --- src/bag/layout/template.py | 47 ++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/bag/layout/template.py b/src/bag/layout/template.py index 904a4aa..31f4838 100755 --- a/src/bag/layout/template.py +++ b/src/bag/layout/template.py @@ -2666,10 +2666,11 @@ def do_device_fill(self, fill_cls: Type[TemplateBase], **kwargs: Any) -> None: cnt += 1 def do_power_fill(self, layer_id: int, tr_manager: TrackManager, - vdd_warrs: Optional[Union[WireArray, List[WireArray]]] = None, + vdd_warrs: Optional[Union[WireArray, + List[WireArray]]] = None, vss_warrs: Optional[Union[WireArray, List[WireArray]]] = None, bound_box: Optional[BBox] = None, x_margin: int = 0, y_margin: int = 0, sup_type: str = 'both', flip: bool = False, - uniform_grid: bool = False) -> Tuple[List[WireArray], List[WireArray]]: + uniform_grid: bool = False, touch_edge: bool = True) -> Tuple[List[WireArray], List[WireArray]]: """Draw power fill on the given layer. Wrapper around do_multi_power_fill method that only returns the VDD and VSS wires. @@ -2695,6 +2696,8 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, draw power fill on a common grid instead of dense packing. flip : bool true to reverse order of power fill. Default (False) is {VDD, VSS}. + touch_edge : bool + true to allow power fill to touch the edge of the bounding box. false to keep a margin that's equal to the preset separate track width. Default is True. Returns ------- @@ -2703,9 +2706,11 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, """ # Value checks if sup_type.lower() not in ['vdd', 'vss', 'both']: - raise ValueError('sup_type has to be "VDD" or "VSS" or "both"(default)') + raise ValueError( + 'sup_type has to be "VDD" or "VSS" or "both"(default)') if not vdd_warrs and not vss_warrs: - raise ValueError('At least one of vdd_warrs or vss_warrs must be given.') + raise ValueError( + 'At least one of vdd_warrs or vss_warrs must be given.') # Build supply lists based on specficiation if sup_type.lower() == 'both' and vdd_warrs and vss_warrs: @@ -2715,15 +2720,17 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, elif sup_type.lower() == 'vdd' and vdd_warrs: top_lists = [vdd_warrs] else: - raise RuntimeError('Provided supply type and supply wires do not match.') + raise RuntimeError( + 'Provided supply type and supply wires do not match.') # Run the actual power fill using the multi_power_fill function ret_warrs = self.do_multi_power_fill(layer_id, tr_manager, top_lists, bound_box, - x_margin, y_margin, flip, uniform_grid) + x_margin, y_margin, flip, uniform_grid, touch_edge) # Reorganize return values if sup_type.lower() == 'both': - top_vdd, top_vss = (ret_warrs[0], ret_warrs[1]) if not flip else (ret_warrs[1], ret_warrs[0]) + top_vdd, top_vss = (ret_warrs[0], ret_warrs[1]) if not flip else ( + ret_warrs[1], ret_warrs[0]) elif sup_type.lower() == 'vss': top_vdd = [] top_vss = ret_warrs[0] @@ -2735,8 +2742,7 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, sup_list: List[Union[WireArray, List[WireArray]]], bound_box: Optional[BBox] = None, - x_margin: int = 0, y_margin: int = 0, flip: bool = False, uniform_grid: bool = False - ) -> List[List[WireArray]]: + x_margin: int = 0, y_margin: int = 0, flip: bool = False, uniform_grid: bool = False, touch_edge: bool = True) -> List[List[WireArray]]: """Draw power fill on the given layer. Accepts as many different supply nets as provided. Parameters @@ -2757,6 +2763,8 @@ def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, draw power fill on a common grid instead of dense packing. flip : bool true to reverse order of power fill. Default is False. + touch_edge : bool + true to allow power fill to touch the edge of the bounding box. false to keep a margin that's equal to the preset separate track width. Default is True. Returns ------- @@ -2782,18 +2790,29 @@ def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, cl, cu = bound_box.xl + fill_w2, bound_box.xh - fill_w2 lower, upper = bound_box.yl, bound_box.yh sep_margin = tr_manager.get_sep(layer_id, ('sup', '')) - tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER) - tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS_EQ) + if touch_edge: + tr_bot = self.grid.coord_to_track( + layer_id, cl, mode=RoundMode.GREATER_EQ) + tr_top = self.grid.coord_to_track( + layer_id, cu, mode=RoundMode.LESS_EQ) + else: + tr_bot = self.grid.coord_to_track( + layer_id, cl, mode=RoundMode.GREATER) + sep_margin + tr_top = self.grid.coord_to_track( + layer_id, cu, mode=RoundMode.LESS) - sep_margin trs = self.get_available_tracks(layer_id, tid_lo=tr_bot, tid_hi=tr_top, lower=lower, upper=upper, width=fill_width, sep=fill_space, sep_margin=sep_margin, uniform_grid=uniform_grid) all_warrs = [[] for _ in range(num_sups)] htr_sep = HalfInt.convert(fill_space).dbl_value if len(trs) < num_sups: - raise ValueError('Not enough available tracks to fill for all provided supplies') + raise ValueError( + 'Not enough available tracks to fill for all provided supplies') for ncur, tr_idx in enumerate(trs): - warr = self.add_wires(layer_id, tr_idx, lower, upper, width=fill_width) - _ncur = HalfInt.convert(tr_idx).dbl_value // htr_sep if uniform_grid else ncur + warr = self.add_wires(layer_id, tr_idx, lower, + upper, width=fill_width) + _ncur = HalfInt.convert( + tr_idx).dbl_value // htr_sep if uniform_grid else ncur if not flip: all_warrs[_ncur % num_sups].append(warr) else: From 4a295813416532d404fe446f596d3ad1f2d2642f Mon Sep 17 00:00:00 2001 From: Di Wang Date: Fri, 12 Jul 2024 17:55:38 -0700 Subject: [PATCH 3/4] feat: added 'touch_edge' arguments for both do_power_fill and do_multi_power_fill --- src/bag/layout/template.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/bag/layout/template.py b/src/bag/layout/template.py index 69b4a09..d38abc1 100755 --- a/src/bag/layout/template.py +++ b/src/bag/layout/template.py @@ -2669,7 +2669,7 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, vdd_warrs: Optional[Union[WireArray, List[WireArray]]] = None, vss_warrs: Optional[Union[WireArray, List[WireArray]]] = None, bound_box: Optional[BBox] = None, x_margin: int = 0, y_margin: int = 0, sup_type: str = 'both', flip: bool = False, - uniform_grid: bool = False) -> Tuple[List[WireArray], List[WireArray]]: + uniform_grid: bool = False, touch_edge: bool = True) -> Tuple[List[WireArray], List[WireArray]]: """Draw power fill on the given layer. Wrapper around do_multi_power_fill method that only returns the VDD and VSS wires. @@ -2695,6 +2695,8 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, draw power fill on a common grid instead of dense packing. flip : bool true to reverse order of power fill. Default (False) is {VDD, VSS}. + touch_edge : bool + true to draw power fill to the edge of the bounding box. false to keep a margin of the preset value of track space width. Default is True. Returns ------- @@ -2719,7 +2721,7 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, # Run the actual power fill using the multi_power_fill function ret_warrs = self.do_multi_power_fill(layer_id, tr_manager, top_lists, bound_box, - x_margin, y_margin, flip, uniform_grid) + x_margin, y_margin, flip, uniform_grid, touch_edge) # Reorganize return values if sup_type.lower() == 'both': @@ -2736,7 +2738,7 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, sup_list: List[Union[WireArray, List[WireArray]]], bound_box: Optional[BBox] = None, x_margin: int = 0, y_margin: int = 0, flip: bool = False, uniform_grid: bool = False - ) -> List[List[WireArray]]: + , touch_edge: bool = True) -> List[List[WireArray]]: """Draw power fill on the given layer. Accepts as many different supply nets as provided. Parameters @@ -2757,6 +2759,8 @@ def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, draw power fill on a common grid instead of dense packing. flip : bool true to reverse order of power fill. Default is False. + touch_edge : bool + true to draw power fill to the edge of the bounding box. false to keep a margin of the preset value of track space width. Default is True. Returns ------- @@ -2782,8 +2786,12 @@ def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, cl, cu = bound_box.xl + fill_w2, bound_box.xh - fill_w2 lower, upper = bound_box.yl, bound_box.yh sep_margin = tr_manager.get_sep(layer_id, ('sup', '')) - tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER_EQ) - tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS_EQ) + if touch_edge: + tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER_EQ) + tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS_EQ) + else: + tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER) + sep_margin + tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS_EQ) - sep_margin trs = self.get_available_tracks(layer_id, tid_lo=tr_bot, tid_hi=tr_top, lower=lower, upper=upper, width=fill_width, sep=fill_space, sep_margin=sep_margin, uniform_grid=uniform_grid) From 3f0c91f8b47831e5b95ddf0f4c52e2bedf65c8e3 Mon Sep 17 00:00:00 2001 From: Di Wang Date: Fri, 26 Jul 2024 15:23:50 -0700 Subject: [PATCH 4/4] style: removed linebreak added by formatter, renamed touch_edge and modified top/bottom tracks --- src/bag/layout/template.py | 43 +++++++++++++++----------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/bag/layout/template.py b/src/bag/layout/template.py index 61e8e1f..72fbdb2 100755 --- a/src/bag/layout/template.py +++ b/src/bag/layout/template.py @@ -2666,11 +2666,10 @@ def do_device_fill(self, fill_cls: Type[TemplateBase], **kwargs: Any) -> None: cnt += 1 def do_power_fill(self, layer_id: int, tr_manager: TrackManager, - vdd_warrs: Optional[Union[WireArray, - List[WireArray]]] = None, + vdd_warrs: Optional[Union[WireArray, List[WireArray]]] = None, vss_warrs: Optional[Union[WireArray, List[WireArray]]] = None, bound_box: Optional[BBox] = None, x_margin: int = 0, y_margin: int = 0, sup_type: str = 'both', flip: bool = False, - uniform_grid: bool = False, touch_edge: bool = True) -> Tuple[List[WireArray], List[WireArray]]: + uniform_grid: bool = False, draw_on_edge: bool = True) -> Tuple[List[WireArray], List[WireArray]]: """Draw power fill on the given layer. Wrapper around do_multi_power_fill method that only returns the VDD and VSS wires. @@ -2696,7 +2695,7 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, draw power fill on a common grid instead of dense packing. flip : bool true to reverse order of power fill. Default (False) is {VDD, VSS}. - touch_edge : bool + draw_on_edge : bool true to draw power fill to the edge of the bounding box. false to keep a margin of the preset value of track space width. Default is True. Returns @@ -2706,11 +2705,9 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, """ # Value checks if sup_type.lower() not in ['vdd', 'vss', 'both']: - raise ValueError( - 'sup_type has to be "VDD" or "VSS" or "both"(default)') + raise ValueError('sup_type has to be "VDD" or "VSS" or "both"(default)') if not vdd_warrs and not vss_warrs: - raise ValueError( - 'At least one of vdd_warrs or vss_warrs must be given.') + raise ValueError('At least one of vdd_warrs or vss_warrs must be given.') # Build supply lists based on specficiation if sup_type.lower() == 'both' and vdd_warrs and vss_warrs: @@ -2720,17 +2717,14 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, elif sup_type.lower() == 'vdd' and vdd_warrs: top_lists = [vdd_warrs] else: - raise RuntimeError( - 'Provided supply type and supply wires do not match.') + raise RuntimeError('Provided supply type and supply wires do not match.') # Run the actual power fill using the multi_power_fill function - ret_warrs = self.do_multi_power_fill(layer_id, tr_manager, top_lists, bound_box, - x_margin, y_margin, flip, uniform_grid, touch_edge) + ret_warrs = self.do_multi_power_fill(layer_id, tr_manager, top_lists, bound_box, x_margin, y_margin, flip, uniform_grid, draw_on_edge) # Reorganize return values - if sup_type.lower() == 'both': - top_vdd, top_vss = (ret_warrs[0], ret_warrs[1]) if not flip else ( - ret_warrs[1], ret_warrs[0]) + if sup_type.lower() == 'both': + top_vdd, top_vss = (ret_warrs[0], ret_warrs[1]) if not flip else (ret_warrs[1], ret_warrs[0]) elif sup_type.lower() == 'vss': top_vdd = [] top_vss = ret_warrs[0] @@ -2743,7 +2737,7 @@ def do_power_fill(self, layer_id: int, tr_manager: TrackManager, def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, sup_list: List[Union[WireArray, List[WireArray]]], bound_box: Optional[BBox] = None, x_margin: int = 0, y_margin: int = 0, flip: bool = False, uniform_grid: bool = False - , touch_edge: bool = True) -> List[List[WireArray]]: + , draw_on_edge: bool = True) -> List[List[WireArray]]: """Draw power fill on the given layer. Accepts as many different supply nets as provided. Parameters @@ -2764,7 +2758,7 @@ def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, draw power fill on a common grid instead of dense packing. flip : bool true to reverse order of power fill. Default is False. - touch_edge : bool + draw_on_edge : bool true to draw power fill to the edge of the bounding box. false to keep a margin of the preset value of track space width. Default is True. Returns @@ -2791,25 +2785,22 @@ def do_multi_power_fill(self, layer_id: int, tr_manager: TrackManager, cl, cu = bound_box.xl + fill_w2, bound_box.xh - fill_w2 lower, upper = bound_box.yl, bound_box.yh sep_margin = tr_manager.get_sep(layer_id, ('sup', '')) - if touch_edge: + if draw_on_edge: tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER_EQ) tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS_EQ) else: - tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER) + sep_margin - tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS_EQ) - sep_margin + tr_bot = self.grid.coord_to_track(layer_id, cl, mode=RoundMode.GREATER) + sep_margin // 2 + tr_top = self.grid.coord_to_track(layer_id, cu, mode=RoundMode.LESS) - sep_margin // 2 trs = self.get_available_tracks(layer_id, tid_lo=tr_bot, tid_hi=tr_top, lower=lower, upper=upper, width=fill_width, sep=fill_space, sep_margin=sep_margin, uniform_grid=uniform_grid) all_warrs = [[] for _ in range(num_sups)] htr_sep = HalfInt.convert(fill_space).dbl_value if len(trs) < num_sups: - raise ValueError( - 'Not enough available tracks to fill for all provided supplies') + raise ValueError('Not enough available tracks to fill for all provided supplies') for ncur, tr_idx in enumerate(trs): - warr = self.add_wires(layer_id, tr_idx, lower, - upper, width=fill_width) - _ncur = HalfInt.convert( - tr_idx).dbl_value // htr_sep if uniform_grid else ncur + warr = self.add_wires(layer_id, tr_idx, lower, upper, width=fill_width) + _ncur = HalfInt.convert(tr_idx).dbl_value // htr_sep if uniform_grid else ncur if not flip: all_warrs[_ncur % num_sups].append(warr) else: