Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: allow PDKs without diode, antenna, and/or decap cells #662

Merged
merged 5 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading