diff --git a/doc/Technology/Tech-class.rst b/doc/Technology/Tech-class.rst index e71d8be47..58bc778aa 100644 --- a/doc/Technology/Tech-class.rst +++ b/doc/Technology/Tech-class.rst @@ -28,6 +28,7 @@ HammerTechnology Class The HammerTechnology class is the base class that all technology plugins should inherit from and is defined in ``hammer/tech/__init__.py``. Particularly useful methods are: +* ``gen_config``: the plugin subclass should override this method to generate the tech config. See the next section (:ref:`tech-json`) for details. * ``post_install_script``: the plugin subclass should override this method to apply any non-default PDK installation steps or hotfixes in order to set up the technology libraries for use with Hammer. * ``read_libs``: this is a particularly powerful method to read the libraries contained in the ``tech.json`` file and filter them using the filters also contained the same file. See the :ref:`filters` section for details. * ``get_tech__hooks``: these methods are necessary if tech--specific hooks are needed, and must return a list of hooks when a given tool name implementing the relevant action is called. Refer to the :ref:`hooks` section for details about how to write hooks. diff --git a/doc/Technology/Tech-json.rst b/doc/Technology/Tech-json.rst index ef4a412bc..2c5388906 100644 --- a/doc/Technology/Tech-json.rst +++ b/doc/Technology/Tech-json.rst @@ -1,16 +1,51 @@ .. _tech-json: -Hammer Tech JSON +Hammer Tech Config (Tech JSON) =============================== -The ``tech.json`` for a given technology sets up some general information about the install of the PDK, sets up DRC rule decks, sets up pointers to PDK files, and supplies technology stackup information. -For the full schema of the tech JSON, please see the :ref:`full_schema` section below, which is derived from the ``TechJSON`` Pydantic BaseModel in ``hammer/tech/__init__.py``. +Technology plugins must set up some general information about the install of the PDK, set up DRC rule decks, set up pointers to PDK files, and supply technology stackup information. +Formerly, this information was provided in a static ``.tech.json`` file. We now encourage you to generate this information in the form of ``TechJSON`` Pydantic BaseModel instances (see ``hammer/tech/__init__.py`` for all BaseModel definitions). Instructions are given below for both forms, with examples from the Sky130 and ASAP7 plugins. + +For the full schema of the tech configuration, please see the :ref:`full_schema` section below, which is derived from ``TechJSON``. Technology Install --------------------------------- -The user may supply the PDK to Hammer as an already extracted directory and/or as a tarball that Hammer can automatically extract. Setting ``technology.TECH_NAME.`` ``install_dir`` and/or ``tarball_dir`` (key is setup in the defaults.yml) will fill in as the path prefix for paths supplied to PDK files in the rest of the ``tech.json``. -Below is an example of the installs and tarballs from the ASAP7 plugin. +The user may supply the PDK to Hammer as an already extracted directory and/or as a tarball that Hammer can automatically extract. Setting ``technology.TECH_NAME.`` key (as defined in the plugin's ``defaults.yml``) will fill in as the path prefix for paths supplied to PDK files. + +Path prefixes can be supplied in multiple forms. The options are as follows (taken from ``prepend_dir_path`` in ``hammer/tech/__init__py``): + +#. Absolute path: the path starts with "/" and refers to an absolute path on the filesystem + * ``/path/to/a/lib/file.lib`` -> ``/path/to/a/lib/file.lib`` +#. Tech plugin relative path: the path has no "/"s and refers to a file directly inside the tech plugin folder (no subdirectories allowed, else it conflicts with 3-5. below!) + * ``techlib.lib`` -> ``/techlib.lib`` +#. Tech cache relative path: the path starts with an identifier which is "cache" (this is used in the SKY130 example below) + * ``cache/primitives.v`` -> ``/primitives.v`` +#. Install relative path: the path starts with an install/tarball identifier (installs.id, tarballs.root.id) and refers to a file relative to that identifier's path + * ``pdkroot/dac/dac.lib`` -> ``/nfs/ecad/tsmc100/stdcells/dac/dac.lib`` +#. Library extra_prefix path: the path starts with an identifier present in the provided library's ``extra_prefixes`` Field + * ``lib1/cap150f.lib`` -> ``/design_files/caps/cap150f.lib`` + +Below is an example of the installs and tarballs defining path prefixes from the Sky130 and ASAP7 plugins. + +Pydantic: + +.. code-block:: python + + def gen_config(self) -> None: + #... + self.config = TechJSON( + name = "Skywater 130nm Library", + grid_unit = "0.001", + installs = [ + PathPrefix(id = "$SKY130_NDA", path = "technology.sky130.sky130_nda"), + PathPrefix(id = "$SKY130A", path = "technology.sky130.sky130A"), + PathPrefix(id = "$SKY130_CDS", path = "technology.sky130.sky130_cds") + ], + #fields skipped... + ) + +JSON: .. code-block:: json @@ -37,13 +72,33 @@ Below is an example of the installs and tarballs from the ASAP7 plugin. } ], -The ``id`` field is used within the file listings further down in the file to prefix ``path``, as shown in detail below. If the file listing begins with ``cache``, then this denotes files that exist in the tech cache, which are generally placed there by the tech plugin's post-installation script (see ASAP7's ``post_install_script`` method). Finally, the encrypted Calibre decks are provided in a tarball and denoted as optional. +The ``id`` field is used within the file listings further down in the file to prefix ``path``, as shown in detail below. If the file listing begins with ``cache``, then this denotes files that exist in the tech cache, which are generally placed there by the tech plugin's post-installation script (see ASAP7's ``post_install_script`` method). In the ASAP7 example, the encrypted Calibre decks are provided in a tarball and denoted as optional. DRC/LVS Deck Setup --------------------------------- As many DRC & LVS decks for as many tools can be specified in the ``drc decks`` and ``lvs decks`` keys. Additional DRC/LVS commands can be appended to the generated run files by specifying raw text in the ``additional_drc_text`` and ``additional_lvs_text`` keys. -Below is an example of an LVS deck from the ASAP7 plugin. + +Pydantic: + +.. code-block:: python + + def gen_config(self) -> None: + #... + self.config = TechJSON( + #fields skipped... + drc_decks = [ + DRCDeck(tool_name = "calibre", deck_name = "calibre_drc", path = "$SKY130_NDA/s8/V2.0.1/DRC/Calibre/s8_drcRules"), + DRCDeck(tool_name = "klayout", deck_name = "klayout_drc", path = "$SKY130A/libs.tech/klayout/drc/sky130A.lydrc"), + DRCDeck(tool_name = "pegasus", deck_name = "pegasus_drc", path = "$SKY130_CDS/Sky130_DRC/sky130_rev_0.0_1.0.drc.pvl") + ], + additional_drc_text = "", + #fields skipped... + ) + +The example above contains decks for 3 different tools, with file pointers using the installs prefixes defined before. + +JSON: .. code-block:: json @@ -61,8 +116,59 @@ The file pointers, in this case, use the tarball prefix because Hammer will be e Library Setup --------------------------------- -The ``libraries`` key also must be setup in the JSON plugin. This will tell Hammer where to find all of the relevant files for standard cells and other blocks for the VLSI flow. -Below is an example of the start of the library setup and one entry from the ASAP7 plugin. +The ``libraries`` Field also must be set in the TechJSON instance. This will tell Hammer where to find all of the relevant files for standard cells and other blocks for the VLSI flow. Path prefixes are used most heavily here. + +The ``corner`` Field (BaseModel type: Corner) tells Hammer what process and temperature corner that these files correspond to. The ``supplies`` Field (BaseModel type: Supplies) tells Hammer what the nominal supply for these cells are. +The ``provides`` Field (type: List[Provide]) has several sub-fields that tell Hammer what kind of library this is (examples include ``stdcell``, ``fiducials``, ``io pad cells``, ``bump``, and ``level shifters``) and the threshold voltage flavor of the cells, if applicable. +Adding the tech LEF for the technology with the ``lib_type`` set as ``technology`` is necessary for place and route. This must be the first ``lef_file`` provided in the entire list of Libraries. + +Pydantic: + +.. code-block:: python + + def gen_config(self) -> None: + #... + libs = [ + Library(lef_file = "cache/sky130_fd_sc_hd__nom.tlef", verilog_sim = "cache/primitives.v", provides = [Provide(lib_type = "technology")]), + Library(spice_file = "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_ef_io__analog.spice", provides = [Provide(lib_type = "IO library")]) + ] + #... + #Generate loops + SKYWATER_LIBS = os.path.join('$SKY130A', 'libs.ref', library) + for cornerfilename in lib_corner_files: + #... + lib_entry = Library( + nldm_liberty_file = os.path.join(SKYWATER_LIBS,'lib', cornerfilename), + verilog_sim = os.path.join(SKYWATER_LIBS,'verilog', file_lib + '.v'), + lef_file = lef_file, + spice_file = spice_file, + gds_file = os.path.join(SKYWATER_LIBS,'gds', gds_file), + corner = Corner( + nmos = speed, + pmos = speed, + temperature = temp + ), + supplies = Supplies( + VDD = vdd, + GND ="0 V" + ), + provides = [Provide( + lib_type = cell_name, + vt = "RVT" + ) + ] + ) + libs.append(lib_entry) + #... + self.config = TechJSON( + #fields skipped... + libraries = libs, + #fields skipped... + ) + +In the above example, we use the ``$SKY130A`` prefix and some loops to generate Library entries. These loops are often derived from the directory structure of the standard cell library. + +JSON: .. code-block:: json @@ -102,9 +208,7 @@ Below is an example of the start of the library setup and one entry from the ASA ] }, -The file pointers, in this case, use the ``$PDK`` and ``$STDCELLS`` prefix as defined in the installs. The ``corner`` key tells Hammer what process and temperature corner that these files correspond to. The ``supplies`` key tells Hammer what the nominal supply for these cells are. -The ``provides`` key has several sub-keys that tell Hammer what kind of library this is (examples include ``stdcell``, ``fiducials``, ``io pad cells``, ``bump``, and ``level shifters``) and the threshold voltage flavor of the cells, if applicable. -Adding the tech LEF for the technology with the ``lib_type`` set as ``technology`` is necessary for place and route. +The file pointers, in this case, use the ``$PDK`` and ``$STDCELLS`` prefix as defined in the installs. .. _filters: @@ -117,32 +221,79 @@ For a list of pre-built library filters, refer to the properties in the ``Librar Stackup -------------------------------- -The ``stackups`` sets up the important metal layer information for Hammer to use. -Below is an example of one metal layer in the ``metals`` list from the ASAP7 example tech plugin. +The ``stackups`` sets up the important metal layer information for Hammer to use. All this information is typically taken from the tech LEF and can be automatically filled in with a script. + +You can use ``LEFUtils.get_metals`` to generate the stackup information for simple tech LEFs: + +.. code-block:: python + + from hammer.tech import * + from hammer.utils import LEFUtils + class SKY130Tech(HammerTechnology): + def gen_config(self) -> None: + #... + stackups = [] # type: List[Stackup] + tlef_path = os.path.join(SKY130A, 'libs.ref', library, 'techlef', f"{library}__min.tlef") + metals = list(map(lambda m: Metal.model_validate(m), LEFUtils.get_metals(tlef_path))) + stackups.append(Stackup(name = library, grid_unit = Decimal("0.001"), metals = metals)) + + self.config = TechJSON( + #fields skipped... + stackups = stackups, + #fields skipped... + ) + + +Below is an example of one metal layer in the ``metals`` list from the ASAP7 example tech plugin. This gives a better idea of the serialized fields in the Metal BaseModel. This is extracted by loading the tech LEF into Innovus, then using the ``hammer/par/innovus/dump_stackup_to_json.tcl`` script. .. code-block:: json {"name": "M3", "index": 3, "direction": "vertical", "min_width": 0.072, "pitch": 0.144, "offset": 0.0, "power_strap_widths_and_spacings": [{"width_at_least": 0.0, "min_spacing": 0.072}], "power_strap_width_table": [0.072, 0.36, 0.648, 0.936, 1.224, 1.512]} -All this information is typically taken from the tech LEF and can be automatically filled in with a script. The metal layer name and layer number is specified. ``direction`` specifies the preferred routing direction for the layer. ``min_width`` and ``pitch`` specify the minimum width wire and the track pitch, respectively. ``power_strap_widths_and_spacings`` is a list of pairs that specify design rules relating to the widths of wires and minimum required spacing between them. This information is used by Hammer when drawing power straps to make sure it is conforming to some basic design rules. +The metal layer name and layer number is specified. ``direction`` specifies the preferred routing direction for the layer. ``min_width`` and ``pitch`` specify the minimum width wire and the track pitch, respectively. ``power_strap_widths_and_spacings`` is a list of pairs that specify design rules relating to the widths of wires and minimum required spacing between them. This information is used by Hammer when drawing power straps to make sure it is conforming to some basic design rules. Sites -------------------------------- The ``sites`` field specifies the unit standard cell size of the technology for Hammer. +.. code-block:: python + + def gen_config(self) -> None: + #... + self.config = TechJSON( + #fields skipped... + sites = [ + Site(name = "unithd", x = Decimal("0.46"), y = Decimal("2.72")), + Site(name = "unithddbl", x = Decimal("0.46"), y = Decimal("5.44")) + ], + #fields skipped... + ) + .. code-block:: json "sites": [ {"name": "asap7sc7p5t", "x": 0.216, "y": 1.08} ] -This is an example from the ASAP7 tech plugin in which the ``name`` parameter specifies the core site name used in the tech LEF, and the ``x`` and ``y`` parameters specify the width and height of the unit standard cell size, respectively. +These are examples from the Sky130 and ASAP7 tech plugin in which the ``name`` parameter specifies the core site name used in the tech LEF, and the ``x`` and ``y`` parameters specify the width and height of the unit standard cell size, respectively. Special Cells -------------------------------- The ``special_cells`` field specifies a set of cells in the technology that have special functions. -The example below shows a subset of the ASAP7 tech plugin for 2 types of cells: ``tapcell`` and ``stdfiller``. +The example below shows a subset of the Sky130 and ASAP7 tech plugin for 2 types of cells: ``tapcell`` and ``stdfiller``. + +.. code-block:: python + + def gen_config(self) -> None: + #... + self.config = TechJSON( + #fields skipped... + special_cells = [ + SpecialCell(cell_type = CellType("tapcell"), name = ["sky130_fd_sc_hd__tapvpwrvgnd_1"]), + SpecialCell(cell_type = CellType("stdfiller"), name = ["sky130_fd_sc_hd__fill_1", "sky130_fd_sc_hd__fill_2", "sky130_fd_sc_hd__fill_4", "sky130_fd_sc_hd__fill_8"]), + ] + ) .. code-block:: json @@ -161,7 +312,25 @@ There is an optional ``size`` list. For each element in its corresponding ``name Don't Use, Physical-Only Cells -------------------------------- The ``dont_use_list`` is used to denote cells that should be excluded due to things like bad timing models or layout. -The ``physical_only_cells_list`` is used to denote cells that contain only physical geometry, which means that they should be excluded from netlisting for simulation and LVS. Examples from the ASAP7 plugin are below: +The ``physical_only_cells_list`` is used to denote cells that contain only physical geometry, which means that they should be excluded from netlisting for simulation and LVS. Examples: + +.. code-block:: python + + def gen_config(self) -> None: + #... + self.config = TechJSON( + #fields skipped... + physical_only_cells_list = [ + "sky130_fd_sc_hd__tap_1", "sky130_fd_sc_hd__tap_2", "sky130_fd_sc_hd__tapvgnd_1", "sky130_fd_sc_hd__tapvpwrvgnd_1", + "sky130_fd_sc_hd__fill_1", "sky130_fd_sc_hd__fill_2", "sky130_fd_sc_hd__fill_4", "sky130_fd_sc_hd__fill_8", + "sky130_fd_sc_hd__diode_2"] + dont_use_list = [ + "*sdf*", + "sky130_fd_sc_hd__probe_p_*", + "sky130_fd_sc_hd__probec_p_*" + ] + #fields skipped... + ) .. code-block:: json diff --git a/e2e/Makefile b/e2e/Makefile index 00c370bac..a66bb878c 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -45,4 +45,4 @@ $(HAMMER_D_MK): -include $(HAMMER_D_MK) clean: - rm -rf $(OBJ_DIR) hammer-vlsi-*.log + rm -rf $(OBJ_DIR) hammer-vlsi-*.log diff --git a/e2e/configs-env/bwrc-env.yml b/e2e/configs-env/bwrc-env.yml index 613304ede..e4fc2429e 100644 --- a/e2e/configs-env/bwrc-env.yml +++ b/e2e/configs-env/bwrc-env.yml @@ -33,7 +33,8 @@ technology.sky130: sram22_sky130_macros: "/tools/commercial/skywater/local/sram22_sky130_macros" openram_lib: "/tools/commercial/skywater/local/sky130_sram_macros" sky130_nda: "/tools/commercial/skywater/swtech130/skywater-src-nda-20221031" - sky130_cds: "/tools/commercial/skywater/sky130_cds/sky130_prelim_release_091123" + sky130_cds: "/tools/commercial/skywater/sky130_cds/PDK/sky130_release_0.0.3/" + sky130_scl: "/tools/commercial/skywater/sky130_cds/LIB/sky130_scl_9T_0.0.3/" # ASAP7 paths technology.asap7: diff --git a/e2e/pdks/sky130-bwrc.yml b/e2e/pdks/sky130-bwrc.yml index e7feb9a04..0d75b7862 100644 --- a/e2e/pdks/sky130-bwrc.yml +++ b/e2e/pdks/sky130-bwrc.yml @@ -5,8 +5,10 @@ technology.sky130: openram_lib: "/tools/commercial/skywater/local/sky130_sram_macros" sky130_nda: "/tools/commercial/skywater/swtech130/skywater-src-nda-20221031" sky130_cds: "/tools/commercial/skywater/sky130_cds/sky130_prelim_release_091123" + sky130_cds: "/tools/commercial/skywater/sky130_cds/PDK/sky130_release_0.0.3/" + sky130_scl: "/tools/commercial/skywater/sky130_cds/LIB/sky130_scl_9T_0.0.3/" -synthesis.genus.version: "211" +synthesis.genus.version: "221" par.innovus.version: "211" sim.vcs.version: "S-2021.09-SP1-1" diff --git a/hammer/drc/pegasus/__init__.py b/hammer/drc/pegasus/__init__.py index 1f5b3509e..3d899e3c8 100644 --- a/hammer/drc/pegasus/__init__.py +++ b/hammer/drc/pegasus/__init__.py @@ -30,7 +30,9 @@ def empty_step(self) -> bool: @property def steps(self) -> List[HammerToolStep]: - steps = [self.generate_drc_ctl_file] # TODO: DRC steps require multiple runs of the tool how do we support this? + steps = [ + self.generate_drc_ctl_file + ] # TODO: DRC steps require multiple runs of the tool how do we support this? return self.make_steps_from_methods(steps) def do_post_steps(self) -> bool: @@ -50,17 +52,22 @@ def run_pegasus(self) -> bool: args = [ pegasus_bin, "-drc", # DRC mode - "-dp", str(self.get_setting("vlsi.core.max_threads")), + "-dp", + str(self.get_setting("vlsi.core.max_threads")), "-license_dp_continue", # don't quit if requested dp license not available - "-control", self.drc_ctl_file, - "-log_dir", f"{self.top_module}_logs", - "-ui_data" # for results viewer + "-control", + self.drc_ctl_file, + "-log_dir", + f"{self.top_module}_logs", + "-ui_data", # for results viewer # TODO: -interactive for block level - ] + rules + ] + rules HammerVLSILogging.enable_colour = False HammerVLSILogging.enable_tag = False - self.run_executable(args, cwd=self.run_dir) # TODO: check for errors and deal with them + self.run_executable( + args, cwd=self.run_dir + ) # TODO: check for errors and deal with them HammerVLSILogging.enable_colour = True HammerVLSILogging.enable_tag = True @@ -72,31 +79,43 @@ def run_pegasus(self) -> bool: technology = self.get_setting("vlsi.core.technology").split(".")[-1] with open(self.view_drc_script, "w") as f: - f.write(textwrap.dedent(f""" + f.write( + textwrap.dedent( + f""" cd {self.run_dir} source ./enter {pegasus_bin}DesignReview -qrv -tech {technology} -data {self.layout_file} -post {self.dr_rv_macro} -verbose - """)) + """ + ) + ) os.chmod(self.view_drc_script, 0o755) with open(self.dr_rv_macro, "w") as f: - f.write(textwrap.dedent(f''' + f.write( + textwrap.dedent( + f""" PVS::invoke_pvsrv("{self.run_dir}"); - ''')) + """ + ) + ) return True def generate_drc_ctl_file(self) -> bool: - """ Generate the DRC control file self.drc_ctl_file and fill its contents """ + """Generate the DRC control file self.drc_ctl_file and fill its contents""" with open(self.drc_ctl_file, "w") as f: - f.write(self.header.replace("#","//")) - f.write(textwrap.dedent(f''' + f.write(self.header.replace("#", "//")) + f.write( + textwrap.dedent( + f""" virtual_connect -report yes; layout_path "{self.layout_file}"; layout_primary {self.top_module}; results_db -drc "{self.drc_results_db}" -ascii; report_summary -drc "{self.drc_results_file}" -replace; - ''')) + """ + ) + ) f.write(self.get_additional_drc_text()) return True @@ -132,10 +151,14 @@ def env_vars(self) -> Dict[str, str]: """ v = dict(super().env_vars) v["PEGASUS_BIN"] = self.get_setting("drc.pegasus.pegasus_bin") + v["PEGASUS_DRC"] = os.path.join( + self.get_setting("technology.sky130.sky130_cds"), "Sky130_DRC" + ) return v @property def post_synth_sdc(self) -> Optional[str]: pass + tool = PegasusDRC diff --git a/hammer/par/openroad/__init__.py b/hammer/par/openroad/__init__.py index dfe3085c4..0a15dfec1 100644 --- a/hammer/par/openroad/__init__.py +++ b/hammer/par/openroad/__init__.py @@ -1448,7 +1448,9 @@ def write_gds(self) -> str: ilm_gds = list(map(lambda ilm: ilm.gds, self.get_input_ilms())) gds_files.extend(ilm_gds) - layer_map_file=self.get_setting('par.inputs.gds_map_file') + layer_map_file=self.get_gds_map_file() + if layer_map_file is None: + raise FileNotFoundError(f"Must have GDS layer map for write_gds! KLayout won't be able to write GDS file. ({layer_map_file}") # the first entry of $KLAYOUT_PATH will be the one where the configuration is stored when KLayout exits # otherwise KLayout tries to write everything to the same directory as the klayout binary and throws an error if it is not writeable diff --git a/hammer/synthesis/genus/__init__.py b/hammer/synthesis/genus/__init__.py index a167f08b7..1a5af24bb 100644 --- a/hammer/synthesis/genus/__init__.py +++ b/hammer/synthesis/genus/__init__.py @@ -198,6 +198,8 @@ def init_environment(self) -> bool: verbose_append("set_db lp_clock_gating_prefix {CLKGATE}") verbose_append("set_db lp_insert_clock_gating true") verbose_append("set_db lp_clock_gating_register_aware true") + else: + verbose_append("set_db lp_clock_gating_infer_enable false") # Set up libraries. # Read timing libraries. diff --git a/hammer/tech/__init__.py b/hammer/tech/__init__.py index 5044745de..7f4b9f709 100644 --- a/hammer/tech/__init__.py +++ b/hammer/tech/__init__.py @@ -353,8 +353,12 @@ def __init__(self): self.time_unit: Optional[str] = None self.cap_unit: Optional[str] = None + def gen_config(self) -> None: + """For subclasses to set self.config (type: TechJSON) directly, instead of from static JSON file""" + pass + @classmethod - def load_from_module(cls, tech_module: str) -> Optional["HammerTechnology"]: + def load_from_module(cls, tech_module: str) -> "HammerTechnology": """Load a technology from a given module. :param tech_module: Technology module (e.g. "hammer.technology.asap7") @@ -375,8 +379,8 @@ def load_from_module(cls, tech_module: str) -> Optional["HammerTechnology"]: elif tech_yaml.is_file(): tech.config = TechJSON.model_validate_json(json.dumps(load_yaml(tech_yaml.read_text()))) return tech - else: #TODO - from Pydantic model instance - return None + else: # Assume tech implents gen_config() + return tech def get_lib_units(self) -> None: """ @@ -415,6 +419,12 @@ def get_setting(self, key: str) -> Any: print(e) # TODO: fix the root cause return None + def set_setting(self, key: str, value: Any) -> None: + """ + Set a runtime setting in the database. + """ + self._database.set_setting(key, value) + def get_setting_suffix(self, key: str) -> Any: """Get a particular setting from the database with a suffix. """ @@ -648,15 +658,15 @@ def prepend_dir_path(self, path: str, lib: Optional[Library] = None) -> str: 1. Absolute path: the path starts with "/" and refers to an absolute path on the filesystem /path/to/a/lib/file.lib -> /path/to/a/lib/file.lib - 2. Tech plugin relative path: the path has no "/"s and refers to a file directly inside the tech plugin folder + 2. Tech plugin relative path: the path has no "/"s and refers to a file directly inside the tech plugin folder (no subdirectories allowed, else it conflicts with 3-5. below!) techlib.lib -> /techlib.lib - 3. Tech cache relative path: the path starts with an identifier which is "cache" (this is used in the SKY130 tech JSON) + 3. Tech cache relative path: the path starts with an identifier which is "cache" (this is used in the SKY130 Libraries) cache/primitives.v -> /primitives.v 4. Install relative path: the path starts with an install/tarball identifier (installs.id, tarballs.root.id) and refers to a file relative to that identifier's path pdkroot/dac/dac.lib -> /nfs/ecad/tsmc100/stdcells/dac/dac.lib 5. Library extra_prefix path: the path starts with an identifier present in the provided - library's extra_prefixes + library's extra_prefixes Field lib1/cap150f.lib -> /design_files/caps/cap150f.lib """ assert len(path) > 0, "path must not be empty" diff --git a/hammer/technology/sky130/README.md b/hammer/technology/sky130/README.md index 9bfbcac28..2a630ad01 100644 --- a/hammer/technology/sky130/README.md +++ b/hammer/technology/sky130/README.md @@ -45,6 +45,22 @@ Now in your Hammer YAML configs, point to the location of this install: technology.sky130.sky130A: "/share/pdk/sky130A" ``` +### Cadence PDK + +Cadence has also created a PDK and standard cell library based on the original open PDK, and optimized for use with Cadence tools. Usage of this PDK is purely optional, but enables DRC/LVS with Pegasus, and IR drop analysis with Voltus. + +You can download them from [here](https://support.cadence.com/apex/ArticleAttachmentPortal?id=a1Od000000051TqEAI&pageName=ArticleContent) (Cadence Support account is required). After downloading and untar-ing the packages, point to the location of this install: + +```yaml +technology.sky130.sky130_cds: "" +technology.sky130.sky130_scl: "" +``` + +To select this standard cell library (instead of the default `sky130_fd_sc_hd`): + +```yaml +technology.sky130.stdcell_library: "sky130_scl" +``` SRAM Macros ----------- diff --git a/hammer/technology/sky130/__init__.py b/hammer/technology/sky130/__init__.py index 35528bc7b..555bf3992 100644 --- a/hammer/technology/sky130/__init__.py +++ b/hammer/technology/sky130/__init__.py @@ -4,68 +4,544 @@ import sys import re -import os, shutil +import os +import shutil from pathlib import Path from typing import NamedTuple, List, Optional, Tuple, Dict, Set, Any import importlib import json +import functools + +from hammer.tech import * +from hammer.vlsi import ( + HammerTool, + HammerPlaceAndRouteTool, + TCLTool, + HammerDRCTool, + HammerLVSTool, + HammerToolHookAction, + HierarchicalMode, +) +from hammer.utils import LEFUtils +from hammer.vlsi.hammer_vlsi_impl import HammerSimTool -import hammer.tech -from hammer.tech import HammerTechnology -from hammer.vlsi import HammerTool, HammerPlaceAndRouteTool, TCLTool, HammerDRCTool, HammerLVSTool, \ - HammerToolHookAction, HierarchicalMode - -import hammer.tech.specialcells as specialcells -from hammer.tech.specialcells import CellType, SpecialCell class SKY130Tech(HammerTechnology): """ Override the HammerTechnology used in `hammer_tech.py` This class is loaded by function `load_from_json`, and will pass the `try` in `importlib`. """ + + def gen_config(self) -> None: + """Generate the tech config, based on the library type selected""" + slib = self.get_setting("technology.sky130.stdcell_library") + SKY130A = self.get_setting("technology.sky130.sky130A") + SKY130_CDS = self.get_setting("technology.sky130.sky130_cds") + SKY130_CDS_LIB = self.get_setting("technology.sky130.sky130_scl") + + # Common tech LEF and IO cell spice netlists + libs = [] + if slib == "sky130_fd_sc_hd": + libs += [ + Library( + spice_file="$SKY130A/libs.ref/sky130_fd_io/spice/sky130_ef_io.spice", + provides=[Provide(lib_type="IO library")], + ), + Library( + lef_file="cache/sky130_fd_sc_hd__nom.tlef", + verilog_sim="cache/primitives.v", + provides=[Provide(lib_type="technology")], + ), + ] + elif slib == "sky130_scl": + # Since the cadence (v0.0.3) tlef doesn't have nwell/pwell/li1, we can't use the sky130A IO libs. + # TODO: should we just take those layers out of the IO tlef? they shouldn't be necessary since we don't route on those layers + libs += [ + Library( + lef_file="cache/sky130_scl_9T.tlef", + # lef_file="$SKY130_SCL/lef/sky130_scl_9T.tlef", + verilog_sim="$SKY130_SCL/verilog/sky130_scl_9T.v", + provides=[Provide(lib_type="technology")], + ), + ] + else: + raise ValueError(f"Incorrect standard cell library selection: {slib}") + # Generate IO cells unless we're using the Cadence stdcell lib (see above comment about missing layers in tlef) + # nvm we need to do this + if True: # slib != "sky130_scl": + library = "sky130_fd_io" + SKYWATER_LIBS = os.path.join("$SKY130A", "libs.ref", library) + LIBRARY_PATH = os.path.join(SKY130A, "libs.ref", library, "lib") + lib_corner_files = os.listdir(LIBRARY_PATH) + lib_corner_files.sort() + for cornerfilename in lib_corner_files: + # Skip versions with no internal power + if "nointpwr" in cornerfilename: + continue + + tmp = cornerfilename.replace(".lib", "") + # Split into cell, and corner strings + # Resulting list if only one ff/ss/tt in name: [, , , , ] + # Resulting list if ff_ff/ss_ss/tt_tt in name: [, , , , '', , , , ] + split_cell_corner = re.split("_(ff)|_(ss)|_(tt)", tmp) + cell_name = split_cell_corner[0] + process = split_cell_corner[1:-1] + temp_volt = split_cell_corner[-1].split("_")[1:] + + # Filter out cross corners (e.g ff_ss or ss_ff) + if len(process) > 3: + if not functools.reduce( + lambda x, y: x and y, + map(lambda p, q: p == q, process[0:3], process[4:]), + True, + ): + continue + # Determine actual corner + speed = next(c for c in process if c is not None).replace("_", "") + if speed == "ff": + speed = "fast" + if speed == "tt": + speed = "typical" + if speed == "ss": + speed = "slow" + + temp = temp_volt[0] + temp = temp.replace("n", "-") + temp = temp.split("C")[0] + " C" + + vdd = (".").join(temp_volt[1].split("v")) + " V" + # Filter out IO/analog voltages that are not high voltage + if temp_volt[2].startswith("1"): + continue + if len(temp_volt) == 4: + if temp_volt[3].startswith("1"): + continue + + # gpiov2_pad_wrapped has separate GDS + if cell_name == "sky130_ef_io__gpiov2_pad_wrapped": + + file_lib = "sky130_ef_io" + gds_file = cell_name + ".gds" + lef_file = os.path.join( + SKY130A, "libs.ref", library, "lef", "sky130_ef_io.lef" + ) + if self.get_setting("vlsi.core.lvs_tool") == "hammer.lvs.pegasus" and slib == "sky130_scl": + spice_file = None + else: + spice_file = os.path.join(SKYWATER_LIBS, "cdl", file_lib + ".cdl") + elif "sky130_ef_io" in cell_name: + file_lib = "sky130_ef_io" + gds_file = file_lib + ".gds" + lef_file = os.path.join( + SKY130A, "libs.ref", library, "lef", "sky130_ef_io.lef" + ) + if self.get_setting("vlsi.core.lvs_tool") == "hammer.lvs.pegasus" and slib == "sky130_scl": + spice_file = None + else: + spice_file = os.path.join(SKYWATER_LIBS, "cdl", file_lib + ".cdl") + else: + if "sky130_fd_io" in cell_name and self.get_setting("vlsi.core.lvs_tool") == "hammer.lvs.pegasus" : + # going to blackbox these + spice_file = None + else: + spice_file = os.path.join( + SKYWATER_LIBS, "spice", file_lib + ".spice" + ) + file_lib = library + gds_file = file_lib + ".gds" + lef_file = os.path.join(SKYWATER_LIBS, "lef", file_lib + ".lef") + + lib_entry = Library( + nldm_liberty_file=os.path.join( + SKYWATER_LIBS, "lib", cornerfilename + ), + verilog_sim=os.path.join(SKYWATER_LIBS, "verilog", file_lib + ".v"), + lef_file=lef_file, + spice_file=spice_file, + gds_file=os.path.join(SKYWATER_LIBS, "gds", gds_file), + corner=Corner(nmos=speed, pmos=speed, temperature=temp), + supplies=Supplies(VDD=vdd, GND="0 V"), + provides=[Provide(lib_type=cell_name, vt="RVT")], + ) + libs.append(lib_entry) + + # Stdcell library-dependent lists + stackups = [] # type: List[Stackup] + phys_only = [] # type: List[Cell] + dont_use = [] # type: List[Cell] + spcl_cells = [] # type: List[SpecialCell] + + # Select standard cell libraries + if slib == "sky130_fd_sc_hd": + + phys_only = [ + "sky130_fd_sc_hd__tap_1", + "sky130_fd_sc_hd__tap_2", + "sky130_fd_sc_hd__tapvgnd_1", + "sky130_fd_sc_hd__tapvpwrvgnd_1", + "sky130_fd_sc_hd__fill_1", + "sky130_fd_sc_hd__fill_2", + "sky130_fd_sc_hd__fill_4", + "sky130_fd_sc_hd__fill_8", + "sky130_fd_sc_hd__diode_2", + ] + dont_use = [ + "*sdf*", + "sky130_fd_sc_hd__probe_p_*", + "sky130_fd_sc_hd__probec_p_*", + ] + spcl_cells = [ + # for now, skipping the tiecell step. I think the extracted verilog netlist is ignoring the tiecells which is causing lvs issues + SpecialCell( + cell_type=CellType("tiehilocell"), name=["sky130_fd_sc_hd__conb_1"] + ), + SpecialCell( + cell_type=CellType("tiehicell"), + name=["sky130_fd_sc_hd__conb_1"], + output_ports=["HI"], + ), + SpecialCell( + cell_type=CellType("tielocell"), + name=["sky130_fd_sc_hd__conb_1"], + output_ports=["LO"], + ), + SpecialCell( + cell_type=CellType("endcap"), name=["sky130_fd_sc_hd__tap_1"] + ), + SpecialCell( + cell_type=CellType("tapcell"), + name=["sky130_fd_sc_hd__tapvpwrvgnd_1"], + ), + SpecialCell( + cell_type=CellType("stdfiller"), + name=[ + "sky130_fd_sc_hd__fill_1", + "sky130_fd_sc_hd__fill_2", + "sky130_fd_sc_hd__fill_4", + "sky130_fd_sc_hd__fill_8", + ], + ), + SpecialCell( + cell_type=CellType("decap"), + name=[ + "sky130_fd_sc_hd__decap_3", + "sky130_fd_sc_hd__decap_4", + "sky130_fd_sc_hd__decap_6", + "sky130_fd_sc_hd__decap_8", + "sky130_fd_sc_hd__decap_12", + ], + ), + SpecialCell( + cell_type=CellType("driver"), + name=["sky130_fd_sc_hd__buf_4"], + input_ports=["A"], + output_ports=["X"], + ), + SpecialCell( + cell_type=CellType("ctsbuffer"), name=["sky130_fd_sc_hd__clkbuf_1"] + ), + ] + + # Generate standard cell library + library = slib + + # scl vs 130a have different site names + sites = None + + SKYWATER_LIBS = os.path.join("$SKY130A", "libs.ref", library) + LIBRARY_PATH = os.path.join(SKY130A, "libs.ref", library, "lib") + lib_corner_files = os.listdir(LIBRARY_PATH) + lib_corner_files.sort() + for cornerfilename in lib_corner_files: + if not ( + "sky130" in cornerfilename + ): # cadence doesn't use the lib name in their corner libs + continue + if "ccsnoise" in cornerfilename: + continue # ignore duplicate corner.lib/corner_ccsnoise.lib files + + tmp = cornerfilename.replace(".lib", "") + if tmp + "_ccsnoise.lib" in lib_corner_files: + cornerfilename = ( + tmp + "_ccsnoise.lib" + ) # use ccsnoise version of lib file + + cornername = tmp.split("__")[1] + cornerparts = cornername.split("_") + + speed = cornerparts[0] + if speed == "ff": + speed = "fast" + if speed == "tt": + speed = "typical" + if speed == "ss": + speed = "slow" + + temp = cornerparts[1] + temp = temp.replace("n", "-") + temp = temp.split("C")[0] + " C" + + vdd = cornerparts[2] + vdd = vdd.split("v")[0] + "." + vdd.split("v")[1] + " V" + + lib_entry = Library( + nldm_liberty_file=os.path.join( + SKYWATER_LIBS, "lib", cornerfilename + ), + verilog_sim=os.path.join("cache", library + ".v"), + lef_file=os.path.join(SKYWATER_LIBS, "lef", library + ".lef"), + spice_file=os.path.join("cache", library + ".cdl"), + gds_file=os.path.join(SKYWATER_LIBS, "gds", library + ".gds"), + corner=Corner(nmos=speed, pmos=speed, temperature=temp), + supplies=Supplies(VDD=vdd, GND="0 V"), + provides=[Provide(lib_type="stdcell", vt="RVT")], + ) + + libs.append(lib_entry) + + # Generate stackup + tlef_path = os.path.join( + SKY130A, "libs.ref", library, "techlef", f"{library}__min.tlef" + ) + metals = list( + map(lambda m: Metal.model_validate(m), LEFUtils.get_metals(tlef_path)) + ) + stackups.append( + Stackup(name=slib, grid_unit=Decimal("0.001"), metals=metals) + ) + + sites = [ + Site(name="unithd", x=Decimal("0.46"), y=Decimal("2.72")), + Site(name="unithddbl", x=Decimal("0.46"), y=Decimal("5.44")), + ] + lvs_decks = [ + LVSDeck( + tool_name="calibre", + deck_name="calibre_lvs", + path="$SKY130_NDA/s8/V2.0.1/LVS/Calibre/lvsRules_s8", + ), + LVSDeck( + tool_name="pegasus", + deck_name="pegasus_lvs", + path="$SKY130_CDS/Sky130_LVS/sky130.lvs.pvl", + ), + ] + drc_decks = ( + [ + DRCDeck( + tool_name="calibre", + deck_name="calibre_drc", + path="$SKY130_NDA/s8/V2.0.1/DRC/Calibre/s8_drcRules", + ), + DRCDeck( + tool_name="klayout", + deck_name="klayout_drc", + path="$SKY130A/libs.tech/klayout/drc/sky130A.lydrc", + ), + DRCDeck( + tool_name="pegasus", + deck_name="pegasus_drc", + path="$SKY130_CDS/Sky130_DRC/sky130_rev_0.0_1.0.drc.pvl", + ), + ] + ) + + elif slib == "sky130_scl": + + # The cadence PDK (as of version 0.0.3) doesn't seem to have tap nor decap cells, so par won't run (and if we forced it to, lvs would fail) + spcl_cells = [ + SpecialCell( + cell_type="stdfiller", name=[f"FILL{i**2}" for i in range(7)] + ), + SpecialCell( + cell_type="driver", + name=["TBUFX1", "TBUFX4", "TBUFX8"], + input_ports=["A"], + output_ports=["Y"], + ), + SpecialCell(cell_type="ctsbuffer", name=["CLKBUFX2","CLKBUFX4", "CLKBUFX8" ]), + SpecialCell(cell_type=CellType("ctsgate"), name=["ICGX1"]), + SpecialCell( + cell_type=CellType("tiehicell"), name=["TIEHI"], input_ports=["Y"] + ), + SpecialCell( + cell_type=CellType("tielocell"), name=["TIELO"], input_ports=["Y"] + ), + ] + + # Generate standard cell library + library = slib + + LIBRARY_PATH = os.path.join(SKY130_CDS_LIB, "lib") + lib_corner_files = os.listdir(LIBRARY_PATH) + lib_corner_files.sort() + for cornerfilename in lib_corner_files: + if not ( + "sky130" in cornerfilename + ): # cadence doesn't use the lib name in their corner libs + continue + if "ccsnoise" in cornerfilename: + continue # ignore duplicate corner.lib/corner_ccsnoise.lib files + + tmp = cornerfilename.replace(".lib", "") + if tmp + "_ccsnoise.lib" in lib_corner_files: + cornerfilename = ( + tmp + "_ccsnoise.lib" + ) # use ccsnoise version of lib file + + cornername = tmp.replace("sky130_", "") + cornerparts = cornername.split("_") + + # Hardcode corner annotations since they don't exactly match the sky130a + speed = cornerparts[0] + vdd = "" + temp = "" + if speed == "ff": + temp = "-40 C" + vdd = "1.95 V" + speed = "fast" + if speed == "tt": + vdd = "1.80 V" + temp = "25 C" + speed = "typical" + if speed == "ss": + vdd = "1.60 V" + speed = "slow" + temp = "100 C" + + lib_entry = Library( + nldm_liberty_file=os.path.join( + SKY130_CDS_LIB, "lib", cornerfilename + ), + verilog_sim=os.path.join( + SKY130_CDS_LIB, "verilog", library + "_9T.v" + ), + lef_file=os.path.join(SKY130_CDS_LIB, "lef", library + "_9T.lef"), + spice_file=os.path.join(SKY130_CDS_LIB, "cdl", library + "_9T.cdl"), + gds_file=os.path.join(SKY130_CDS_LIB, "gds", library + "_9T.gds"), + corner=Corner(nmos=speed, pmos=speed, temperature=temp), + supplies=Supplies(VDD=vdd, GND="0 V"), + provides=[Provide(lib_type="stdcell", vt="RVT")], + ) + + libs.append(lib_entry) + + # Generate stackup + metals = [] # type: List[Metal] + + tlef_path = os.path.join(SKY130_CDS_LIB, "lef", f"{slib}_9T.tlef") + metals = list( + map(lambda m: Metal.model_validate(m), LEFUtils.get_metals(tlef_path)) + ) + stackups.append( + Stackup(name=slib, grid_unit=Decimal("0.001"), metals=metals) + ) + + sites = [ + Site(name="CoreSite", x=Decimal("0.46"), y=Decimal("4.14")), + Site(name="IOSite", x=Decimal("1.0"), y=Decimal("240.0")), + Site(name="CornerSite", x=Decimal("240.0"), y=Decimal("240.0")), + ] + + lvs_decks = [ + # LVSDeck(tool_name="calibre", deck_name="calibre_lvs", + # path="$SKY130_NDA/s8/V2.0.1/LVS/Calibre/lvsRules_s8"), + # seems like cadence just hasthis hardcoded lvs deck name? + LVSDeck( + tool_name="pegasus", + deck_name="pegasus_lvs", + path=os.path.join(SKY130_CDS, "Sky130_LVS", "sky130.lvs.pvl"), + ) + ] + drc_decks = [ + DRCDeck( + tool_name="pegasus", + deck_name="pegasus_drc", + path=os.path.join( + SKY130_CDS, "Sky130_DRC", "sky130_rev_0.0_1.0.drc.pvl" + ), + ) + ] + + else: + raise ValueError(f"Incorrect standard cell library selection: {slib}") + + self.config = TechJSON( + name="Skywater 130nm Library", + grid_unit="0.001", + shrink_factor=None, + installs=[ + PathPrefix(id="$SKY130_NDA", path="technology.sky130.sky130_nda"), + PathPrefix(id="$SKY130A", path="technology.sky130.sky130A"), + PathPrefix(id="$SKY130_CDS", path="technology.sky130.sky130_cds"), + PathPrefix(id="$SKY130_SCL", path="technology.sky130.sky130_scl"), + ], + libraries=libs, + gds_map_file="sky130_lefpin.map", + physical_only_cells_list=phys_only, + dont_use_list=dont_use, + additional_drc_text="", + lvs_decks=lvs_decks, + drc_decks=drc_decks, + additional_lvs_text="", + tarballs=None, + sites=sites, + stackups=stackups, + special_cells=spcl_cells, + extra_prefixes=None, + ) + def post_install_script(self) -> None: - self.library_name = 'sky130_fd_sc_hd' + self.library_name = "sky130_fd_sc_hd" # check whether variables were overriden to point to a valid path - self.use_sram22 = os.path.exists(self.get_setting("technology.sky130.sram22_sky130_macros")) - self.setup_cdl() - self.setup_verilog() + self.use_sram22 = os.path.exists( + self.get_setting("technology.sky130.sram22_sky130_macros") + ) + if self.get_setting("technology.sky130.stdcell_library") == "sky130_fd_sc_hd": + self.setup_cdl() + # self.setup_verilog() self.setup_techlef() - self.setup_io_lefs() - self.logger.info('Loaded Sky130 Tech') - + self.logger.info("Loaded Sky130 Tech") def setup_cdl(self) -> None: - ''' Copy and hack the cdl, replacing pfet_01v8_hvt/nfet_01v8 with - respective names in LVS deck - ''' + """Copy and hack the cdl, replacing pfet_01v8_hvt/nfet_01v8 with + respective names in LVS deck + """ setting_dir = self.get_setting("technology.sky130.sky130A") setting_dir = Path(setting_dir) - source_path = setting_dir / 'libs.ref' / self.library_name / 'cdl' / f'{self.library_name}.cdl' + source_path = ( + setting_dir + / "libs.ref" + / self.library_name + / "cdl" + / f"{self.library_name}.cdl" + ) if not source_path.exists(): raise FileNotFoundError(f"CDL not found: {source_path}") cache_tech_dir_path = Path(self.cache_dir) os.makedirs(cache_tech_dir_path, exist_ok=True) - dest_path = cache_tech_dir_path / f'{self.library_name}.cdl' + dest_path = cache_tech_dir_path / f"{self.library_name}.cdl" # device names expected in LVS decks - pmos = 'pfet_01v8_hvt' - nmos = 'nfet_01v8' - if (self.get_setting('vlsi.core.lvs_tool') == "hammer.lvs.calibre"): - pmos = 'phighvt' - nmos = 'nshort' - elif (self.get_setting('vlsi.core.lvs_tool') == "hammer.lvs.netgen"): - pmos = 'sky130_fd_pr__pfet_01v8_hvt' - nmos = 'sky130_fd_pr__nfet_01v8' - - with open(source_path, 'r') as sf: - with open(dest_path, 'w') as df: - self.logger.info("Modifying CDL netlist: {} -> {}".format - (source_path, dest_path)) + pmos = "pfet_01v8_hvt" + nmos = "nfet_01v8" + if self.get_setting("vlsi.core.lvs_tool") == "hammer.lvs.calibre": + pmos = "phighvt" + nmos = "nshort" + elif self.get_setting("vlsi.core.lvs_tool") == "hammer.lvs.netgen": + pmos = "sky130_fd_pr__pfet_01v8_hvt" + nmos = "sky130_fd_pr__nfet_01v8" + + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying CDL netlist: {} -> {}".format(source_path, dest_path) + ) df.write("*.SCALE MICRON\n") for line in sf: - line = line.replace('pfet_01v8_hvt', pmos) - line = line.replace('nfet_01v8' , nmos) + line = line.replace("pfet_01v8_hvt", pmos) + line = line.replace("nfet_01v8", nmos) df.write(line) # Copy and hack the verilog @@ -78,223 +554,341 @@ def setup_verilog(self) -> None: setting_dir = Path(setting_dir) # .v - source_path = setting_dir / 'libs.ref' / self.library_name / 'verilog' / f'{self.library_name}.v' + source_path = ( + setting_dir + / "libs.ref" + / self.library_name + / "verilog" + / f"{self.library_name}.v" + ) if not source_path.exists(): raise FileNotFoundError(f"Verilog not found: {source_path}") cache_tech_dir_path = Path(self.cache_dir) os.makedirs(cache_tech_dir_path, exist_ok=True) - dest_path = cache_tech_dir_path / f'{self.library_name}.v' + dest_path = cache_tech_dir_path / f"{self.library_name}.v" - with open(source_path, 'r') as sf: - with open(dest_path, 'w') as df: - self.logger.info("Modifying Verilog netlist: {} -> {}".format - (source_path, dest_path)) + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying Verilog netlist: {} -> {}".format(source_path, dest_path) + ) for line in sf: - line = line.replace('wire 1','// wire 1') - line = line.replace('`endif SKY130_FD_SC_HD__LPFLOW_BLEEDER_FUNCTIONAL_V','`endif // SKY130_FD_SC_HD__LPFLOW_BLEEDER_FUNCTIONAL_V') + line = line.replace("wire 1", "// wire 1") + line = line.replace( + "`endif SKY130_FD_SC_HD__LPFLOW_BLEEDER_FUNCTIONAL_V", + "`endif // SKY130_FD_SC_HD__LPFLOW_BLEEDER_FUNCTIONAL_V", + ) df.write(line) - + # Additionally hack out the specifies sl = [] - with open(dest_path, 'r') as sf: + with open(dest_path, "r") as sf: sl = sf.readlines() # Find timing declaration - start_idx = [idx for idx, line in enumerate(sl) if "`ifndef SKY130_FD_SC_HD__LPFLOW_BLEEDER_1_TIMING_V" in line][0] + start_idx = [ + idx + for idx, line in enumerate(sl) + if "`ifndef SKY130_FD_SC_HD__LPFLOW_BLEEDER_1_TIMING_V" in line + ][0] # Search for the broken statement - search_range = range(start_idx+1, len(sl)) - broken_specify_idx = len(sl)-1 + search_range = range(start_idx + 1, len(sl)) + broken_specify_idx = len(sl) - 1 broken_substr = "(SHORT => VPWR) = (0:0:0,0:0:0,0:0:0,0:0:0,0:0:0,0:0:0);" - broken_specify_idx = [idx for idx in search_range if broken_substr in sl[idx]][0] + broken_specify_idx = [ + idx for idx in search_range if broken_substr in sl[idx] + ][0] endif_idx = [idx for idx in search_range if "`endif" in sl[idx]][0] # Now, delete all the specify statements if specify exists before an endif. if broken_specify_idx < endif_idx: self.logger.info("Removing incorrectly formed specify block.") - cell_def_range = range(start_idx+1, endif_idx) - start_specify_idx = [idx for idx in cell_def_range if "specify" in sl[idx]][0] - end_specify_idx = [idx for idx in cell_def_range if "endspecify" in sl[idx]][0] - sl[start_specify_idx:end_specify_idx+1] = [] # Dice + cell_def_range = range(start_idx + 1, endif_idx) + start_specify_idx = [ + idx for idx in cell_def_range if "specify" in sl[idx] + ][0] + end_specify_idx = [ + idx for idx in cell_def_range if "endspecify" in sl[idx] + ][0] + sl[start_specify_idx : end_specify_idx + 1] = [] # Dice # Deal with the nonexistent net tactfully (don't code in brittle replacements) self.logger.info("Fixing broken net references with select specify blocks.") pattern = r"^\s*wire SLEEP.*B.*delayed;" capture_pattern = r".*(SLEEP.*?B.*?delayed).*" - pattern_idx = [(idx, re.findall(capture_pattern, value)[0]) for idx, value in enumerate(sl) if re.search(pattern, value)] + pattern_idx = [ + (idx, re.findall(capture_pattern, value)[0]) + for idx, value in enumerate(sl) + if re.search(pattern, value) + ] for list_idx, pattern_tuple in enumerate(pattern_idx): - if list_idx != len(pattern_idx)-1: - search_range = range(pattern_tuple[0]+1, pattern_idx[list_idx+1][0]) - else: - search_range = range(pattern_tuple[0]+1, len(sl)) + if list_idx != len(pattern_idx) - 1: + search_range = range(pattern_tuple[0] + 1, pattern_idx[list_idx + 1][0]) + else: + search_range = range(pattern_tuple[0] + 1, len(sl)) for idx in search_range: list = re.findall(capture_pattern, sl[idx]) for elem in list: if elem != pattern_tuple[1]: sl[idx] = sl[idx].replace(elem, pattern_tuple[1]) - self.logger.info(f"Incorrect reference `{elem}` to be replaced with: `{pattern_tuple[1]}` on raw line {idx}.") - - # Write back into destination - with open(dest_path, 'w') as df: + self.logger.info( + f"Incorrect reference `{elem}` to be replaced with: `{pattern_tuple[1]}` on raw line {idx}." + ) + + # Write back into destination + with open(dest_path, "w") as df: df.writelines(sl) # primitives.v - source_path = setting_dir / 'libs.ref' / self.library_name / 'verilog' / 'primitives.v' + source_path = ( + setting_dir / "libs.ref" / self.library_name / "verilog" / "primitives.v" + ) if not source_path.exists(): raise FileNotFoundError(f"Verilog not found: {source_path}") cache_tech_dir_path = Path(self.cache_dir) os.makedirs(cache_tech_dir_path, exist_ok=True) - dest_path = cache_tech_dir_path / 'primitives.v' + dest_path = cache_tech_dir_path / "primitives.v" - with open(source_path, 'r') as sf: - with open(dest_path, 'w') as df: - self.logger.info("Modifying Verilog netlist: {} -> {}".format - (source_path, dest_path)) + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying Verilog netlist: {} -> {}".format(source_path, dest_path) + ) for line in sf: - line = line.replace('`default_nettype none','`default_nettype wire') + line = line.replace( + "`default_nettype none", "`default_nettype wire" + ) df.write(line) # Copy and hack the tech-lef, adding this very important `licon` section def setup_techlef(self) -> None: - setting_dir = self.get_setting("technology.sky130.sky130A") - setting_dir = Path(setting_dir) - source_path = setting_dir / 'libs.ref' / self.library_name / 'techlef' / f'{self.library_name}__nom.tlef' + cache_tech_dir_path = Path(self.cache_dir) + os.makedirs(cache_tech_dir_path, exist_ok=True) + if self.get_setting("technology.sky130.stdcell_library") == "sky130_fd_sc_hd": + setting_dir = self.get_setting("technology.sky130.sky130A") + setting_dir = Path(setting_dir) + source_path = ( + setting_dir + / "libs.ref" + / self.library_name + / "techlef" + / f"{self.library_name}__nom.tlef" + ) + dest_path = cache_tech_dir_path / f"{self.library_name}__nom.tlef" + else: + setting_dir = self.get_setting("technology.sky130.sky130_scl") + setting_dir = Path(setting_dir) + source_path = ( + setting_dir + / "lef" + / "sky130_scl_9T.tlef" + ) + dest_path = cache_tech_dir_path / "sky130_scl_9T.tlef" if not source_path.exists(): raise FileNotFoundError(f"Tech-LEF not found: {source_path}") - cache_tech_dir_path = Path(self.cache_dir) - os.makedirs(cache_tech_dir_path, exist_ok=True) - dest_path = cache_tech_dir_path / f'{self.library_name}__nom.tlef' - with open(source_path, 'r') as sf: - with open(dest_path, 'w') as df: - self.logger.info("Modifying Technology LEF: {} -> {}".format - (source_path, dest_path)) + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying Technology LEF: {} -> {}".format(source_path, dest_path) + ) for line in sf: df.write(line) - if line.strip() == 'END pwell': - df.write(_the_tlef_edit) - - # Power pins for clamps must be CLASS CORE - # connect/disconnect spacers must be CLASS PAD SPACER, not AREAIO - # Current version has two errors in MACRO class definitions that break lef parser. - def setup_io_lefs(self) -> None: - sky130A_path = Path(self.get_setting('technology.sky130.sky130A')) - source_path = sky130A_path / 'libs.ref' / 'sky130_fd_io' / 'lef' / 'sky130_ef_io.lef' - if not source_path.exists(): - raise FileNotFoundError(f"IO LEF not found: {source_path}") + if self.get_setting("technology.sky130.stdcell_library") == "sky130_scl": + if line.strip() == "END poly": + df.write(_the_tlef_edit + _additional_tlef_edit_for_scl) + else: + if line.strip() == "END pwell": + df.write(_the_tlef_edit) + + # syn_power seems to not take hooks from `get_tech_syn_hooks` + # also, syn_power is called from joules so we need to add the hook to joules + # TODO: clean this up, there should be a way to always include this hook whenever genus will be invoked + def get_tech_power_hooks(self, tool_name: str) -> List[HammerToolHookAction]: + hooks = {} + + def enable_scl_clk_gating_cell_hook(ht: HammerTool) -> bool: + ht.append( + "set_db [get_db lib_cells -if {.base_name == ICGX1}] .avoid false" + ) + return True + + # The clock gating cell is set to don't touch/use in the cadence pdk (as of v0.0.3), work around that + if self.get_setting("technology.sky130.stdcell_library") == "sky130_scl": + hooks["joules"] = [ + HammerTool.make_pre_insertion_hook( + "synthesize_design", enable_scl_clk_gating_cell_hook + ) + ] - cache_tech_dir_path = Path(self.cache_dir) - os.makedirs(cache_tech_dir_path, exist_ok=True) - dest_path = cache_tech_dir_path / 'sky130_ef_io.lef' - - with open(source_path, 'r') as sf: - with open(dest_path, 'w') as df: - self.logger.info("Modifying IO LEF: {} -> {}".format - (source_path, dest_path)) - sl = sf.readlines() - for net in ['VCCD1', 'VSSD1']: - start = [idx for idx,line in enumerate(sl) if 'PIN ' + net in line] - end = [idx for idx,line in enumerate(sl) if 'END ' + net in line] - intervals = zip(start, end) - for intv in intervals: - port_idx = [idx for idx,line in enumerate(sl[intv[0]:intv[1]]) if 'PORT' in line] - for idx in port_idx: - sl[intv[0]+idx]=sl[intv[0]+idx].replace('PORT', 'PORT\n CLASS CORE ;') - for cell in [ - 'sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um', - 'sky130_ef_io__disconnect_vccd_slice_5um', - 'sky130_ef_io__disconnect_vdda_slice_5um', - ]: - # force class to spacer - start = [idx for idx, line in enumerate(sl) if f'MACRO {cell}' in line] - sl[start[0] + 1] = sl[start[0] + 1].replace('AREAIO', 'SPACER') - - # Current version has two one-off error that break lef parser. - self.logger.info("Fixing broken sky130_ef_io__analog_esd_pad LEF definition.") - start_broken_macro_list = ["MACRO sky130_ef_io__analog_esd_pad\n", "MACRO sky130_ef_io__analog_pad\n"] - end_broken_macro_list = ["END sky130_ef_io__analog_pad\n", "END sky130_ef_io__analog_noesd_pad\n"] - end_fixed_macro_list = ["END sky130_ef_io__analog_esd_pad\n", "END sky130_ef_io__analog_pad\n"] - - for start_broken_macro, end_broken_macro, end_fixed_macro in zip(start_broken_macro_list, end_broken_macro_list, end_fixed_macro_list): - # Get all start indices to be checked - start_check_indices = [idx for idx, line in enumerate(sl) if line == start_broken_macro] - - # Extract broken macro - for idx_broken_macro in start_check_indices: - # Find the start of the next_macro - idx_start_next_macro = [idx for idx in range(idx_broken_macro+1, len(sl)) if "MACRO" in sl[idx]][0] - # Find the broken macro ending - idx_end_broken_macro = len(sl) - idx_end_broken_macro = [idx for idx in range(idx_broken_macro+1, len(sl)) if end_broken_macro in sl[idx]][0] - - # Fix - if idx_end_broken_macro < idx_start_next_macro: - sl[idx_end_broken_macro] = end_fixed_macro - - df.writelines(sl) + return hooks.get(tool_name, []) + + def get_tech_syn_hooks(self, tool_name: str) -> List[HammerToolHookAction]: + hooks = {} + + def enable_scl_clk_gating_cell_hook(ht: HammerTool) -> bool: + ht.append( + "set_db [get_db lib_cells -if {.base_name == ICGX1}] .avoid false" + ) + return True + + # The clock gating cell is set to don't touch/use in the cadence pdk (as of v0.0.3), work around that + if self.get_setting("technology.sky130.stdcell_library") == "sky130_scl": + hooks["genus"] = [ + HammerTool.make_pre_insertion_hook( + "syn_generic", enable_scl_clk_gating_cell_hook + ) + ] + + # seems to mess up lvs for now + # hooks['genus'].append(HammerTool.make_removal_hook("add_tieoffs")) + return hooks.get(tool_name, []) def get_tech_par_hooks(self, tool_name: str) -> List[HammerToolHookAction]: hooks = { "innovus": [ - HammerTool.make_post_insertion_hook("init_design", sky130_innovus_settings), - HammerTool.make_pre_insertion_hook("place_tap_cells", sky130_add_endcaps), - HammerTool.make_pre_insertion_hook("power_straps", sky130_connect_nets), - HammerTool.make_pre_insertion_hook("write_design", sky130_connect_nets2) - ]} + HammerTool.make_post_insertion_hook( + "init_design", sky130_innovus_settings + ), + HammerTool.make_pre_insertion_hook("power_straps", sky130_connect_nets), + HammerTool.make_pre_insertion_hook( + "write_design", sky130_connect_nets2 + ), + ] + } + # there are no cap/decap cells in the cadence stdcell library as of version 0.0.3, so we can't do things that reference them + if self.get_setting("technology.sky130.stdcell_library") == "sky130_scl": + + hooks["innovus"].append( + HammerTool.make_replacement_hook( + "power_straps", power_rail_straps_no_tapcells + ) + ) + else: + hooks["innovus"].append( + HammerTool.make_pre_insertion_hook( + "place_tap_cells", sky130_add_endcaps + ) + ) + return hooks.get(tool_name, []) def get_tech_drc_hooks(self, tool_name: str) -> List[HammerToolHookAction]: calibre_hooks = [] pegasus_hooks = [] if self.get_setting("technology.sky130.drc_blackbox_srams"): - calibre_hooks.append(HammerTool.make_post_insertion_hook("generate_drc_run_file", calibre_drc_blackbox_srams)) - pegasus_hooks.append(HammerTool.make_post_insertion_hook("generate_drc_ctl_file", pegasus_drc_blackbox_srams)) - hooks = {"calibre": calibre_hooks, - "pegasus": pegasus_hooks - } + calibre_hooks.append( + HammerTool.make_post_insertion_hook( + "generate_drc_run_file", calibre_drc_blackbox_srams + ) + ) + pegasus_hooks.append( + HammerTool.make_post_insertion_hook( + "generate_drc_ctl_file", pegasus_drc_blackbox_srams + ) + ) + hooks = {"calibre": calibre_hooks, "pegasus": pegasus_hooks} return hooks.get(tool_name, []) def get_tech_lvs_hooks(self, tool_name: str) -> List[HammerToolHookAction]: - calibre_hooks = [HammerTool.make_post_insertion_hook("generate_lvs_run_file", setup_calibre_lvs_deck)] + calibre_hooks = [ + HammerTool.make_post_insertion_hook( + "generate_lvs_run_file", setup_calibre_lvs_deck + ) + ] pegasus_hooks = [] if self.use_sram22: - calibre_hooks.append(HammerTool.make_post_insertion_hook("generate_lvs_run_file", sram22_lvs_recognize_gates_all)) + calibre_hooks.append( + HammerTool.make_post_insertion_hook( + "generate_lvs_run_file", sram22_lvs_recognize_gates_all + ) + ) if self.get_setting("technology.sky130.lvs_blackbox_srams"): - calibre_hooks.append(HammerTool.make_post_insertion_hook("generate_lvs_run_file", calibre_lvs_blackbox_srams)) - pegasus_hooks.append(HammerTool.make_post_insertion_hook("generate_lvs_ctl_file", pegasus_lvs_blackbox_srams)) - hooks = {"calibre": calibre_hooks, - "pegasus": pegasus_hooks - } + calibre_hooks.append( + HammerTool.make_post_insertion_hook( + "generate_lvs_run_file", calibre_lvs_blackbox_srams + ) + ) + pegasus_hooks.append( + HammerTool.make_post_insertion_hook( + "generate_lvs_ctl_file", pegasus_lvs_blackbox_srams + ) + ) + + if self.get_setting("technology.sky130.stdcell_library") == "sky130_scl": + pegasus_hooks.append( + HammerTool.make_post_insertion_hook( + "generate_lvs_ctl_file", pegasus_lvs_add_130a_primitives + ) + ) + hooks = {"calibre": calibre_hooks, "pegasus": pegasus_hooks} return hooks.get(tool_name, []) @staticmethod def openram_sram_names() -> List[str]: - """ Return a list of cell-names of the OpenRAM SRAMs (that we'll use). """ + """Return a list of cell-names of the OpenRAM SRAMs (that we'll use).""" return [ "sky130_sram_1kbyte_1rw1r_32x256_8", "sky130_sram_1kbyte_1rw1r_8x1024_8", - "sky130_sram_2kbyte_1rw1r_32x512_8" + "sky130_sram_2kbyte_1rw1r_32x512_8", ] + @staticmethod + def sky130_sram_primitive_names() -> List[str]: + spice_filenames = [ + "sky130_fd_pr__pfet_01v8", + "sky130_fd_pr__nfet_01v8", + "sky130_fd_pr__pfet_01v8_hvt", + "sky130_fd_pr__special_nfet_latch", + "sky130_fd_pr__special_nfet_pass", + ] # "sky130_fd_pr__special_pfet_latch", ] + paths = [] + for fname in spice_filenames: + paths.append( + f"/tools/commercial/skywater/local/sky130A/libs.ref/sky130_fd_pr/spice/{fname}.pm3.spice" + ) + # TODO: this is bc line 535 in the bwrc one causes a syntax error + paths.append( + "/tools/C/elamdf/chipyard_dev/vlsi/sky130_fd_pr__special_pfet_latch.pm3.spice" + ) + return paths + @staticmethod def sky130_sram_names() -> List[str]: sky130_sram_names = [] - sram_cache_json = importlib.resources.files("hammer.technology.sky130").joinpath("sram-cache.json").read_text() + sram_cache_json = ( + importlib.resources.files("hammer.technology.sky130") + .joinpath("sram-cache.json") + .read_text() + ) dl = json.loads(sram_cache_json) for d in dl: - sky130_sram_names.append(d['name']) + sky130_sram_names.append(d["name"]) return sky130_sram_names -_the_tlef_edit = ''' +# the io libs (sky130a) +_the_tlef_edit = """ LAYER licon TYPE CUT ; END licon -''' +""" +_additional_tlef_edit_for_scl = """" +LAYER nwell + TYPE MASTERSLICE ; +END nwell +LAYER pwell + TYPE MASTERSLICE ; +END pwell +LAYER li1 + TYPE MASTERSLICE ; +END li1 +""" # various Innovus database settings @@ -303,7 +897,7 @@ def sky130_innovus_settings(ht: HammerTool) -> bool: assert isinstance(ht, TCLTool), "innovus settings can only run on TCL tools" """Settings for every tool invocation""" ht.append( - ''' + f""" ########################################################## # Placement attributes [get_db -category place] @@ -343,8 +937,10 @@ def sky130_innovus_settings(ht: HammerTool) -> bool: # Routing attributes [get_db -category route] ########################################################## #------------------------------------------------------------------------------- -set_db route_design_antenna_diode_insertion 1 -set_db route_design_antenna_cell_name "sky130_fd_sc_hd__diode_2" +puts "WARNING ELAM ELAM ELAM REMOVING ANTENNA DIODES FOR NOW BC THEY BREAK LVS and ARE NOT DRC CLEAN WITH CADENCE STDCELLS REMOVE MEEEEE" +set_db route_design_antenna_diode_insertion 0 +#set_db route_design_antenna_diode_insertion 1 +#set_db route_design_antenna_cell_name "{"sky130_fd_sc_hd__diode_2" if ht.get_setting("technology.sky130.stdcell_library") == "sky130_fd_sc_hd" else "ANTENNA"}" set_db route_design_high_freq_search_repair true set_db route_design_detail_post_route_spread_wire true @@ -353,26 +949,37 @@ def sky130_innovus_settings(ht: HammerTool) -> bool: set_db route_design_concurrent_minimize_via_count_effort high set_db opt_consider_routing_congestion true set_db route_design_detail_use_multi_cut_via_effort medium - ''' + """ ) if ht.hierarchical_mode in {HierarchicalMode.Top, HierarchicalMode.Flat}: ht.append( - ''' + """ # For top module: snap die to manufacturing grid, not placement grid set_db floorplan_snap_die_grid manufacturing - ''' + """ ) + return True + def sky130_connect_nets(ht: HammerTool) -> bool: assert isinstance(ht, HammerPlaceAndRouteTool), "connect global nets only for par" assert isinstance(ht, TCLTool), "connect global nets can only run on TCL tools" - for pwr_gnd_net in (ht.get_all_power_nets() + ht.get_all_ground_nets()): - if pwr_gnd_net.tie is not None: - ht.append("connect_global_net {tie} -type pg_pin -pin_base_name {net} -all -auto_tie -netlist_override".format(tie=pwr_gnd_net.tie, net=pwr_gnd_net.name)) - ht.append("connect_global_net {tie} -type net -net_base_name {net} -all -netlist_override".format(tie=pwr_gnd_net.tie, net=pwr_gnd_net.name)) + for pwr_gnd_net in ht.get_all_power_nets() + ht.get_all_ground_nets(): + if pwr_gnd_net.tie is not None: + ht.append( + "connect_global_net {tie} -type pg_pin -pin_base_name {net} -all -auto_tie -netlist_override".format( + tie=pwr_gnd_net.tie, net=pwr_gnd_net.name + ) + ) + ht.append( + "connect_global_net {tie} -type net -net_base_name {net} -all -netlist_override".format( + tie=pwr_gnd_net.tie, net=pwr_gnd_net.name + ) + ) return True + # Pair VDD/VPWR and VSS/VGND nets # these commands are already added in Innovus.write_netlist, # but must also occur before power straps are placed @@ -384,18 +991,19 @@ def sky130_connect_nets2(ht: HammerTool) -> bool: def sky130_add_endcaps(ht: HammerTool) -> bool: assert isinstance(ht, HammerPlaceAndRouteTool), "endcap insertion only for par" assert isinstance(ht, TCLTool), "endcap insertion can only run on TCL tools" - endcap_cells=ht.technology.get_special_cell_by_type(CellType.EndCap) - endcap_cell=endcap_cells[0].name[0] + endcap_cells = ht.technology.get_special_cell_by_type(CellType.EndCap) + endcap_cell = endcap_cells[0].name[0] ht.append( - f''' + f""" set_db add_endcaps_boundary_tap true set_db add_endcaps_left_edge {endcap_cell} set_db add_endcaps_right_edge {endcap_cell} add_endcaps - ''' + """ ) return True + def efabless_ring_io(ht: HammerTool) -> bool: assert isinstance(ht, HammerPlaceAndRouteTool), "IO ring instantiation only for par" assert isinstance(ht, TCLTool), "IO ring instantiation can only run on TCL tools" @@ -403,7 +1011,8 @@ def efabless_ring_io(ht: HammerTool) -> bool: ht.append(f"read_io_file {io_file} -no_die_size_adjust") p_nets = list(map(lambda s: s.name, ht.get_independent_power_nets())) g_nets = list(map(lambda s: s.name, ht.get_independent_ground_nets())) - ht.append(f''' + ht.append( + f""" # Global net connections connect_global_net VDDA -type pg_pin -pin_base_name VDDA -verbose connect_global_net VDDIO -type pg_pin -pin_base_name VDDIO* -verbose @@ -413,8 +1022,10 @@ def efabless_ring_io(ht: HammerTool) -> bool: connect_global_net {g_nets[0]} -type pg_pin -pin_base_name VSSA -verbose connect_global_net {g_nets[0]} -type pg_pin -pin_base_name VSSIO* -verbose connect_global_net {g_nets[0]} -type pg_pin -pin_base_name VSSD* -verbose - ''') - ht.append(''' + """ + ) + ht.append( + """ # IO fillers set io_fillers {sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um sky130_ef_io__com_bus_slice_10um sky130_ef_io__com_bus_slice_5um sky130_ef_io__com_bus_slice_1um} add_io_fillers -prefix IO_FILLER -io_ring 1 -cells $io_fillers -side top -filler_orient r0 @@ -424,24 +1035,96 @@ def efabless_ring_io(ht: HammerTool) -> bool: # Fix placement set io_filler_insts [get_db insts IO_FILLER_*] set_db $io_filler_insts .place_status fixed - ''') + """ + ) # An offset of 40um is used to place the core ring inside the core area. It # can be decreased down to 5um as desired, but will require additional # routing / settings to connect the core power stripes to the ring. - ht.append(f''' + ht.append( + f""" # Core ring add_rings -follow io -layer met5 -nets {{ {p_nets[0]} {g_nets[0]} }} -offset 40 -width 13 -spacing 3 route_special -connect pad_pin -nets {{ {p_nets[0]} {g_nets[0]} }} -detailed_log - ''') - ht.append(''' + """ + ) + ht.append( + """ # Prevent buffering on TIE_LO_ESD and TIE_HI_ESD set_dont_touch [get_db [get_db pins -if {.name == *TIE*ESD}] .net] - ''') + """ + ) return True + +def power_rail_straps_no_tapcells(ht: HammerTool) -> bool: + # We do this since there are no explicit tapcells in sky130_scl + + # just need the rail ones, others are placed as usual. + ht.append( + """ +# -------------------------------------------------------------------------------- +# This script was written and developed by HAMMER at UC Berkeley; however, the +# underlying commands and reports are copyrighted by Cadence. We thank Cadence for +# granting permission to share our research to help promote and foster the next +# generation of innovators. +# -------------------------------------------------------------------------------- + +# Power strap definition for layer met1 (rails): + +# should be .14 +set_db add_stripes_stacked_via_top_layer met1 +set_db add_stripes_stacked_via_bottom_layer met1 +set_db add_stripes_spacing_from_block 4.000 +#add_stripes -over_physical_pins 1 -nets {VDD VSS} -width .14 -direction horizontal -pin_layer met1 -layer met1 +#add_stripes -layer met1 -over_pins 1 -number_of_sets 1 -spacing 3.74 -direction horizontal -width .4 -nets { VSS VDD } -number_of_sets 1 +#add_stripes -pin_layer met1 -layer met1 -over_pins 1 -spacing .2 -direction horizontal -width .4 -nets { VSS VDD } +#add_stripes -master "FILL*" -over_pins 1 -block_ring_bottom_layer_limit met1 -block_ring_top_layer_limit met1 -direction horizontal -layer met1 -nets {VSS VDD} -pad_core_ring_bottom_layer_limit met1 -width pin_width +#add_stripes -nets {VDD VSS} -layer met1 -direction horizontal -width .4 -spacing 4.54 -set_to_set_distance 9.08 -start_from bottom -pin_offset -2.46 +#add_stripes -nets {VDD VSS} -layer met1 -direction horizontal -width .4 -spacing 3.74 -number_of_sets 1 -start_from left -switch_layer_over_obs false -max_same_layer_jog_length 2 -pad_core_ring_top_layer_limit met5 -pad_core_ring_bottom_layer_limit met1 -block_ring_top_layer_limit met5 -block_ring_bottom_layer_limit met1 -use_wire_group 0 -snap_wire_center_to_grid none +add_stripes -nets {VDD VSS} -layer met1 -direction horizontal -start_offset -.2 -width .4 -spacing 3.74 -set_to_set_distance 8.28 -start_from bottom -switch_layer_over_obs false -max_same_layer_jog_length 2 -pad_core_ring_top_layer_limit met5 -pad_core_ring_bottom_layer_limit met1 -block_ring_top_layer_limit met5 -block_ring_bottom_layer_limit met1 -use_wire_group 0 -snap_wire_center_to_grid none + +# Power strap definition for layer met2: + +#set_db add_stripes_stacked_via_top_layer met2 +#set_db add_stripes_stacked_via_bottom_layer met1 +#set_db add_stripes_trim_antenna_back_to_shape {stripe} +##set_db add_stripes_spacing_from_block 4.000 +##add_stripes -create_pins 0 -block_ring_bottom_layer_limit met2 -block_ring_top_layer_limit met1 -direction vertical -layer met2 -nets {VSS VDD} -pad_core_ring_bottom_layer_limit met1 -set_to_set_distance 101.20 -spacing 2.26 -switch_layer_over_obs 0 -width 1.42 -area [get_db designs .core_bbox] -start [expr [lindex [lindex [get_db designs .core_bbox] 0] 0] + 4.81] +#add_stripes -nets {VDD VSS} -layer met2 -direction vertical -width .2 -spacing 0.14 -number_of_sets 1 -extend_to all_domains -start_from left -switch_layer_over_obs false -max_same_layer_jog_length 2 -pad_core_ring_top_layer_limit met5 -pad_core_ring_bottom_layer_limit met1 -block_ring_top_layer_limit met5 -block_ring_bottom_layer_limit met1 -use_wire_group 0 -snap_wire_center_to_grid none + +## Power strap definition for layer met3: + +#set_db add_stripes_stacked_via_top_layer met3 +#set_db add_stripes_stacked_via_bottom_layer met2 +#set_db add_stripes_trim_antenna_back_to_shape {stripe} +#set_db add_stripes_spacing_from_block 2.000 +#add_stripes -create_pins 0 -block_ring_bottom_layer_limit met3 -block_ring_top_layer_limit met2 -direction horizontal -layer met3 -nets {VSS VDD} -pad_core_ring_bottom_layer_limit met2 -set_to_set_distance 75.90 -spacing 3.66 -switch_layer_over_obs 0 -width 1.86 -area [get_db designs .core_bbox] -start [expr [lindex [lindex [get_db designs .core_bbox] 0] 1] + 7.35] + +# Power strap definition for layer met4: + +set_db add_stripes_stacked_via_top_layer met4 +set_db add_stripes_stacked_via_bottom_layer met1 +set_db add_stripes_trim_antenna_back_to_shape {stripe} +set_db add_stripes_spacing_from_block 2.000 +#add_stripes -create_pins 0 -block_ring_bottom_layer_limit met4 -block_ring_top_layer_limit met3 -direction vertical -layer met4 -nets {VSS VDD} -pad_core_ring_bottom_layer_limit met3 -set_to_set_distance 75.90 -spacing 3.66 -switch_layer_over_obs 0 -width 1.86 -area [get_db designs .core_bbox] -start [expr [lindex [lindex [get_db designs .core_bbox] 0] 0] + 7.35] +add_stripes -create_pins 0 -block_ring_bottom_layer_limit met4 -block_ring_top_layer_limit met1 -direction vertical -layer met4 -nets {VSS VDD} -pad_core_ring_bottom_layer_limit met1 -set_to_set_distance 75.90 -spacing 3.66 -switch_layer_over_obs 0 -width 1.86 -area [get_db designs .core_bbox] -start [expr [lindex [lindex [get_db designs .core_bbox] 0] 0] + 7.35] + +# Power strap definition for layer met5: + +set_db add_stripes_stacked_via_top_layer met5 +set_db add_stripes_stacked_via_bottom_layer met4 +set_db add_stripes_trim_antenna_back_to_shape {stripe} +set_db add_stripes_spacing_from_block 2.000 +add_stripes -create_pins 1 -block_ring_bottom_layer_limit met5 -block_ring_top_layer_limit met4 -direction horizontal -layer met5 -nets {VSS VDD} -pad_core_ring_bottom_layer_limit met4 -set_to_set_distance 225.40 -spacing 17.68 -switch_layer_over_obs 0 -width 1.64 -area [get_db designs .core_bbox] -start [expr [lindex [lindex [get_db designs .core_bbox] 0] 1] + 5.62] + +""" + ) + return True + + def calibre_drc_blackbox_srams(ht: HammerTool) -> bool: assert isinstance(ht, HammerDRCTool), "Exlude SRAMs only in DRC" - drc_box = '' + drc_box = "" for name in SKY130Tech.sky130_sram_names(): drc_box += f"\nEXCLUDE CELL {name}" run_file = ht.drc_run_file # type: ignore @@ -449,9 +1132,10 @@ def calibre_drc_blackbox_srams(ht: HammerTool) -> bool: f.write(drc_box) return True + def pegasus_drc_blackbox_srams(ht: HammerTool) -> bool: assert isinstance(ht, HammerDRCTool), "Exlude SRAMs only in DRC" - drc_box = '' + drc_box = "" for name in SKY130Tech.sky130_sram_names(): drc_box += f"\nexclude_cell {name}" run_file = ht.drc_ctl_file # type: ignore @@ -459,9 +1143,10 @@ def pegasus_drc_blackbox_srams(ht: HammerTool) -> bool: f.write(drc_box) return True + def calibre_lvs_blackbox_srams(ht: HammerTool) -> bool: assert isinstance(ht, HammerLVSTool), "Blackbox and filter SRAMs only in LVS" - lvs_box = '' + lvs_box = "" for name in SKY130Tech.sky130_sram_names(): lvs_box += f"\nLVS BOX {name}" lvs_box += f"\nLVS FILTER {name} OPEN " @@ -470,15 +1155,43 @@ def calibre_lvs_blackbox_srams(ht: HammerTool) -> bool: f.write(lvs_box) return True + +# required for sram22 since they use the 130a primiviites +def pegasus_lvs_add_130a_primitives(ht: HammerTool) -> bool: + return True + assert isinstance(ht, HammerLVSTool), "Blackbox and filter SRAMs only in LVS" + lvs_box = "" + for name in SKY130Tech.sky130_sram_primitive_names(): + lvs_box += f"""\nschematic_path "{name}" spice;""" + # this is because otherwise lvs crashes with tons of stdcell-level pin mismatches + lvs_box += f"""\nlvs_inconsistent_reduction_threshold -none;""" + run_file = ht.lvs_ctl_file # type: ignore + with open(run_file, "r+") as f: + # Remove SRAM SPICE file includes. + pattern = "schematic_path.*({}).*spice;\n".format( + "|".join(SKY130Tech.sky130_sram_primitive_names()) + ) + matcher = re.compile(pattern) + contents = f.read() + fixed_contents = contents + lvs_box + f.seek(0) + f.write(fixed_contents) + return True + + def pegasus_lvs_blackbox_srams(ht: HammerTool) -> bool: assert isinstance(ht, HammerLVSTool), "Blackbox and filter SRAMs only in LVS" - lvs_box = '' - for name in SKY130Tech.sky130_sram_names(): + lvs_box = "" + for name in ( + SKY130Tech.sky130_sram_names() # + SKY130Tech.sky130_sram_primitive_names() + ): lvs_box += f"\nlvs_black_box {name} -gray" run_file = ht.lvs_ctl_file # type: ignore with open(run_file, "r+") as f: # Remove SRAM SPICE file includes. - pattern = 'schematic_path.*({}).*spice;\n'.format('|'.join(SKY130Tech.sky130_sram_names())) + pattern = "schematic_path.*({}).*spice;\n".format( + "|".join(SKY130Tech.sky130_sram_names()) + ) matcher = re.compile(pattern) contents = f.read() fixed_contents = matcher.sub("", contents) + lvs_box @@ -486,8 +1199,11 @@ def pegasus_lvs_blackbox_srams(ht: HammerTool) -> bool: f.write(fixed_contents) return True + def sram22_lvs_recognize_gates_all(ht: HammerTool) -> bool: - assert isinstance(ht, HammerLVSTool), "Change 'LVS RECOGNIZE GATES' from 'NONE' to 'ALL' for SRAM22" + assert isinstance( + ht, HammerLVSTool + ), "Change 'LVS RECOGNIZE GATES' from 'NONE' to 'ALL' for SRAM22" run_file = ht.lvs_run_file # type: ignore with open(run_file, "a") as f: f.write("LVS RECOGNIZE GATES ALL") @@ -500,40 +1216,42 @@ def sram22_lvs_recognize_gates_all(ht: HammerTool) -> bool: "SOURCE SYSTEM SPICE", "SOURCE PATH", "ERC", - "LVS REPORT" + "LVS REPORT", ] -LVS_DECK_INSERT_LINES = ''' +LVS_DECK_INSERT_LINES = """ LVS FILTER D OPEN SOURCE LVS FILTER D OPEN LAYOUT -''' +""" + def setup_calibre_lvs_deck(ht: HammerTool) -> bool: assert isinstance(ht, HammerLVSTool), "Modify Calibre LVS deck for LVS only" # Remove conflicting specification statements found in PDK LVS decks - pattern = '.*({}).*\n'.format('|'.join(LVS_DECK_SCRUB_LINES)) + pattern = ".*({}).*\n".format("|".join(LVS_DECK_SCRUB_LINES)) matcher = re.compile(pattern) - source_paths = ht.get_setting('technology.sky130.lvs_deck_sources') + source_paths = ht.get_setting("technology.sky130.lvs_deck_sources") lvs_decks = ht.technology.config.lvs_decks if not lvs_decks: return True - for i,deck in enumerate(lvs_decks): - if deck.tool_name != 'calibre': continue + for i, deck in enumerate(lvs_decks): + if deck.tool_name != "calibre": + continue try: source_path = Path(source_paths[i]) except IndexError: - ht.logger.error( - 'No corresponding source for LVS deck {}'.format(deck)) + ht.logger.error("No corresponding source for LVS deck {}".format(deck)) continue if not source_path.exists(): raise FileNotFoundError(f"LVS deck not found: {source_path}") dest_path = deck.path ht.technology.ensure_dirs_exist(dest_path) - with open(source_path, 'r') as sf: - with open(dest_path, 'w') as df: - ht.logger.info("Modifying LVS deck: {} -> {}".format - (source_path, dest_path)) + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + ht.logger.info( + "Modifying LVS deck: {} -> {}".format(source_path, dest_path) + ) df.write(matcher.sub("", sf.read())) df.write(LVS_DECK_INSERT_LINES) return True diff --git a/hammer/technology/sky130/defaults.yml b/hammer/technology/sky130/defaults.yml index 59bff2f12..b22fb09e8 100644 --- a/hammer/technology/sky130/defaults.yml +++ b/hammer/technology/sky130/defaults.yml @@ -11,6 +11,9 @@ technology.sky130: sky130_cds: "/path/to/sky130_cds" # This contains the Cadence PDK # this key is OPTIONAL, and is only required if you are running Pegasus DRC/LVS. + + sky130_scl: "/path/to/sky130_cdl" # This contains the Cadence standard cell library + # this key is OPTIONAL, and is only required if you want to do Voltus IR drop analysis. sram22_sky130_macros: "/path/to/sram22_sky130_macros" # SRAM path # /path/to/sram22_sky130_macros @@ -32,7 +35,8 @@ technology.sky130: io_file: "extra/efabless_template.io" # IO ring - take this template and modify for your own use io_file_meta: prependlocal - + + stdcell_library: "sky130_fd_sc_hd" # Choose between "sky130_fd_sc_hd" (open-source) or "sky130_scl" (Cadence) mentor.extra_env_vars_meta: lazydeepsubst # Mentor environment variables # Override this in project @@ -109,9 +113,6 @@ synthesis.yosys: par.inputs: gds_merge: true - gds_map_mode: manual - gds_map_file: "extra/sky130_lefpin.map" - gds_map_file_meta: prependlocal par.openroad: # openroad setup/files setrc_file: "extra/setRC.tcl" diff --git a/hammer/technology/sky130/defaults_types.yml b/hammer/technology/sky130/defaults_types.yml index f46c2e6f7..a0196e2a9 100644 --- a/hammer/technology/sky130/defaults_types.yml +++ b/hammer/technology/sky130/defaults_types.yml @@ -15,6 +15,10 @@ technology.sky130: # this key is OPTIONAL, and is only required if you are running Pegasus DRC/LVS. sky130_cds: str + # This contains the Cadence standard cell library + # this key is OPTIONAL, and is only required if you want to do Voltus IR drop analysis. + sky130_scl: str + # RAM paths # OpenRAM openram_lib: str @@ -27,3 +31,6 @@ technology.sky130: # Path to IO file io_file: str + + # Choose between "sky130_fd_sc_hd" (open-source) or "sky130_scl" (Cadence) + stdcell_library: str diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning.json deleted file mode 100644 index 7fbc7cd3c..000000000 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "Skywater 130nm Library", - "grid_unit": "0.001", - "installs": [ - { - "id": "$SKY130A", - "path": "technology.sky130.sky130A" - } - ], - "libraries": [ - { - "lef_file": "tech-sky130-cache/sky130_fd_sc_hd__nom.tlef", - "verilog_sim": "tech-sky130-cache/primitives.v", - "provides": [ - { - "lib_type": "technology" - } - ] - } - ] -} diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning_nda.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning_nda.json deleted file mode 100644 index 2d248220c..000000000 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning_nda.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "Skywater 130nm Library", - "grid_unit": "0.001", - "installs": [ - { - "id": "$SKY130_NDA", - "path": "technology.sky130.sky130_nda" - }, - { - "id": "$SKY130A", - "path": "technology.sky130.sky130A" - } - ], - "layer_map_file": "$SKY130_NDA/s8/V2.0.1/VirtuosoOA/libs/technology_library/technology_library.layermap", - "drc_decks": [ - { - "tool_name": "calibre", - "deck_name": "calibre_drc", - "path": "$SKY130_NDA/s8/V2.0.1/DRC/Calibre/s8_drcRules" - }, - { - "tool_name": "klayout", - "deck_name": "klayout_drc", - "path": "$SKY130A/libs.tech/klayout/drc/sky130A.lydrc" - } - ], - "additional_drc_text": "", - "lvs_decks": [ - { - "tool_name": "calibre", - "deck_name": "calibre_lvs", - "old_path": "$SKY130_NDA/s8/V2.0.1/LVS/Calibre/lvsRules_s8", - "path": "cache/lvsControlFile_s8" - } - ], - "additional_lvs_text": "", - "libraries": [ - { - "lef_file": "cache/sky130_fd_sc_hd__nom.tlef", - "verilog_sim": "cache/primitives.v", - "provides": [ - { - "lib_type": "technology" - } - ] - } - ] -} diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/cells.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/cells.json deleted file mode 100644 index 440b8afcf..000000000 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/cells.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "physical_only_cells_list": [ - "sky130_fd_sc_hd__tap_1", "sky130_fd_sc_hd__tap_2", "sky130_fd_sc_hd__tapvgnd_1", "sky130_fd_sc_hd__tapvpwrvgnd_1", - "sky130_fd_sc_hd__fill_1", "sky130_fd_sc_hd__fill_2", "sky130_fd_sc_hd__fill_4", "sky130_fd_sc_hd__fill_8", - "sky130_fd_sc_hd__diode_2" - ], - "dont_use_list": [ - "*sdf*", - "sky130_fd_sc_hd__probe_p_*", - "sky130_fd_sc_hd__probec_p_*" - ], - "special_cells": [ - { - "cell_type": "tiehilocell", - "name": ["sky130_fd_sc_hd__conb_1"] - }, - { - "cell_type": "tiehicell", - "name": ["sky130_fd_sc_hd__conb_1"], - "output_ports": ["HI"] - }, - { - "cell_type": "tielocell", - "name": ["sky130_fd_sc_hd__conb_1"], - "output_ports": ["LO"] - }, - { - "cell_type": "endcap", - "name": ["sky130_fd_sc_hd__tap_1"] - }, - { - "cell_type": "tapcell", - "name": ["sky130_fd_sc_hd__tapvpwrvgnd_1"] - }, - { - "cell_type": "stdfiller", - "name": ["sky130_fd_sc_hd__fill_1", "sky130_fd_sc_hd__fill_2", "sky130_fd_sc_hd__fill_4", "sky130_fd_sc_hd__fill_8"] - }, - { - "cell_type": "decap", - "name": ["sky130_fd_sc_hd__decap_3", "sky130_fd_sc_hd__decap_4", "sky130_fd_sc_hd__decap_6", "sky130_fd_sc_hd__decap_8", "sky130_fd_sc_hd__decap_12"] - }, - { - "cell_type": "driver", - "name": ["sky130_fd_sc_hd__buf_4"], - "input_ports": ["A"], - "output_ports": ["X"] - }, - { - "cell_type": "ctsbuffer", - "name": ["sky130_fd_sc_hd__clkbuf_1"] - } - ] -} \ No newline at end of file diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/sites.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/sites.json deleted file mode 100644 index e243250cb..000000000 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/sites.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "sites": [ - {"name": "unithd", "x": 0.46, "y": 2.72}, - {"name": "unithddbl", "x": 0.46, "y": 5.44} - ] -} \ No newline at end of file diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups-gen.py b/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups-gen.py deleted file mode 100755 index b6abc3511..000000000 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups-gen.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 -# type: ignore -# tell mypy to ignore this file during typechecking -# -*- coding: utf-8 -*- -# -# Generate Hammer Sky130 tech plugin file: sky130.tech.json -# -# See LICENSE for licence details. -import sys -import json -import os - -library='sky130_fd_sc_hd' - -def main(args) -> int: - if len(args) != 3: - print("Usage: ./stackups-gen.py /path/to/sky130A stackups.json") - return 1 - - SKY130A = sys.argv[1] - - stackup = {} - stackup["name"] = library - stackup["grid_unit"] = 0.001 - stackup["metals"] = [] - - def is_float(string): - try: - float(string) - return True - except ValueError: - return False - - def get_min_from_line(line): - words = line.split() - nums = [float(w) for w in words if is_float(w)] - return min(nums) - - - tlef_path = os.path.join(SKY130A, 'libs.ref', library, 'techlef', f"{library}__min.tlef") - with open(tlef_path, 'r') as f: - metal_name = None - metal_index = 0 - lines = f.readlines() - idx = -1 - while idx < len(lines): - idx += 1 - if idx == len(lines) - 1: break - line = lines[idx] - if '#' in line: line = line[:line.index('#')] - words = line.split() - if line.startswith('LAYER') and len(words) > 1: - if words[1].startswith('li') or words[1].startswith('met'): - metal_name = words[1] - metal_index += 1 - metal = {} - metal["name"] = metal_name - metal["index"] = metal_index - - if metal_name is not None: - line = line.strip() - if line.startswith("DIRECTION"): - metal["direction"] = words[1].lower() - if line.startswith("PITCH"): - metal["pitch"] = get_min_from_line(line) - if line.startswith("OFFSET"): - metal["offset"] = get_min_from_line(line) - if line.startswith("WIDTH"): - metal["min_width"] = get_min_from_line(line) - if line.startswith("SPACINGTABLE"): - metal["power_strap_widths_and_spacings"] = [] - while ';' not in line: - idx += 1 - if idx == len(lines) - 1: break - line = lines[idx].strip() - if '#' in line: line = line[:line.index('#')] - words = line.split() - d = {} - if line.startswith("WIDTH"): - d["width_at_least"] = float(words[1]) - d["min_spacing"] = float(words[2]) - metal["power_strap_widths_and_spacings"].append(d.copy()) - if line.startswith("END"): - metal["grid_unit"] = 0.001 - stackup["metals"].append(metal.copy()) - metal_name = None - - - with open(sys.argv[2], 'w') as f: - json.dump(stackup, f, indent=2) - - return 0 - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups.json deleted file mode 100644 index 576f61446..000000000 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "name": "sky130_fd_sc_hd", - "grid_unit": 0.001, - "metals": [ - { - "name": "li1", - "index": 1, - "direction": "vertical", - "pitch": 0.34, - "offset": 0.17, - "min_width": 0.17, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.17 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met1", - "index": 2, - "direction": "horizontal", - "pitch": 0.34, - "offset": 0.17, - "min_width": 0.14, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.14 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.28 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met2", - "index": 3, - "direction": "vertical", - "pitch": 0.46, - "offset": 0.23, - "min_width": 0.14, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.14 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.28 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met3", - "index": 4, - "direction": "horizontal", - "pitch": 0.68, - "offset": 0.34, - "min_width": 0.3, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.3 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.4 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met4", - "index": 5, - "direction": "vertical", - "pitch": 0.92, - "offset": 0.46, - "min_width": 0.3, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.3 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.4 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met5", - "index": 6, - "direction": "horizontal", - "pitch": 3.4, - "offset": 1.7, - "min_width": 1.6, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 1.6 - } - ], - "grid_unit": 0.001 - } - ] -} \ No newline at end of file diff --git a/hammer/technology/sky130/extra/sky130-tech-gen.py b/hammer/technology/sky130/extra/sky130-tech-gen.py deleted file mode 100755 index 19ddfe8ee..000000000 --- a/hammer/technology/sky130/extra/sky130-tech-gen.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -# type: ignore -# tell mypy to ignore this file during typechecking -# -*- coding: utf-8 -*- -# -# Generate Hammer Sky130 tech plugin file: sky130.tech.json -# -# See LICENSE for licence details. -import sys -import json -import os -import re -import functools - -use_nda_files=True - -def main(args) -> int: - if len(args) != 3: - print("Usage: ./sky130-tech-gen.py /path/to/sky130A sky130.tech.json") - return 1 - - SKY130A = sys.argv[1] - - if use_nda_files: - with open('sky130-tech-gen-files/beginning_nda.json', 'r') as f: data = json.load(f) - else: - with open('sky130-tech-gen-files/beginning.json', 'r') as f: data = json.load(f) - - with open('sky130-tech-gen-files/cells.json', 'r') as f: - cells = json.load(f) - data["physical_only_cells_list"] = cells["physical_only_cells_list"] - data["dont_use_list"] = cells["dont_use_list"] - data["special_cells"] = cells["special_cells"] - - # Standard cells - library='sky130_fd_sc_hd' - - SKYWATER_LIBS = os.path.join('$SKY130A', 'libs.ref', library) - LIBRARY_PATH = os.path.join( SKY130A, 'libs.ref', library, 'lib') - lib_corner_files=os.listdir(LIBRARY_PATH) - lib_corner_files.sort() - for cornerfilename in lib_corner_files: - if (not (library in cornerfilename) ) : continue - if ('ccsnoise' in cornerfilename): continue # ignore duplicate corner.lib/corner_ccsnoise.lib files - - tmp = cornerfilename.replace('.lib','') - if (tmp+'_ccsnoise.lib' in lib_corner_files): - cornerfilename=tmp+'_ccsnoise.lib' # use ccsnoise version of lib file - - cornername = tmp.split('__')[1] - cornerparts = cornername.split('_') - - speed = cornerparts[0] - if (speed == 'ff'): speed = 'fast' - if (speed == 'tt'): speed = 'typical' - if (speed == 'ss'): speed = 'slow' - - temp = cornerparts[1] - temp = temp.replace('n','-') - temp = temp.split('C')[0]+' C' - - vdd = cornerparts[2] - vdd = vdd.split('v')[0]+'.'+vdd.split('v')[1]+' V' - - lib_entry = { - "nldm_liberty_file": os.path.join(SKYWATER_LIBS,'lib', cornerfilename), - "verilog_sim": os.path.join('cache', library+'.v'), - "lef_file": os.path.join(SKYWATER_LIBS,'lef', library+'.lef'), - "spice_file": os.path.join('cache', library+'.cdl'), - "gds_file": os.path.join(SKYWATER_LIBS,'gds', library+'.gds'), - "corner": { - "nmos": speed, - "pmos": speed, - "temperature": temp - }, - "supplies": { - "VDD": vdd, - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - } - - data["libraries"].append(lib_entry) - - # IO cells - library='sky130_fd_io' - SKYWATER_LIBS = os.path.join('$SKY130A', 'libs.ref', library) - LIBRARY_PATH = os.path.join( SKY130A, 'libs.ref', library, 'lib') - lib_corner_files=os.listdir(LIBRARY_PATH) - lib_corner_files.sort() - for cornerfilename in lib_corner_files: - # Skip versions with no internal power - if ('nointpwr' in cornerfilename) : continue - - tmp = cornerfilename.replace('.lib','') - # Split into cell, and corner strings - # Resulting list if only one ff/ss/tt in name: [, , , , ] - # Resulting list if ff_ff/ss_ss/tt_tt in name: [, , , , '', , , , ] - split_cell_corner = re.split('_(ff)|_(ss)|_(tt)', tmp) - cell_name = split_cell_corner[0] - process = split_cell_corner[1:-1] - temp_volt = split_cell_corner[-1].split('_')[1:] - - # Filter out cross corners (e.g ff_ss or ss_ff) - if len(process) > 3: - if not functools.reduce(lambda x,y: x and y, map(lambda p,q: p==q, process[0:3], process[4:]), True): - continue - # Determine actual corner - speed = next(c for c in process if c is not None).replace('_','') - if (speed == 'ff'): speed = 'fast' - if (speed == 'tt'): speed = 'typical' - if (speed == 'ss'): speed = 'slow' - - temp = temp_volt[0] - temp = temp.replace('n','-') - temp = temp.split('C')[0]+' C' - - vdd = ('.').join(temp_volt[1].split('v')) + ' V' - # Filter out IO/analog voltages that are not high voltage - if temp_volt[2].startswith('1'): continue - if len(temp_volt) == 4: - if temp_volt[3].startswith('1'): continue - - # gpiov2_pad_wrapped has separate GDS - if cell_name == 'sky130_ef_io__gpiov2_pad_wrapped': - file_lib = 'sky130_ef_io' - gds_file = cell_name + '.gds' - lef_file = 'cache/sky130_ef_io.lef' - spice_file = os.path.join(SKYWATER_LIBS,'cdl', file_lib + '.cdl') - elif 'sky130_ef_io' in cell_name: - file_lib = 'sky130_ef_io' - gds_file = file_lib + '.gds' - lef_file = 'cache/' + file_lib + '.lef' - spice_file = os.path.join(SKYWATER_LIBS,'cdl', file_lib + '.cdl') - else: - file_lib = library - gds_file = file_lib + '.gds' - lef_file = os.path.join(SKYWATER_LIBS,'lef', file_lib + '.lef') - spice_file = os.path.join(SKYWATER_LIBS,'spice', file_lib + '.spice') - - lib_entry = { - "nldm_liberty_file": os.path.join(SKYWATER_LIBS,'lib', cornerfilename), - "verilog_sim": os.path.join(SKYWATER_LIBS,'verilog', file_lib + '.v'), - "lef_file": lef_file, - "spice_file": spice_file, - "gds_file": os.path.join(SKYWATER_LIBS,'gds', gds_file), - "corner": { - "nmos": speed, - "pmos": speed, - "temperature": temp - }, - "supplies": { - "VDD": vdd, - "GND": "0 V" - }, - "provides": [ - { - "lib_type": cell_name, - "vt": "RVT" - } - ] - } - - data["libraries"].append(lib_entry) - - with open('sky130-tech-gen-files/stackups.json', 'r') as f: - stackups = json.load(f) - data["stackups"] = [stackups] - - with open('sky130-tech-gen-files/sites.json', 'r') as f: - sites = json.load(f) - data["sites"] = sites["sites"] - - with open(sys.argv[2], 'w') as f: - json.dump(data, f, indent=2) - - return 0 - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/hammer/technology/sky130/sky130.tech.json b/hammer/technology/sky130/sky130.tech.json deleted file mode 100644 index 2d6d2d2bf..000000000 --- a/hammer/technology/sky130/sky130.tech.json +++ /dev/null @@ -1,2058 +0,0 @@ -{ - "name": "Skywater 130nm Library", - "grid_unit": "0.001", - "installs": [ - { - "id": "$SKY130_NDA", - "path": "technology.sky130.sky130_nda" - }, - { - "id": "$SKY130A", - "path": "technology.sky130.sky130A" - }, - { - "id": "$SKY130_CDS", - "path": "technology.sky130.sky130_cds" - } - ], - "layer_map_file": "$SKY130_NDA/s8/V2.0.1/VirtuosoOA/libs/technology_library/technology_library.layermap", - "drc_decks": [ - { - "tool_name": "calibre", - "deck_name": "calibre_drc", - "path": "$SKY130_NDA/s8/V2.0.1/DRC/Calibre/s8_drcRules" - }, - { - "tool_name": "klayout", - "deck_name": "klayout_drc", - "path": "$SKY130A/libs.tech/klayout/drc/sky130A.lydrc" - }, - { - "tool_name": "pegasus", - "deck_name": "pegasus_drc", - "path": "$SKY130_CDS/Sky130_DRC/sky130_rev_0.0_1.0.drc.pvl" - } - ], - "additional_drc_text": "", - "lvs_decks": [ - { - "tool_name": "calibre", - "deck_name": "calibre_lvs", - "old_path": "$SKY130_NDA/s8/V2.0.1/LVS/Calibre/lvsRules_s8", - "path": "cache/lvsControlFile_s8" - }, - { - "tool_name": "pegasus", - "deck_name": "pegasus_lvs", - "path": "$SKY130_CDS/Sky130_LVS/Sky130_rev_0.0_0.1.lvs.pvl" - } - ], - "additional_lvs_text": "", - "libraries": [ - { - "lef_file": "cache/sky130_fd_sc_hd__nom.tlef", - "verilog_sim": "cache/primitives.v", - "provides": [ - { - "lib_type": "technology" - } - ] - }, - { - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "provides": [ - { - "lib_type": "technology" - } - ] - }, - { - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_ef_io__analog.spice", - "provides": [ - { - "lib_type": "technology" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ff_100C_1v65.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.65 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ff_100C_1v95.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ff_n40C_1v56.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.56 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ff_n40C_1v65.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.65 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ff_n40C_1v76.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.76 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ff_n40C_1v95_ccsnoise.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_100C_1v40.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.40 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_100C_1v60.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_n40C_1v28.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.28 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_n40C_1v35.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.35 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_n40C_1v40.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.40 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_n40C_1v44.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.44 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_n40C_1v60_ccsnoise.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_n40C_1v76.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.76 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__tt_100C_1v80.lib", - "verilog_sim": "cache/sky130_fd_sc_hd.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef", - "spice_file": "cache/sky130_fd_sc_hd.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__gpiov2_pad_tt_tt_025C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__gpiov2_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__gpiov2_pad_wrapped_ff_ff_100C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io__gpiov2_pad_wrapped.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__gpiov2_pad_wrapped", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__gpiov2_pad_wrapped_ff_ff_n40C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io__gpiov2_pad_wrapped.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__gpiov2_pad_wrapped", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__gpiov2_pad_wrapped_ss_ss_100C_1v60_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io__gpiov2_pad_wrapped.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__gpiov2_pad_wrapped", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__gpiov2_pad_wrapped_tt_tt_025C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io__gpiov2_pad_wrapped.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__gpiov2_pad_wrapped", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped3_pad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped3_pad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped3_pad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped3_pad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped_pad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped_pad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped_pad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vccd_lvc_clamped_pad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vccd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vdda_hvc_clamped_pad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vdda_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vdda_hvc_clamped_pad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vdda_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vdda_hvc_clamped_pad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vdda_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vdda_hvc_clamped_pad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vdda_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vddio_hvc_clamped_pad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vddio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vddio_hvc_clamped_pad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vddio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vddio_hvc_clamped_pad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vddio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vddio_hvc_clamped_pad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vddio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssa_hvc_clamped_pad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssa_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssa_hvc_clamped_pad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssa_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssa_hvc_clamped_pad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssa_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssa_hvc_clamped_pad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssa_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped3_pad_ff_100C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped3_pad_ff_n40C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped3_pad_ss_100C_1v60_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped3_pad_tt_025C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped3_pad_tt_100C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped3_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped_pad_ff_100C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped_pad_ff_n40C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped_pad_ss_100C_1v60_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped_pad_tt_025C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssd_lvc_clamped_pad_tt_100C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssd_lvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssio_hvc_clamped_pad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssio_hvc_clamped_pad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssio_hvc_clamped_pad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_ef_io__vssio_hvc_clamped_pad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_ef_io.v", - "lef_file": "cache/sky130_ef_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/cdl/sky130_ef_io.cdl", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_ef_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_ef_io__vssio_hvc_clamped_pad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_gpiov2_ff_ff_100C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_gpiov2", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_gpiov2_ff_ff_n40C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_gpiov2", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_gpiov2_ss_ss_100C_1v60_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_gpiov2", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_gpiov2_tt_tt_025C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_gpiov2", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_hvc_wpad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_hvc_wpad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_hvc_wpad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_hvc_wpad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_lvc_wpad_ff_100C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_lvc_wpad_ff_n40C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_lvc_wpad_ss_100C_1v60_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_lvc_wpad_tt_025C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_ground_lvc_wpad_tt_100C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_ground_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_hvc_wpad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_hvc_wpad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_hvc_wpad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_hvc_wpad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_hvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_lvc_wpad_ff_100C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_lvc_wpad_ff_n40C_1v95_5v50_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_lvc_wpad_ss_100C_1v60_3v00_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_power_lvc_wpad_tt_025C_1v80_3v30_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_power_lvc_wpad", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_xres4v2_ff_ff_100C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_xres4v2", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_xres4v2_ff_ff_n40C_1v95_5v50.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "fast", - "pmos": "fast", - "temperature": "-40 C" - }, - "supplies": { - "VDD": "1.95 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_xres4v2", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_xres4v2_ss_ss_100C_1v60_3v00.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "slow", - "pmos": "slow", - "temperature": "100 C" - }, - "supplies": { - "VDD": "1.60 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_xres4v2", - "vt": "RVT" - } - ] - }, - { - "nldm_liberty_file": "$SKY130A/libs.ref/sky130_fd_io/lib/sky130_fd_io__top_xres4v2_tt_tt_025C_1v80_3v30.lib", - "verilog_sim": "$SKY130A/libs.ref/sky130_fd_io/verilog/sky130_fd_io.v", - "lef_file": "$SKY130A/libs.ref/sky130_fd_io/lef/sky130_fd_io.lef", - "spice_file": "$SKY130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice", - "gds_file": "$SKY130A/libs.ref/sky130_fd_io/gds/sky130_fd_io.gds", - "corner": { - "nmos": "typical", - "pmos": "typical", - "temperature": "025 C" - }, - "supplies": { - "VDD": "1.80 V", - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "sky130_fd_io__top_xres4v2", - "vt": "RVT" - } - ] - } - ], - "physical_only_cells_list": [ - "sky130_fd_sc_hd__tap_1", - "sky130_fd_sc_hd__tap_2", - "sky130_fd_sc_hd__tapvgnd_1", - "sky130_fd_sc_hd__tapvgnd2_1", - "sky130_fd_sc_hd__tapvgnd_1", - "sky130_fd_sc_hd__tapvpwrvgnd_1", - "sky130_fd_sc_hd__fill_1", - "sky130_fd_sc_hd__fill_2", - "sky130_fd_sc_hd__fill_4", - "sky130_fd_sc_hd__fill_8", - "sky130_fd_sc_hd__diode_2", - "sky130_ef_io__corner_pad" - ], - "dont_use_list": [ - "*sdf*", - "sky130_fd_sc_hd__probe_p_*", - "sky130_fd_sc_hd__probec_p_*" - ], - "special_cells": [ - { - "cell_type": "tiehilocell", - "name": [ - "sky130_fd_sc_hd__conb_1" - ] - }, - { - "cell_type": "tiehicell", - "name": [ - "sky130_fd_sc_hd__conb_1" - ], - "output_ports": [ - "HI" - ] - }, - { - "cell_type": "tielocell", - "name": [ - "sky130_fd_sc_hd__conb_1" - ], - "output_ports": [ - "LO" - ] - }, - { - "cell_type": "endcap", - "name": [ - "sky130_fd_sc_hd__tap_1" - ] - }, - { - "cell_type": "tapcell", - "name": [ - "sky130_fd_sc_hd__tapvpwrvgnd_1" - ] - }, - { - "cell_type": "stdfiller", - "name": [ - "sky130_fd_sc_hd__fill_1", - "sky130_fd_sc_hd__fill_2", - "sky130_fd_sc_hd__fill_4", - "sky130_fd_sc_hd__fill_8" - ] - }, - { - "cell_type": "decap", - "name": [ - "sky130_fd_sc_hd__decap_3", - "sky130_fd_sc_hd__decap_4", - "sky130_fd_sc_hd__decap_6", - "sky130_fd_sc_hd__decap_8", - "sky130_fd_sc_hd__decap_12" - ] - }, - { - "cell_type": "driver", - "name": [ - "sky130_fd_sc_hd__buf_4" - ], - "input_ports": [ - "A" - ], - "output_ports": [ - "X" - ] - }, - { - "cell_type": "ctsbuffer", - "name": [ - "sky130_fd_sc_hd__clkbuf_1" - ] - } - ], - "stackups": [ - { - "name": "sky130_fd_sc_hd", - "grid_unit": 0.001, - "metals": [ - { - "name": "li1", - "index": 1, - "direction": "vertical", - "pitch": 0.34, - "offset": 0.17, - "min_width": 0.17, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.17 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met1", - "index": 2, - "direction": "horizontal", - "pitch": 0.34, - "offset": 0.17, - "min_width": 0.14, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.14 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.28 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met2", - "index": 3, - "direction": "vertical", - "pitch": 0.46, - "offset": 0.23, - "min_width": 0.14, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.14 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.28 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met3", - "index": 4, - "direction": "horizontal", - "pitch": 0.68, - "offset": 0.34, - "min_width": 0.3, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.3 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.4 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met4", - "index": 5, - "direction": "vertical", - "pitch": 0.92, - "offset": 0.46, - "min_width": 0.3, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 0.3 - }, - { - "width_at_least": 3.0, - "min_spacing": 0.4 - } - ], - "grid_unit": 0.001 - }, - { - "name": "met5", - "index": 6, - "direction": "horizontal", - "pitch": 3.4, - "offset": 1.7, - "min_width": 1.6, - "power_strap_widths_and_spacings": [ - { - "width_at_least": 0.0, - "min_spacing": 1.6 - } - ], - "grid_unit": 0.001 - } - ] - } - ], - "sites": [ - { - "name": "unithd", - "x": 0.46, - "y": 2.72 - }, - { - "name": "unithddbl", - "x": 0.46, - "y": 5.44 - } - ] -} diff --git a/hammer/technology/sky130/extra/sky130_lefpin.map b/hammer/technology/sky130/sky130_lefpin.map similarity index 100% rename from hammer/technology/sky130/extra/sky130_lefpin.map rename to hammer/technology/sky130/sky130_lefpin.map diff --git a/hammer/technology/sky130/sram-cache.json b/hammer/technology/sky130/sram-cache.json index 045da80ef..3683de4ed 100644 --- a/hammer/technology/sky130/sram-cache.json +++ b/hammer/technology/sky130/sram-cache.json @@ -195,34 +195,6 @@ } ] }, - { - "type": "sram", - "name": "sram22_2048x32m8w8", - "source": "sram22", - "depth": "2048", - "width": 32, - "family": "1rw", - "mask": "true", - "vt": "svt", - "mux": 8, - "ports": [ - { - "address port name": "addr", - "address port polarity": "active high", - "clock port name": "clk", - "clock port polarity": "active high", - "write enable port name": "we", - "write enable port polarity": "active high", - "output port name": "dout", - "output port polarity": "active high", - "input port name": "din", - "input port polarity": "active high", - "mask port name": "wmask", - "mask granularity": 8, - "mask port polarity": "active high" - } - ] - }, { "type": "sram", "name": "sram22_1024x32m8w32", diff --git a/hammer/utils/lef_utils.py b/hammer/utils/lef_utils.py index da526ad98..c1c628408 100644 --- a/hammer/utils/lef_utils.py +++ b/hammer/utils/lef_utils.py @@ -6,7 +6,7 @@ import re from decimal import Decimal -from typing import List, Optional, Tuple +from typing import List, Optional, Tuple, Dict, Union __all__ = ['LEFUtils'] @@ -92,3 +92,88 @@ def get_sizes(source: str) -> List[Tuple[str, Decimal, Decimal]]: raise ValueError("Unexpected end of file in MACRO block {m}".format(m=in_macro)) return output + + @staticmethod + def get_metals(source: str) -> List[Dict]: + """ + Parse a tech LEF to extract Metal fields. + Note: list(map(lambda m: Metal.model_validate(m), LEFUtils.get_metals(tlef_path))) + is required to convert this into a list of Metals (we can't import stackups classes here) + """ + metals = [] + def is_float(string): + try: + float(string) + return True + except ValueError: + return False + + def get_min_from_line(line): + words = line.split() + nums = [float(w) for w in words if is_float(w)] + return min(nums) + + with open(source, 'r') as f: + metal_name = None + metal_index = 0 + lines = f.readlines() + idx = -1 + while idx < len(lines): + idx += 1 + if idx == len(lines) - 1: break + line = lines[idx] + if '#' in line: line = line[:line.index('#')] + words = line.split() + if line.startswith('LAYER') and len(words) > 1: + if lines[idx+1].strip().startswith('TYPE ROUTING'): + metal_name = words[1] + metal_index += 1 + metal = {} + metal["name"] = metal_name + metal["index"] = metal_index # type: ignore + + if metal_name is not None: + line = line.strip() + if line.startswith("DIRECTION"): + metal["direction"] = words[1].lower() + if line.startswith("PITCH"): + metal["pitch"] = get_min_from_line(line) + if line.startswith("OFFSET"): + metal["offset"] = get_min_from_line(line) + if line.startswith("WIDTH"): + metal["min_width"] = get_min_from_line(line) + if line.startswith("SPACINGTABLE"): + metal["power_strap_widths_and_spacings"] = [] # type: ignore + while ';' not in line: + idx += 1 + if idx == len(lines) - 1: break + line = lines[idx].strip() + if '#' in line: line = line[:line.index('#')] + words = line.split() + d = {} + if line.startswith("WIDTH"): + d["width_at_least"] = float(words[1]) + d["min_spacing"] = float(words[2]) + metal["power_strap_widths_and_spacings"].append(d.copy()) # type: ignore + #width table is a bit more complex + metal["power_strap_width_table"] = [] # type: ignore + # definition on one line + if "WIDTHTABLE" in line: + # definition on one line + if "LEF58_WIDTHTABLE" in line: + metal["power_strap_width_table"] = list(filter(lambda s: is_float(s), line.split())) # type: ignore + # multiple tables, only want routing direction one + if not any(s in line for s in ["ORTHOGONAL", "WRONGDIRECTION"]): + metal["power_strap_width_table"] = list(filter(lambda s: is_float(s), line.split())) # type: ignore + + if line.startswith("END"): + # TODO: grid_unit is not currently parsed as part of the Metal data structure! + # See #379 + metal["grid_unit"] = 0.001 # type: ignore + # Give 'offset' a default value to make pydantic happy + if 'offset' not in metal: + metal['offset'] = Decimal("0.0") + metals.append(metal.copy()) + metal_name = None + + return metals diff --git a/hammer/utils/lib_utils.py b/hammer/utils/lib_utils.py index 582bf9875..65e706fb1 100644 --- a/hammer/utils/lib_utils.py +++ b/hammer/utils/lib_utils.py @@ -53,4 +53,6 @@ def get_headers(source: str) -> List[str]: # TODO: handle other compressed file types? Tools only seem to support gzip. fd = os.open(source, os.O_RDONLY) lines = os.pread(fd, nbytes, 0).splitlines() - return list(map(lambda l: l.decode('ascii', errors='ignore'), lines)) + lines = list(map(lambda l: l.decode('ascii', errors='ignore'), lines)) + all_lines = '\n'.join(lines).replace('\\\n','') # combine lines that are split by \ character + return all_lines.split('\n') diff --git a/hammer/vlsi/driver.py b/hammer/vlsi/driver.py index 8b2862bdd..9a97c53da 100644 --- a/hammer/vlsi/driver.py +++ b/hammer/vlsi/driver.py @@ -65,7 +65,7 @@ def __init__(self, options: HammerDriverOptions, extra_project_config: dict = {} file_logger = HammerVLSIFileLogger(options.log_file) HammerVLSILogging.add_callback(file_logger.callback) self.log = HammerVLSILogging.context() # type: HammerVLSILoggingContext - + # Create a new hammer database. self.database = hammer_config.HammerDatabase() # type: hammer_config.HammerDatabase @@ -152,17 +152,15 @@ def load_technology(self, cache_dir: str = "") -> None: cache_dir = os.path.join(self.obj_dir, "tech-%s-cache" % tech_name) self.log.info("Loading technology '{0}'".format(tech_module)) - tech_opt = hammer_tech.HammerTechnology.load_from_module(tech_module) - if tech_opt is None: - self.log.fatal("Technology {0} not found or missing .tech.[json/yml]!".format(tech_module)) - return - else: - tech: hammer_tech.HammerTechnology = tech_opt - # Update database as soon as possible since e.g. extract_technology_files could use those settings + tech = hammer_tech.HammerTechnology.load_from_module(tech_module) self.database.update_technology(*tech.get_config()) tech.logger = self.log.context("tech") tech.set_database(self.database) tech.cache_dir = cache_dir + tech.gen_config() + if tech.config is None: + self.log.fatal("Technology {0} config not generated or missing .tech.[json/yml]!".format(tech_module)) + return tech.extract_technology_files() tech.get_lib_units() diff --git a/hammer/vlsi/units.py b/hammer/vlsi/units.py index 44230faec..f1a1beae3 100644 --- a/hammer/vlsi/units.py +++ b/hammer/vlsi/units.py @@ -82,7 +82,7 @@ class if one is not specified. match = re.search(regex, value) if match is None: try: - num = str(float(value)) + num = str(float(value.strip("\\"))) self._value_prefix = default_prefix except ValueError: raise ValueError("Malformed {type} value {value}".format(type=self.unit_type,