diff --git a/openlane/config/pdk_compat.py b/openlane/config/pdk_compat.py index 0b0b5056a..e0025c628 100644 --- a/openlane/config/pdk_compat.py +++ b/openlane/config/pdk_compat.py @@ -24,9 +24,9 @@ def migrate_old_config(config: Mapping[str, Any]) -> Dict[str, Any]: if "SYNTH_DRIVING_CELL_PIN" in new: del new["SYNTH_DRIVING_CELL"] del new["SYNTH_DRIVING_CELL_PIN"] - new["SYNTH_DRIVING_CELL"] = ( - f"{config['SYNTH_DRIVING_CELL']}/{config['SYNTH_DRIVING_CELL_PIN']}" - ) + new[ + "SYNTH_DRIVING_CELL" + ] = f"{config['SYNTH_DRIVING_CELL']}/{config['SYNTH_DRIVING_CELL_PIN']}" # 2. Migrate SYNTH_TIE{HI,LO}_CELL if "SYNTH_TIEHI_PORT" in new: @@ -171,9 +171,9 @@ def migrate_old_config(config: Mapping[str, Any]) -> Dict[str, Any]: del new["KLAYOUT_DRC_TECH_SCRIPT"] - new["SYNTH_CLK_DRIVING_CELL"] = ( - f"{config['SYNTH_CLK_DRIVING_CELL']}/{config['SYNTH_DRIVING_CELL_PIN']}" - ) + new[ + "SYNTH_CLK_DRIVING_CELL" + ] = f"{config['SYNTH_CLK_DRIVING_CELL']}/{config['SYNTH_DRIVING_CELL_PIN']}" # x3. Timing Corners lib_sta: Dict[str, List[str]] = {} @@ -251,4 +251,7 @@ def process_sta(key: str): elif new["PDK"].startswith("gf180mcu"): new["HEURISTIC_ANTENNA_THRESHOLD"] = 130 + if new["PDK"].startswith("sky130"): + new["ISOSUB_LAYER"] = (81, 53) + return new diff --git a/openlane/scripts/klayout/stream_out.py b/openlane/scripts/klayout/stream_out.py index 3bdbcb3e5..73ddc1141 100755 --- a/openlane/scripts/klayout/stream_out.py +++ b/openlane/scripts/klayout/stream_out.py @@ -77,6 +77,10 @@ required=True, help="KLayout .map (LEF/DEF layer map) file", ) +@click.option( + "--isosub", + "isosub", +) @click.option("-w", "--with-gds-file", "input_gds_files", multiple=True, default=[]) @click.option("-s", "--seal-gds-file", "seal_gds", default=None) @click.option( @@ -100,6 +104,7 @@ def stream_out( seal_gds: Optional[str], design_name: str, input: str, + isosub: str, ): # Load technology file try: tech = pya.Technology() @@ -165,6 +170,13 @@ def stream_out( # Write out the GDS print(f"[INFO] Writing out GDS '{output}'…") + if isosub is not None: + top_cell_bbox = top_only_layout.top_cell().bbox() + isosub_layer = top_only_layout.layer( + int(isosub.split(";")[0]), int(isosub.split(";")[1]) + ) + top_only_layout.top_cell().shapes(isosub_layer).insert(top_cell_bbox) + print("[INFO] Added isosub") top_only_layout.write(output) print("[INFO] Done.") except Exception as e: diff --git a/openlane/scripts/magic/add_subcut.tcl b/openlane/scripts/magic/add_subcut.tcl new file mode 100644 index 000000000..170eba437 --- /dev/null +++ b/openlane/scripts/magic/add_subcut.tcl @@ -0,0 +1,30 @@ +# Copyright 2024 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +source $::env(SCRIPTS_DIR)/magic/common/read.tcl +drc off +read_pdk_gds +gds noduplicates true +gds read $::env(CURRENT_GDS) +load $::env(DESIGN_NAME) +select top cell +paint isosub +if { $::env(MAGIC_DISABLE_CIF_INFO) } { + cif *hier write disable + cif *array write disable +} +gds nodatestamp yes +if { $::env(MAGIC_GDS_POLYGON_SUBCELLS) } { + gds polygon subcells true +} +gds write $::env(SAVE_MAG_GDS) diff --git a/openlane/scripts/magic/def/mag_gds.tcl b/openlane/scripts/magic/def/mag_gds.tcl index 90ca86b39..1c8a0a4e9 100755 --- a/openlane/scripts/magic/def/mag_gds.tcl +++ b/openlane/scripts/magic/def/mag_gds.tcl @@ -75,6 +75,10 @@ if { $::env(MAGIC_GDS_POLYGON_SUBCELLS) } { gds polygon subcells true } +if { $::env(MAGIC_ADD_ISOSUB) } { + paint isosub +} + gds write $::env(SAVE_MAG_GDS) puts "\[INFO\] GDS Write Complete" diff --git a/openlane/steps/klayout.py b/openlane/steps/klayout.py index 14db3d1a0..e8b48e255 100644 --- a/openlane/steps/klayout.py +++ b/openlane/steps/klayout.py @@ -24,7 +24,7 @@ from .step import ViewsUpdate, MetricsUpdate, Step, StepError, StepException from ..config import Variable -from ..logging import info +from ..logging import info, warn from ..state import DesignFormat, State from ..common import Path, get_script_dir, mkdirp, _get_process_limit @@ -185,6 +185,21 @@ class StreamOut(KLayoutStep): id = "KLayout.StreamOut" name = "GDSII Stream Out (KLayout)" + config_vars = KLayoutStep.config_vars + [ + Variable( + "ISOSUB_LAYER", + Optional[Tuple[int, int]], + "Layer/datatype pair for subcut", + pdk=True, + ), + Variable( + "KLAYOUT_ADD_ISOSUB", + bool, + default=False, + description="Add isosub(subcut) drawing over the design. Useful when the design is getting integarated in a design with multiple power domains", + ), + ] + inputs = [DesignFormat.DEF] outputs = [DesignFormat.GDS, DesignFormat.KLAYOUT_GDS] @@ -197,6 +212,14 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]: ) kwargs, env = self.extract_env(kwargs) + isosub_layer_arg = [] + if self.config.get("KLAYOUT_ADD_ISOSUB"): + if isosub_layer := self.config.get("ISOSUB_LAYER"): + isosub_layer_arg = ["--isosub", f"{isosub_layer[0]};{isosub_layer[1]}"] + else: + warn( + "KLAYOUT_ADD_ISOSUB enabled but no ISOSUB_LAYER defined for the PDK. Not going to add isosub to the design" + ) self.run_pya_script( [ sys.executable, @@ -211,7 +234,8 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]: "--top", self.config["DESIGN_NAME"], ] - + self.get_cli_args(include_lefs=True, include_gds=True), + + self.get_cli_args(include_lefs=True, include_gds=True) + + isosub_layer_arg, env=env, ) diff --git a/openlane/steps/magic.py b/openlane/steps/magic.py index bd27f9c1b..6716960c1 100644 --- a/openlane/steps/magic.py +++ b/openlane/steps/magic.py @@ -274,6 +274,12 @@ class StreamOut(MagicStep): "A flag to move the layout such that it's origin in the lef generated by magic is 0,0.", default=False, ), + Variable( + "MAGIC_ADD_ISOSUB", + bool, + "Add isosub(subcut) drawing over the design. Useful when the design is getting integarated in a design with multiple power domains", + default=False, + ), Variable( "MAGIC_DISABLE_CIF_INFO", bool, @@ -564,3 +570,15 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]: magic.send_signal(SIGKILL) return {}, {} + + +@Step.factory.register() +class AddIsosub(MagicStep): + id = "Magic.AddIsosub" + name = "Add isosub(subcut) to the design" + + outputs = [DesignFormat.GDS, DesignFormat.MAG_GDS] + config_vars = StreamOut.config_vars + + def get_script_path(self): + return os.path.join(get_script_dir(), "magic", "add_subcut.tcl")