Skip to content

Commit

Permalink
feat!: allow PDKs without diode, antenna, and/or decap cells (#662)
Browse files Browse the repository at this point in the history
Some PDKs have self-tapping standard cells, do not suffer from the
antenna effect, have no endcap cell, or a combination of those.

This patch makes the variables options and modifies included steps to no
longer assume their existence.
  • Loading branch information
donn authored Feb 13, 2025
1 parent 7e30ca1 commit 21f8e1e
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 53 deletions.
19 changes: 17 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
* `PDN_OBSTRUCTIONS` and `ROUTING_OBSTRUCTIONS` are now lists of tuples
instead of variable-length Tcl-style lists (AKA: strings).

* `Odb.DiodesOnPorts`, `Odb.PortDiodePlacement`, `Odb.FuzzyDiodePlacement`,
`Odb.HeuristicDiodeInsertion`

* Steps no longer assume `DIODE_CELL` exists and fall back to doing nothing.

* `OpenROAD.*`

* Added `PNR_CORNERS`. An override for `DEFAULT_CORNER` for PnR steps except
Expand Down Expand Up @@ -66,8 +71,8 @@
* Added `DRT_SAVE_SNAPSHOTS` which enables saving snapshots of the layout each
detalied routing iteration.
* Added `DRT_SAVE_DRC_REPORT_ITERS`
* Added `DRT_ANTENNA_REPAIR_ITERS`, which if greater than zero, enables
antenna fixing after detailed routing
* Added `DRT_ANTENNA_REPAIR_ITERS`, which, if greater than zero and
`DIODE_CELL` is set, enables antenna fixing after detailed routing
* Added `DRT_ANTENNA_MARGIN` which is similar to `GRT_ANTENNA_MARGIN` but for
the aforementioned antenna repair iterations
* DRC reports are now converted to `xml` and readable by KLayout
Expand All @@ -84,6 +89,10 @@

* Corrected `GPL_CELL_PADDING` to be an integer.

* `OpenROAD.RepairAntennas`

* Step no longer assumes `DIODE_CELL` exists and falls back to doing nothing.

* `OpenROAD.RepairDesignPostGPL`

* Added optional variable `DESIGN_REPAIR_MAX_UTIL_PCT`
Expand Down Expand Up @@ -118,6 +127,11 @@
* `GRT_RESIZER_HOLD_REPAIR_TNS_PCT`
* `GRT_RESIZER_HOLD_MAX_UTIL_PCT`

* `OpenROAD.TapDecapInsertion`

* No longer assumes `WELLTAP_CELL` has a value and skips tap insertion if not.
* No longer assumes `DECAP_CELL` has a value and skips decap insertion if not.

* Created `OpenROAD.UnplaceAll`

* Removes the placement status of all instances.
Expand Down Expand Up @@ -211,6 +225,7 @@

* `{GPL,DPL}_CELL_PADDING`, `PL_MAX_DISPLACEMENT_{X,Y}` now all integers to
match OpenROAD.
* `WELLTAP_CELL`, `DECAP_CELL` now optional.

* `Checker.HoldViolations`

Expand Down
30 changes: 15 additions & 15 deletions openlane/config/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,20 +304,6 @@ def _prefix_to_wildcard(prefixes_raw: Union[str, Sequence[str]]):
"Defines a buffer port to be used by yosys during synthesis: in the format `{cell}/{input_port}/{output_port}`",
pdk=True,
),
Variable(
"WELLTAP_CELL",
str,
"Defines the cell used for tap insertion.",
pdk=True,
deprecated_names=["FP_WELLTAP_CELL"],
),
Variable(
"ENDCAP_CELL",
str,
"Defines the so-called 'end-cap' cell- class of decap cells placed at either sides of a design.",
pdk=True,
deprecated_names=["FP_ENDCAP_CELL"],
),
# Placement
Variable(
"PLACE_SITE",
Expand All @@ -335,9 +321,23 @@ def _prefix_to_wildcard(prefixes_raw: Union[str, Sequence[str]]):
Variable(
"DIODE_CELL",
Optional[str],
"Defines a diode cell used to fix antenna violations, in the format {name}/{port}.",
"Defines a diode cell used to fix antenna violations, in the format {name}/{port}. If not defined, steps should not attempt to repair the antenna effect by inserting diode cells.",
pdk=True,
),
Variable(
"WELLTAP_CELL",
Optional[str],
"Defines the cell used for tap insertion. If not defined, steps should not attempt to insert welltap cells.",
pdk=True,
deprecated_names=["FP_WELLTAP_CELL"],
),
Variable(
"ENDCAP_CELL",
Optional[str],
"Defines the so-called 'end-cap' cell- class of decap cells placed at either sides of a design, if available.",
pdk=True,
deprecated_names=["FP_ENDCAP_CELL"],
),
]
option_variables = [
# Common
Expand Down
6 changes: 2 additions & 4 deletions openlane/scripts/openroad/cut_rows.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ source $::env(SCRIPTS_DIR)/openroad/common/io.tcl
read_current_odb

set arg_list [list]
lappend arg_list -endcap_master $::env(ENDCAP_CELL)
lappend arg_list -halo_width_x $::env(FP_MACRO_HORIZONTAL_HALO)
lappend arg_list -halo_width_y $::env(FP_MACRO_VERTICAL_HALO)
if { [info exists ::env(FP_PRUNE_THRESHOLD)] } {
lappend arg_list -row_min_width $::env(FP_PRUNE_THRESHOLD)
}
append_if_exists_argument arg_list FP_PRUNE_THRESHOLD -row_min_width
append_if_exists_argument arg_list ENDCAP_CELL -endcap_master
log_cmd cut_rows {*}$arg_list

# # verify -row_min_width worked
Expand Down
26 changes: 16 additions & 10 deletions openlane/scripts/openroad/drt.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,23 @@ drt_run $i {*}$drt_args

incr i

set diode_cell [lindex [split $::env(DIODE_CELL) "/"] 0]
if { ![info exists ::env(DIODE_CELL)] } {
puts "\[INFO\] Skipping post-DRT antenna repair: 'DIODE_CELL' not set."
} elseif { $::env(DRT_ANTENNA_REPAIR_ITERS) == 0 } {
puts "\[INFO\] Skipping post-DRT antenna repair: DRT_ANTENNA_REPAIR_ITERS set to 0."
} else {
set diode_cell [lindex [split $::env(DIODE_CELL) "/"] 0]

while {$i <= $::env(DRT_ANTENNA_REPAIR_ITERS) && [log_cmd check_antennas]} {
puts "\[INFO\] Running antenna repair iteration $i"
set diodes_inserted [log_cmd repair_antennas $diode_cell -ratio_margin $::env(DRT_ANTENNA_MARGIN)]
if {$diodes_inserted} {
drt_run $i {*}$drt_args
} else {
puts "\[INFO\] No diodes inserted. Ending antenna repair iterations."
break
while {$i <= $::env(DRT_ANTENNA_REPAIR_ITERS) && [log_cmd check_antennas]} {
puts "\[INFO\] Running antenna repair iteration $i"
set diodes_inserted [log_cmd repair_antennas $diode_cell -ratio_margin $::env(DRT_ANTENNA_MARGIN)]
if {$diodes_inserted} {
drt_run $i {*}$drt_args
} else {
puts "\[INFO\] No diodes inserted. Ending antenna repair iterations."
break
}
incr i
}
incr i
}
write_views
19 changes: 13 additions & 6 deletions openlane/scripts/openroad/tapcell.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@
source $::env(SCRIPTS_DIR)/openroad/common/io.tcl
read_current_odb

log_cmd tapcell\
-distance $::env(FP_TAPCELL_DIST)\
-tapcell_master "$::env(WELLTAP_CELL)"\
-endcap_master "$::env(ENDCAP_CELL)"\
-halo_width_x $::env(FP_MACRO_HORIZONTAL_HALO)\
-halo_width_y $::env(FP_MACRO_VERTICAL_HALO)
set tapcell_args [list]
append_if_exists_argument tapcell_args FP_TAPCELL_DIST -distance
append_if_exists_argument tapcell_args WELLTAP_CELL -tapcell_master
append_if_exists_argument tapcell_args ENDCAP_CELL -endcap_master

if { [llength tapcell_args] } {
log_cmd tapcell\
-halo_width_x $::env(FP_MACRO_HORIZONTAL_HALO)\
-halo_width_y $::env(FP_MACRO_VERTICAL_HALO)\
{*}$tapcell_args

} else {
puts "\[INFO\] WELLTAP_CELL and ENDCAP_CELL both unspecified. Doing nothing."
}

write_views
2 changes: 1 addition & 1 deletion openlane/steps/cvc_rv.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,5 +165,5 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
)
return {}, {}
except CVCNoSupport as e:
self.warn(f"Could not run CVC: {e}. Skipping…")
self.warn(f"Could not run CVC: {e}. Skipping '{self.id}'…")
return {}, {}
29 changes: 23 additions & 6 deletions openlane/steps/odb.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def get_command(self) -> List[str]:

def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if not self.get_cells():
info("No cells provided, skipping…")
info(f"No cells provided, skipping '{self.id}'…")
return {}, {}
return super().run(state_in, **kwargs)

Expand Down Expand Up @@ -242,7 +242,7 @@ def get_command(self) -> List[str]:

def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if self.config["FP_DEF_TEMPLATE"] is None:
info("No DEF template provided, skipping…")
info(f"No DEF template provided, skipping '{self.id}'…")
return {}, {}

views_updates, metrics_updates = super().run(state_in, **kwargs)
Expand Down Expand Up @@ -657,7 +657,7 @@ def get_command(self) -> List[str]:

def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if self.config["FP_PIN_ORDER_CFG"] is None:
info("No custom floorplan file configured, skipping…")
info(f"No custom floorplan file configured, skipping '{self.id}'…")
return {}, {}
return super().run(state_in, **kwargs)

Expand Down Expand Up @@ -715,7 +715,11 @@ def get_command(self) -> List[str]:

def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if self.config["DIODE_ON_PORTS"] == "none":
info("'DIODE_ON_PORTS' is set to 'none': skipping…")
info(f"'DIODE_ON_PORTS' is set to 'none': skipping '{self.id}'…")
return {}, {}

if self.config["DIODE_CELL"] is None:
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
return {}, {}

if self.config["GPL_CELL_PADDING"] == 0:
Expand Down Expand Up @@ -755,7 +759,10 @@ class DiodesOnPorts(CompositeStep):

def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if self.config["DIODE_ON_PORTS"] == "none":
info("'DIODE_ON_PORTS' is set to 'none': skipping…")
info(f"'DIODE_ON_PORTS' is set to 'none': skipping '{self.id}'…")
return {}, {}
if self.config["DIODE_CELL"] is None:
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
return {}, {}
return super().run(state_in, **kwargs)

Expand Down Expand Up @@ -826,6 +833,10 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
"'GPL_CELL_PADDING' is set to 0. This step may cause overlap failures."
)

if self.config["DIODE_CELL"] is None:
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
return {}, {}

return super().run(state_in, **kwargs)


Expand Down Expand Up @@ -860,6 +871,12 @@ class HeuristicDiodeInsertion(CompositeStep):
GlobalRouting,
]

def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if self.config["DIODE_CELL"] is None:
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
return {}, {}
return super().run(state_in, **kwargs)


@Step.factory.register()
class CellFrequencyTables(OdbpyStep):
Expand Down Expand Up @@ -946,6 +963,6 @@ def get_command(self) -> List[str]:

def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if self.config["MANUAL_GLOBAL_PLACEMENTS"] is None:
info("'MANUAL_GLOBAL_PLACEMENTS' not set, skipping…")
info(f"'MANUAL_GLOBAL_PLACEMENTS' not set, skipping '{self.id}'…")
return {}, {}
return super().run(state_in, **kwargs)
29 changes: 22 additions & 7 deletions openlane/steps/openroad.py
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,13 @@ class TapEndcapInsertion(OpenROADStep):
name = "Tap/Decap Insertion"

config_vars = OpenROADStep.config_vars + [
Variable(
"FP_TAPCELL_DIST",
Optional[Decimal],
"The distance between tap cell columns. Must be specified if WELLTAP_CELL is specified.",
units="µm",
pdk=True,
),
Variable(
"FP_MACRO_HORIZONTAL_HALO",
Decimal,
Expand All @@ -1199,18 +1206,19 @@ class TapEndcapInsertion(OpenROADStep):
units="µm",
deprecated_names=["FP_TAP_VERTICAL_HALO"],
),
Variable(
"FP_TAPCELL_DIST",
Decimal,
"The distance between tap cell columns.",
units="µm",
pdk=True,
),
]

def get_script_path(self):
return os.path.join(get_script_dir(), "openroad", "tapcell.tcl")

def run(self, state_in, **kwargs):
if (
self.config["WELLTAP_CELL"] is not None
and self.config["FP_TAPCELL_DIST"] is None
):
raise StepException("FP_TAPCELL_DIST must be set if WELLTAP_CELL is set.")
return super().run(state_in, **kwargs)


@Step.factory.register()
class UnplaceAll(OpenROADStep):
Expand Down Expand Up @@ -1670,6 +1678,13 @@ class RepairAntennas(CompositeStep):

Steps = [_DiodeInsertion, CheckAntennas]

def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
if self.config["DIODE_CELL"] is None:
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
return {}, {}

return super().run(state_in, **kwargs)


@Step.factory.register()
class DetailedRouting(OpenROADStep):
Expand Down
2 changes: 1 addition & 1 deletion openlane/steps/yosys.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
)
else:
info(
f"PDK {self.config['PDK']} is not supported by the EQY step. Skipping…"
f"PDK {self.config['PDK']} is not supported by the EQY step. Skipping '{self.id}'…"
)
return {}, {}

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "openlane"
version = "3.0.0.dev16"
version = "3.0.0.dev17"
description = "An infrastructure for implementing chip design flows"
authors = ["Efabless Corporation and Contributors <[email protected]>"]
readme = "Readme.md"
Expand Down

0 comments on commit 21f8e1e

Please sign in to comment.