diff --git a/.readthedocs.yml b/.readthedocs.yml index e1ce84e00..7c99bd41b 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -13,7 +13,7 @@ build: # VIRTUAL_ENV needs to be set manually for now. # See https://github.com/readthedocs/readthedocs.org/pull/11152/ - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install - - python3 -c "from hammer.tech import TechJSON; print(TechJSON.schema_json(indent=2))" > doc/Technology/schema.json + - python3 -c "from hammer.tech import TechConfig; print(TechConfig.schema_json(indent=2))" > doc/Technology/schema.json # Build documentation with Sphinx sphinx: diff --git a/doc/Hammer-Basics/Hammer-Setup.md b/doc/Hammer-Basics/Hammer-Setup.md index 4a3b7ddda..267c8ca03 100644 --- a/doc/Hammer-Basics/Hammer-Setup.md +++ b/doc/Hammer-Basics/Hammer-Setup.md @@ -205,7 +205,7 @@ Run `poetry update` and `poetry install` and commit `poetry.lock`. First, generate the `schema.json` file from within your poetry virtualenv: ```shell -python3 -c "from hammer.tech import TechJSON; print(TechJSON.schema_json(indent=2))" > doc/Technology/schema.json +python3 -c "from hammer.tech import TechConfig; print(TechConfig.schema_json(indent=2))" > doc/Technology/schema.json ``` Then: 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..035b3d49e 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 ``TechConfig`` 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 ``TechConfig``. 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 = TechConfig( + 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 = TechConfig( + #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 TechConfig 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 = TechConfig( + #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 = TechConfig( + #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 = TechConfig( + #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 = TechConfig( + #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 = TechConfig( + #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..649e44387 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -5,7 +5,7 @@ vlsi_dir=$(abspath .) # minimal flow configuration variables design ?= pass pdk ?= sky130 -tools ?= nop +tools ?= cm env ?= bwrc extra ?= # extra configs @@ -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/pyproject.toml b/e2e/pyproject.toml index a63016fb8..23c059a6f 100644 --- a/e2e/pyproject.toml +++ b/e2e/pyproject.toml @@ -10,7 +10,7 @@ repository = "https://github.com/ucb-bar/hammer" [tool.poetry.dependencies] python = "^3.9" hammer-vlsi = {path = "../.", extras = ["asap7"], develop = true} -hammer-mentor-plugins = {path = "hammer-mentor-plugins", develop = true} +#hammer-mentor-plugins = {path = "hammer-mentor-plugins", develop = true} [build-system] requires = ["poetry-core>=1.0.8", "setuptools>=65.3"] 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 bfc5225e0..c9a807e2e 100644 --- a/hammer/par/openroad/__init__.py +++ b/hammer/par/openroad/__init__.py @@ -1452,7 +1452,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 f87c5eb37..4f05cf217 100644 --- a/hammer/synthesis/genus/__init__.py +++ b/hammer/synthesis/genus/__init__.py @@ -199,6 +199,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. @@ -228,9 +230,10 @@ def init_environment(self) -> bool: qrc_files = self.technology.read_libs([ hammer_tech.filters.qrc_tech_filter ], hammer_tech.HammerTechnologyUtils.to_plain_item) - verbose_append("set_db qrc_tech_file {{ {files} }}".format( - files=qrc_files[0] - )) + if qrc_files: + verbose_append("set_db qrc_tech_file {{ {files} }}".format( + files=qrc_files[0] + )) # Quit when ispatial is used with sky130 if(not qrc_files and self.get_setting("synthesis.genus.phys_flow_effort").lower() == "high"): diff --git a/hammer/tech/__init__.py b/hammer/tech/__init__.py index b4e844252..71e2d99a2 100644 --- a/hammer/tech/__init__.py +++ b/hammer/tech/__init__.py @@ -211,7 +211,7 @@ def from_setting(grid_unit: Decimal, d: Dict[str, Any]) -> "Site": ) -class TechJSON(BaseModel): +class TechConfig(BaseModel): name: str grid_unit: Optional[str] = None shrink_factor: Optional[str] = None @@ -323,6 +323,77 @@ def ensure_dirs_exist(self, path) -> None: self.logger.info('Creating directory: {}'.format(dir_name)) os.makedirs(dir_name) + def override_tech_libraries(self) -> None: + """ + Override library paths to cached or manually overriden tech collateral + """ + if not self.config.libraries: + return + + tech_module: str = self.get_setting("vlsi.core.technology") + tech_name = tech_module.split('.')[-1] + manual_overrides = {} + + # if user has broken glass, map tech filename -> manual path + if self.get_setting("vlsi.technology.manually_override_pdk_collateral"): + for lib in self.get_setting("vlsi.technology.override_libraries"): + for key, path in lib['library'].items(): + if isinstance(path, list): # path fname and fname to replace are different + fname = path[1] + path = path[0] + else: + fname = os.path.basename(path) + if (key, fname) in manual_overrides and manual_overrides[(key,fname)] != path: + self.logger.error(f"Attempted to add {(key,path)} to overrides when {manual_overrides[(key, fname)]} already exists!") + manual_overrides[(key, fname)] = path + else: + if len(self.get_setting("vlsi.technology.override_libraries")) > 0: + self.logger.warning("You've attempted to specify override libraries without enabling vlsi.technology.manually_override_pdk_collateral! collateral paths will not be overwritten") + + used_overrides = {} + for lib in self.config.libraries + self.config.drc_decks + self.config.lvs_decks: + for field_name in lib.model_fields: + if "file" in field_name or "path" in field_name or field_name == "verilog_sim": + # check if that file exists in cache, override if so + default_path = getattr(lib, field_name) + if not default_path: + continue + new_path = default_path + fname = os.path.basename(default_path) + fnames = [fname, fname.replace(".spice", ".cdl"), fname.replace(".cdl", ".spice")] + + cached_paths = set(os.path.join(self.cache_dir, f) for f in fnames) + cached_paths = [f for f in cached_paths if os.path.exists(f)] + + # only allow 1 valid cached path, otherwise ambiguous + if len(cached_paths) > 1: + self.logger.error(f"ambiguous cache override: {cached_paths}") + if cached_paths: + new_path = cached_paths[0] + used_overrides[(field_name, fname)] = (new_path, False) # non-manual override + + manual_override_paths = set([f for f in fnames if (field_name, f) in manual_overrides]) + manual_override_paths = [manual_overrides[(field_name, f)] for f in manual_override_paths] + + # only allow 1 valid manual_override path, otherwise ambiguous + if len(manual_override_paths) > 1: + self.logger.error(f"ambiguous cache override: {manual_override_paths}") + # prioritize manual overrides over cache + if manual_override_paths: + new_path = manual_override_paths[0] + used_overrides[(field_name, fname)] = (new_path, True) # manual override + + setattr(lib, field_name, new_path) + # do logging at the end to prevent spamming stdout with the same overrides + for field, new_path in used_overrides.items(): + override_type = "manual" if new_path[1] else "cache" + self.logger.info( + f"Overriding {field[0]} {field[1]} with {override_type} path {new_path[0]}" + ) + unused_overrides = [k for k in manual_overrides.keys() if k not in used_overrides] + if unused_overrides: + self.logger.warning(f"Unused tech collateral overrides: {unused_overrides}") + # hammer-vlsi properties. # TODO: deduplicate/put these into an interface to share with HammerTool? @property @@ -348,14 +419,18 @@ def __init__(self): self.package: str = "" # Configuration, since this constructor will never be used, self.config will never seen as None - self.config: TechJSON = None # type: ignore + self.config: TechConfig = None # type: ignore # Units (converted to Time/CapacitanceValue later) self.time_unit: Optional[str] = None self.cap_unit: Optional[str] = None + def gen_config(self) -> None: + """For subclasses to set self.config (type: TechConfig) 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") @@ -371,13 +446,13 @@ def load_from_module(cls, tech_module: str) -> Optional["HammerTechnology"]: tech_yaml = importlib.resources.files(tech_module) / f"{technology_name}.tech.yml" if tech_json.is_file(): - tech.config = TechJSON.model_validate_json(tech_json.read_text()) + tech.config = TechConfig.model_validate_json(tech_json.read_text()) return tech elif tech_yaml.is_file(): - tech.config = TechJSON.model_validate_json(json.dumps(load_yaml(tech_yaml.read_text()))) + tech.config = TechConfig.model_validate_json(json.dumps(load_yaml(tech_yaml.read_text()))) + return tech + else: # Assume tech implents gen_config() return tech - else: #TODO - from Pydantic model instance - return None def get_lib_units(self) -> None: """ @@ -416,6 +491,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. """ @@ -649,15 +730,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/asap7/defaults.yml b/hammer/technology/asap7/defaults.yml index ba5f45d19..0583029df 100644 --- a/hammer/technology/asap7/defaults.yml +++ b/hammer/technology/asap7/defaults.yml @@ -41,6 +41,10 @@ vlsi: routing_layers: [2, 7] + # WARNING: BREAK GLASS flag to override tech collateral with the paths provided in `override_libraries` + technology.manually_override_pdk_collateral: false + technology.override_libraries: [] # hacked collateral files to be used instead of default tech files with the same name + technology.core: stackup: "asap7_3Ma_2Mb_2Mc_2Md" # This key should exist in the stackups list in the tech json diff --git a/hammer/technology/sky130/README.md b/hammer/technology/sky130/README.md index d5f99934e..49158f688 100644 --- a/hammer/technology/sky130/README.md +++ b/hammer/technology/sky130/README.md @@ -49,6 +49,21 @@ 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 a814688f1..11dec55cb 100644 --- a/hammer/technology/sky130/__init__.py +++ b/hammer/technology/sky130/__init__.py @@ -2,71 +2,570 @@ # # See LICENSE for licence details. -import sys -import re -import os, shutil -from pathlib import Path -from typing import NamedTuple, List, Optional, Tuple, Dict, Set, Any +import functools import importlib import importlib.resources import json - -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 +import os +import re +import shutil +from pathlib import Path +from typing import List + +from hammer.tech import ( + Corner, + Decimal, + DRCDeck, + HammerTechnology, + Library, + LVSDeck, + Metal, + PathPrefix, + Provide, + Site, + Stackup, + Supplies, + TechConfig, +) from hammer.tech.specialcells import CellType, SpecialCell +from hammer.utils import LEFUtils +from hammer.vlsi import ( + HammerDRCTool, + HammerLVSTool, + HammerPlaceAndRouteTool, + HammerTool, + HammerToolHookAction, + HierarchicalMode, + TCLTool, +) + 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_SCL = self.get_setting("technology.sky130.sky130_scl") + + self.use_sram22 = os.path.exists( + self.get_setting("technology.sky130.sram22_sky130_macros") + ) + + # Common tech LEF and IO cell spice netlists + libs = [] + if slib == "sky130_fd_sc_hd": + libs += [ + Library( + lef_file=os.path.join( + SKY130A, + "libs.ref/sky130_fd_sc_hd/techlef/sky130_fd_sc_hd__nom.tlef", + ), + verilog_sim=os.path.join( + SKY130A, "libs.ref/sky130_fd_sc_hd/verilog/primitives.v" + ), + provides=[Provide(lib_type="technology")], + ), + ] + elif slib == "sky130_scl": + libs += [ + Library( + lef_file=os.path.join(SKY130_SCL, "sky130_scl_9T_tech/lef/sky130_scl_9T.tlef"), + verilog_sim=os.path.join(SKY130_SCL, "sky130_scl_9T/verilog/sky130_scl_9T.v"), + provides=[Provide(lib_type="technology")], + ), + ] + libs += [ + Library( + lef_file=os.path.join(SKY130_SCL, "sky130_scl_9T_tech/lef/sky130_scl_9T_phyCells.lef"), + provides=[Provide(lib_type="technology")], + ), + ] + else: + raise ValueError(f"Incorrect standard cell library selection: {slib}") + if self.use_sram22: + libs += [ + Library( + spice_file=os.path.join( + self.get_setting("technology.sky130.sram22_sky130_macros"), + "sram22.spice", + ), + provides=[Provide(lib_type="technology")], + ), + ] + + # Stdcell library-dependent lists + stackups = [] # type: List[Stackup] + phys_only = [] # type: List[Cell] + dont_use = [] # type: List[Cell] + spcl_cells = [] # type: List[SpecialCell] + + # base path -> list of corners + lib_corner_files = {} + + # 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"], + ), + # this breaks synthesis with a complaint about "Cannot perform synthesis because libraries do not have usable inverters." from Genus. + # note that innovus still recognizes and uses this cell as a buffer + # 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 + + STDCELL_LIBRARY_BASE_PATH = os.path.join(SKY130A, "libs.ref", library) + lib_corner_files[STDCELL_LIBRARY_BASE_PATH] = os.listdir( + os.path.join(STDCELL_LIBRARY_BASE_PATH, "lib") + ) + lib_corner_files[STDCELL_LIBRARY_BASE_PATH].sort() + + # 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_2.2.drc.pvl", + ), + ] + + elif slib == "sky130_scl": + # note: you need to manually include io cells in design.yml if using 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"], + ), + # this breaks synthesis with a complaint about "Cannot perform synthesis because libraries do not have usable inverters." from Genus. + # note that innovus still recognizes and uses this cell as a buffer + # added for par with a hook `set_cts_base_cells` + # 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 + STDCELL_LIBRARY_BASE_PATH = os.path.join(SKY130_SCL, "sky130_scl_9T") + lib_corner_files[STDCELL_LIBRARY_BASE_PATH] = os.listdir( + os.path.join(STDCELL_LIBRARY_BASE_PATH, "lib") + ) + lib_corner_files[STDCELL_LIBRARY_BASE_PATH].sort() + + # Generate stackup + metals = [] # type: List[Metal] + + tlef_path = os.path.join(SKY130_SCL, "sky130_scl_9T_tech", "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="pegasus", + deck_name="pegasus_lvs", + path=os.path.join(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="pegasus", + deck_name="pegasus_drc", + path=os.path.join( + SKY130_CDS, "Sky130_DRC", "sky130_rev_0.0_2.2.drc.pvl" + ), + ), + ] + + else: + raise ValueError(f"Incorrect standard cell library selection: {slib}") + + # add skywater io cells + io_library_base_path = os.path.join(SKY130A, "libs.ref", "sky130_fd_io") + if os.path.exists(io_library_base_path): + lib_corner_files[io_library_base_path] = os.listdir( + os.path.join(io_library_base_path, "lib") + ) + + for library_base_path, cornerfiles in lib_corner_files.items(): + for cornerfilename in cornerfiles: + if "sky130" not in cornerfilename or "#" in cornerfilename: + # cadence doesn't use the lib name in their corner libs + # also skip random temp files sometimes included in sky130_scl + continue + if "ccsnoise" in cornerfilename: + continue # ignore duplicate corner.lib/corner_ccsnoise.lib files + + tmp = cornerfilename.replace(".lib", "").strip("_nldm") + if tmp + "_ccsnoise.lib" in lib_corner_files: + cornerfilename = ( + tmp + "_ccsnoise.lib" + ) # use ccsnoise version of lib file + + # different naming conventions + if "sky130A" in library_base_path: + split_cell_corner = re.split("_(ff)|_(ss)|_(tt)", tmp) + cell_name = split_cell_corner[0] + library = tmp.split("__")[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("_", "") + temp = temp_volt[0] + temp = temp.replace("n", "-") + temp = temp.split("C")[0] + " C" + + vdd = (".").join(temp_volt[1].split("v")) + " V" + if speed == "ff": + speed = "fast" + elif speed == "tt": + speed = "typical" + elif speed == "ss": + speed = "slow" + else: + self.logger.info( + "Skipping lib with unsupported corner: {}".format(speed) + ) + continue + else: + library = "sky130_scl_9T" + _, speed, vdd, temp, _ = tmp.split("_") + + # force equivalent operating conditions for speed, since they're different between sky130a and scl + 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" + + cdl_path = os.path.join(library_base_path, "cdl", library + ".cdl") + spice_path = os.path.join( + library_base_path, "spice", library + ".spice" + ) + + # just prioritize spice, arbitrary choice + # assert not (os.path.exists(cdl_path) and os.path.exists(spice_path)), "both spice and cdl netlists exist! this is ambiguous :(" + + netlist_path = spice_path if os.path.exists(spice_path) else cdl_path + + lib_entry = Library( + nldm_liberty_file=os.path.join( + library_base_path, "lib", cornerfilename + ), + verilog_sim=os.path.join( + SKY130_SCL, + "sky130_scl_9T", + "verilog", + library + "_9T.v" if slib == "sky130_scl" else ".v", + ), + lef_file=os.path.join(library_base_path, "lef", library + ".lef"), + spice_file=netlist_path, + gds_file=os.path.join(library_base_path, "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) + + if "sky130_fd_io" in library_base_path: + # these are seperate from the io gds + extra_gds_files = [ + "sky130_ef_io__analog.gds", + "sky130_ef_io__disconnect_vccd_slice_5um.gds", + "sky130_ef_io__gpiov2_pad_wrapped.gds", + "sky130_ef_io__bare_pad.gds", + "sky130_ef_io__disconnect_vdda_slice_5um.gds", + "sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um.gds", + "sky130_ef_io.gds", + ] + for extra_gds_file in extra_gds_files: + lib_entry = Library( + nldm_liberty_file=os.path.join( + library_base_path, "lib", cornerfilename + ), + verilog_sim=os.path.join( + SKY130_SCL, + "sky130_scl_9T", + "verilog", + library + "_9T.v" if slib == "sky130_scl" else ".v", + ), + lef_file=os.path.join( + library_base_path, "lef", library + ".lef" + ), + spice_file=netlist_path, + gds_file=os.path.join( + library_base_path, "gds", extra_gds_file + ), + 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) + + self.config = TechConfig( + 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() + 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.setup_io_lefs() + self.setup_calibre_lvs_deck() + self.setup_hvl_ls_lef() + print("Loaded Sky130 Tech") + + def setup_calibre_lvs_deck(self) -> bool: + # Remove conflicting specification statements found in PDK LVS decks + pattern = ".*({}).*\n".format("|".join(LVS_DECK_SCRUB_LINES)) + matcher = re.compile(pattern) + source_paths = self.get_setting("technology.sky130.lvs_deck_sources") + lvs_decks = self.config.lvs_decks + if not lvs_decks: + return True + for i, deck in enumerate(lvs_decks): + if deck.tool_name != "calibre": + continue + try: + source_path = Path(source_paths[i]) + except IndexError: + self.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}") + cache_tech_dir_path = Path(self.cache_dir) + dest_path = os.path.join(cache_tech_dir_path, os.path.basename(deck.path)) + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying LVS deck: {} -> {}".format(source_path, dest_path) + ) + df.write(matcher.sub("", sf.read())) + df.write(LVS_DECK_INSERT_LINES) + return True 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)) + 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.pegasus": + pmos = "pfet_01v8_hvt" + nmos = "nfet_01v8" + elif self.get_setting("vlsi.core.lvs_tool") == "hammer.lvs.netgen": + pmos = "sky130_fd_pr__pfet_01v8_hvt" + nmos = "sky130_fd_pr__nfet_01v8" + else: + shutil.copy2(source_path, dest_path) + return + + 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 @@ -79,223 +578,392 @@ 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: - 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] - - # Search for the broken statement - 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] - 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 - - # 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)] - 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)) - 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: - 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' - 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' + 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 / "sky130_scl_9T_tech" / "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}") - 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) + if ( + self.get_setting("technology.sky130.stdcell_library") + == "sky130_scl" + ): + if line.strip() == "END poly": + df.write(_additional_tlef_edit_for_scl + _the_tlef_edit) + else: + if line.strip() == "END pwell": + df.write(_the_tlef_edit) + + 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 + ) + ] + + 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, []) # 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' + 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}") 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' + 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)) + 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] + for net in ["VCCD1", "VSSD1", "VDDA", "VSSA", "VSSIO"]: + 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] + port_idx = [ + idx + for idx, line in enumerate(sl[intv[0] : intv[1]]) + if "PORT" in line and "met3" in sl[intv[0] + idx + 1] + ] 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 - + sl[intv[0] + idx] = sl[intv[0] + idx].replace( + "PORT", "PORT\n CLASS CORE ;" + ) + # force class to spacer + # TODO: the disconnect_* slices are also broken like this, but we're not using them + start = [ + idx + for idx, line in enumerate(sl) + if "MACRO sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um" + in line + ] + sl[start[0] + 1] = sl[start[0] + 1].replace("AREAIO", "SPACER") + + for idx, line in enumerate(sl): + if "PIN OUT" in line: + sl[idx + 1].replace( + "DIRECTION INPUT ;", + "DIRECTION INPUT ;\n ANTENNAGATEAREA 1.529 LAYER met3 ;", + ) + df.writelines(sl) + def setup_hvl_ls_lef(self) -> bool: + # Treat HVL cells as if they were hard macros to avoid needing to set them + # up "properly" with multiple power domains + + lef_name = "sky130_fd_sc_hvl__lsbufhv2lv_1.lef" + + sky130A_path = Path(self.get_setting("technology.sky130.sky130A")) + source_path = ( + sky130A_path + / "libs.ref" + / "sky130_fd_sc_hvl" + / "lef" + / "sky130_fd_sc_hvl.lef" + ) + cache_path = Path(self.cache_dir) / "fd_sc_hvl__lef" / lef_name + cache_path.parent.mkdir(exist_ok=True) + + with source_path.open("r") as sf, cache_path.open("w") as df: + self.logger.info(f"Patching HVL LS LEF: {source_path} -> {cache_path}") + is_in_site_def = False + is_in_macro_def = False + for line in sf: + if is_in_site_def: + if "END unithv" in line: + is_in_site_def = False + elif not is_in_macro_def and "SITE unithv" in line: + is_in_site_def = True + elif "MACRO " in line: + is_in_macro_def = True + df.write(line) + elif "SITE unithv" in line: + pass + else: + df.write( + line.replace("CLASS CORE", "CLASS BLOCK") + if not (("ANTENNACELL" in line) or ("SPACER" in line)) + else line + ) + 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"].extend( + [ + HammerTool.make_pre_insertion_hook( + "power_straps", power_rail_straps_no_tapcells + ), + HammerTool.make_pre_insertion_hook( + "clock_tree", set_cts_base_cells + ), + ] + ) + 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 + ) + ) + pegasus_hooks.append( + HammerTool.make_post_insertion_hook( + "generate_drc_ctl_file", pegasus_drc_blackbox_io_cells + ) + ) + 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 = [] 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 = ''' +# string constants +# the io libs (sky130a) +_the_tlef_edit = """ +LAYER AREAIDLD + TYPE MASTERSLICE ; +END AREAIDLD + 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 +""" + +LVS_DECK_INSERT_LINES = """ +LVS FILTER D OPEN SOURCE +LVS FILTER D OPEN LAYOUT +""" + +LVS_DECK_SCRUB_LINES = [ + "VIRTUAL CONNECT REPORT", + "SOURCE PRIMARY", + "SOURCE SYSTEM SPICE", + "SOURCE PATH", + "ERC", + "LVS REPORT", +] # various Innovus database settings @@ -304,7 +972,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] @@ -318,6 +986,7 @@ def sky130_innovus_settings(ht: HammerTool) -> bool: set_db place_global_solver_effort high set_db place_detail_check_cut_spacing true set_db place_global_cong_effort high +set_db add_fillers_with_drc false ########################################################## # Optimization attributes [get_db -category opt] @@ -345,7 +1014,7 @@ def sky130_innovus_settings(ht: HammerTool) -> bool: ########################################################## #------------------------------------------------------------------------------- set_db route_design_antenna_diode_insertion 1 -set_db route_design_antenna_cell_name "sky130_fd_sc_hd__diode_2" +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 @@ -354,26 +1023,48 @@ 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 - ''' + """ ) + + # ht.append( + # """ + # # note this is required for sky130_fd_sc_hd, the design has a ton of drcs if bottom layer is 1 + # # TODO: why is setting routing_layer not enough? + # set_db design_bottom_routing_layer 2 + # set_db design_top_routing_layer 6 + # # deprected syntax, but this used to always work + # set_db route_design_bottom_routing_layer 2 + # """ + # ) + 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 @@ -385,64 +1076,54 @@ 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" - io_file = ht.get_setting("technology.sky130.io_file") - 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''' -# 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 -connect_global_net {p_nets[0]} -type pg_pin -pin_base_name VCCD* -verbose -connect_global_net {p_nets[0]} -type pg_pin -pin_base_name VCCHIB -verbose -connect_global_net {p_nets[0]} -type pg_pin -pin_base_name VSWITCH -verbose -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(''' -# 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 -add_io_fillers -prefix IO_FILLER -io_ring 1 -cells $io_fillers -side right -filler_orient r270 -add_io_fillers -prefix IO_FILLER -io_ring 1 -cells $io_fillers -side bottom -filler_orient r180 -add_io_fillers -prefix IO_FILLER -io_ring 1 -cells $io_fillers -side left -filler_orient r90 -# 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''' -# 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(''' -# Prevent buffering on TIE_LO_ESD and TIE_HI_ESD -set_dont_touch [get_db [get_db pins -if {.name == *TIE*ESD}] .net] - ''') + +# this needs to only be emitted in innovus, since it breaks the genus flow with the complaint that there are no usable inverters/logic cells (???) in version 211 +def set_cts_base_cells(ht: HammerTool) -> bool: + ht.append( + """ +set_db cts_buffer_cells {CLKBUFX2 CLKBUFX4 CLKBUFX8} +set_db cts_clock_gating_cells {ICGX1} + """ + ) return True + +def power_rail_straps_no_tapcells(ht: HammerTool) -> bool: + assert not ht.get_setting( + "par.generate_power_straps_options.by_tracks.generate_rail_layer" + ), """ +Rails must be placed by this hook for sky130_scl! +Set par.generate_power_straps_options.by_tracks.generate_rail_layer: false""" + # We do this since there are no explicit tapcells in sky130_scl + # just need the rail ones, others are placed as usual. + ht.append( + """ +# 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 -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 +""" + ) + 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 @@ -450,9 +1131,28 @@ def calibre_drc_blackbox_srams(ht: HammerTool) -> bool: f.write(drc_box) return True + +# pegasus won't be able to drc the sky130a ios +def pegasus_drc_blackbox_io_cells(ht: HammerTool) -> bool: + assert isinstance(ht, HammerDRCTool) and ht.tool_config_prefix() == "drc.pegasus", ( + "Exlude IOs only for Pegasus DRC" + ) + drc_box = "" + io_cell_names = [ + "sky130_ef_io__*" + ] # TODO i don't think epgasus actually recognizes these? + # io_cell_names = ["sky130_ef_io__gpiov2_pad_wrapped"] + for name in io_cell_names: + drc_box += f"\nexclude_cell {name}" + run_file = ht.drc_ctl_file # type: ignore + with open(run_file, "a") as f: + 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 @@ -460,9 +1160,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 " @@ -471,15 +1172,44 @@ 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 += """\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 + # + SKY130Tech.sky130_sram_primitive_names() + ) in SKY130Tech.sky130_sram_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 @@ -487,56 +1217,14 @@ 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") - return True - - -LVS_DECK_SCRUB_LINES = [ - "VIRTUAL CONNECT REPORT", - "SOURCE PRIMARY", - "SOURCE SYSTEM SPICE", - "SOURCE PATH", - "ERC", - "LVS REPORT" -] - -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)) - matcher = re.compile(pattern) - - 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 - try: - source_path = Path(source_paths[i]) - except IndexError: - 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)) - df.write(matcher.sub("", sf.read())) - df.write(LVS_DECK_INSERT_LINES) + f.write("\nLVS RECOGNIZE GATES ALL") return True diff --git a/hammer/technology/sky130/defaults.yml b/hammer/technology/sky130/defaults.yml index 59bff2f12..25931fc38 100644 --- a/hammer/technology/sky130/defaults.yml +++ b/hammer/technology/sky130/defaults.yml @@ -1,4 +1,6 @@ # Settings for the sky130 technology +# + technology.sky130: sky130A: "/path/to/sky130A" # This should be output files from the OpenPDKs compilation process. # This is $PDK_ROOT/share/pdk/sky130A from the README. @@ -11,6 +13,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 +37,13 @@ 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) + +# WARNING: BREAK GLASS flag to override tech collateral with the paths provided in `override_libraries` +vlsi.technology.manually_override_pdk_collateral: false +vlsi.technology.override_libraries: [] # hacked collateral files to be used instead of default tech files with the same name +# either it's key:path or key:[path,name_to_override] if the path fname is diff than the fname to override mentor.extra_env_vars_meta: lazydeepsubst # Mentor environment variables # Override this in project @@ -109,9 +120,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/efabless_template.io b/hammer/technology/sky130/extra/efabless_template.io index 524090739..cad54564d 100644 --- a/hammer/technology/sky130/extra/efabless_template.io +++ b/hammer/technology/sky130/extra/efabless_template.io @@ -65,8 +65,6 @@ (inst name = "" orientation=R270 offset=4392) (inst name = "clamp_6" orientation=R270 cell="sky130_ef_io__vccd_lvc_clamped3_pad" offset=4613) (inst name = "" orientation=R270 offset=4838) - (inst name = "IO_FILLER_MANUAL_E_1" orientation = R270 offset = 4593 cell = "sky130_ef_io__com_bus_slice_20um") - (inst name = "IO_FILLER_MANUAL_E_2" orientation = R270 offset = 2354 cell = "sky130_ef_io__com_bus_slice_20um") ) (bottomright @@ -117,8 +115,5 @@ (inst name = "clamp_16" orientation=R90 cell="sky130_ef_io__vddio_hvc_clamped_pad" offset=4349) (inst name = "clamp_17" orientation=R90 cell="sky130_ef_io__vccd_lvc_clamped3_pad" offset=4560) (inst name = "" orientation=R90 offset=4771) - (inst name = "IO_FILLER_MANUAL_W_1" orientation = R90 offset = 415 cell = "sky130_ef_io__com_bus_slice_20um") - (inst name = "IO_FILLER_MANUAL_W_2" orientation = R90 offset = 2279 cell = "sky130_ef_io__com_bus_slice_20um") - (inst name = "IO_FILLER_MANUAL_W_3" orientation = R90 offset = 4635 cell = "sky130_ef_io__com_bus_slice_20um") ) ) 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/extra/sram22/sram-cache-gen.py b/hammer/technology/sky130/extra/sram22/sram-cache-gen.py index 0b14da455..303724e14 100755 --- a/hammer/technology/sky130/extra/sram22/sram-cache-gen.py +++ b/hammer/technology/sky130/extra/sram22/sram-cache-gen.py @@ -10,25 +10,28 @@ import sys import re import json -import os from typing import List def main(args: List[str]) -> int: if len(args) != 3: - print("Usage: ./sram-cache-gen.py /path/to/sram22_sky130_macros output-file.json") - print("E.g.: ./sram-cache-gen.py /tools/C/me/sram22_sky130_macros sram-cache.json") + print("Usage: ./sram-cache-gen.py list-of-srams-1-per-line.txt output-file.json") + print("E.g.: ./sram-cache-gen.py srams.txt sram-cache.json") return 1 - list_of_srams: List[str] = [d.name for d in os.scandir(sys.argv[1]) if d.is_dir()] - print(f"Found {len(list_of_srams)} SRAMS to cache") + list_of_srams = [] # type: List[str] + with open(sys.argv[1]) as f: + for line in f: + list_of_srams.append(line) + + print(str(len(list_of_srams)) + " SRAMs to cache") sram_dicts = [] for sram_name in list_of_srams: # SRAM22-generated single-port RAMs if sram_name.startswith("sram22_"): - match = re.match(r"^sram22_(\d+)x(\d+)m(\d+)w(\d+)$", sram_name) + match = re.match(r"sram22_(\d+)x(\d+)m(\d+)w(\d+)(\D*)", sram_name) if match: width = int(match.group(2)) mask_gran = int(match.group(4)) @@ -52,8 +55,11 @@ def main(args: List[str]) -> int: port_dict['clock port name'] = "clk" port_dict['clock port polarity'] = "active high" + port_dict['chip enable port name'] = "ce" + port_dict['chip enable port polarity'] = "active high" # ??? + port_dict['write enable port name'] = "we" - port_dict['write enable port polarity'] = "active high" + port_dict['write enable port polarity'] = "active high" # ??? port_dict['output port name'] = "dout" port_dict['output port polarity'] = "active high" @@ -61,17 +67,27 @@ def main(args: List[str]) -> int: port_dict['input port name'] = "din" port_dict['input port polarity'] = "active high" - # if mask_gran != width: port_dict['mask port name'] = "wmask" port_dict['mask granularity'] = mask_gran port_dict['mask port polarity'] = "active high" # ??? sram_dict['ports'].append(port_dict.copy()) + sram_dict['extra ports'] = [{ + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1, + }] + sram_dicts.append(sram_dict.copy()) else: - print("Skipping unsupported memory: {n}".format(n=sram_name), file=sys.stderr) + print("Unsupported memory: {n}".format(n=sram_name), file=sys.stderr) + return 1 + else: + print("Unsupported memory: {n}".format(n=sram_name), file=sys.stderr) + return 1 with open(sys.argv[2], "w") as f: json.dump(sram_dicts, f, indent=2) diff --git a/hammer/technology/sky130/extra/sram22/sram-cache.json b/hammer/technology/sky130/extra/sram22/sram-cache.json index 045da80ef..fdad68e08 100644 --- a/hammer/technology/sky130/extra/sram22/sram-cache.json +++ b/hammer/technology/sky130/extra/sram22/sram-cache.json @@ -1,10 +1,10 @@ [ { "type": "sram", - "name": "sram22_512x32m4w32", + "name": "sram22_64x24m4w8", "source": "sram22", - "depth": "512", - "width": 32, + "depth": "64", + "width": 24, "family": "1rw", "mask": "true", "vt": "svt", @@ -15,6 +15,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -22,14 +24,22 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 32, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x32m4w32", + "name": "sram22_64x32m4w8", "source": "sram22", "depth": "64", "width": 32, @@ -43,6 +53,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -50,17 +62,25 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 32, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_512x64m4w8", + "name": "sram22_128x16m4w8", "source": "sram22", - "depth": "512", - "width": 64, + "depth": "128", + "width": 16, "family": "1rw", "mask": "true", "vt": "svt", @@ -71,6 +91,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -81,14 +103,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_512x32m4w8", + "name": "sram22_128x24m4w8", "source": "sram22", - "depth": "512", - "width": 32, + "depth": "128", + "width": 24, "family": "1rw", "mask": "true", "vt": "svt", @@ -99,6 +129,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -109,14 +141,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x24m4w24", + "name": "sram22_128x32m4w8", "source": "sram22", - "depth": "64", - "width": 24, + "depth": "128", + "width": 32, "family": "1rw", "mask": "true", "vt": "svt", @@ -127,6 +167,84 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_256x8m8w1", + "source": "sram22", + "depth": "256", + "width": 8, + "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", + "chip enable port name": "ce", + "chip enable 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": 1, + "mask port polarity": "active high" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_256x16m8w8", + "source": "sram22", + "depth": "256", + "width": 16, + "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", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -134,9 +252,17 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 24, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { @@ -155,6 +281,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -165,14 +293,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x4m4w2", + "name": "sram22_256x64m4w8", "source": "sram22", - "depth": "64", - "width": 4, + "depth": "256", + "width": 64, "family": "1rw", "mask": "true", "vt": "svt", @@ -183,6 +319,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -190,17 +328,63 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 2, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_2048x32m8w8", + "name": "sram22_256x128m4w8", "source": "sram22", - "depth": "2048", - "width": 32, + "depth": "256", + "width": 128, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_512x8m8w1", + "source": "sram22", + "depth": "512", + "width": 8, "family": "1rw", "mask": "true", "vt": "svt", @@ -211,6 +395,46 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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": 1, + "mask port polarity": "active high" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_512x32m4w8", + "source": "sram22", + "depth": "512", + "width": 32, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -221,14 +445,98 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_1024x32m8w32", + "name": "sram22_512x64m4w8", + "source": "sram22", + "depth": "512", + "width": 64, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_512x128m4w8", + "source": "sram22", + "depth": "512", + "width": 128, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_1024x8m8w1", "source": "sram22", "depth": "1024", - "width": 32, + "width": 8, "family": "1rw", "mask": "true", "vt": "svt", @@ -239,6 +547,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -246,9 +556,17 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 32, + "mask granularity": 1, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { @@ -267,6 +585,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -277,14 +597,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x32m4w8", + "name": "sram22_1024x64m4w8", "source": "sram22", - "depth": "64", - "width": 32, + "depth": "1024", + "width": 64, "family": "1rw", "mask": "true", "vt": "svt", @@ -295,6 +623,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -305,6 +635,52 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] - } + }, + { + "type": "sram", + "name": "sram22_2048x8m8w1", + "source": "sram22", + "depth": "2048", + "width": 8, + "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", + "chip enable port name": "ce", + "chip enable 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": 1, + "mask port polarity": "active high" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, ] diff --git a/hammer/technology/sky130/extra/sram22/srams.txt b/hammer/technology/sky130/extra/sram22/srams.txt new file mode 100644 index 000000000..94a6c1125 --- /dev/null +++ b/hammer/technology/sky130/extra/sram22/srams.txt @@ -0,0 +1,22 @@ +sram22_64x24m4w8 +sram22_64x32m4w8 +sram22_128x16m4w8 +sram22_128x24m4w8 +sram22_128x32m4w8 +sram22_256x8m8w1 +sram22_256x16m8w8 +sram22_256x32m4w8 +sram22_256x64m4w8 +sram22_256x128m4w8 +sram22_512x8m8w1 +sram22_512x32m4w8 +sram22_512x64m4w8 +sram22_512x128m4w8 +sram22_1024x8m8w1 +sram22_1024x32m8w8 +sram22_1024x64m4w8 +sram22_2048x8m8w1 +sram22_2048x32m8w8 +sram22_4096x8m8w1 +sram22_4096x32m8w8 +sram22_8192x32m8w8 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 95% rename from hammer/technology/sky130/extra/sky130_lefpin.map rename to hammer/technology/sky130/sky130_lefpin.map index 8d84b6219..9081d6ca4 100644 --- a/hammer/technology/sky130/extra/sky130_lefpin.map +++ b/hammer/technology/sky130/sky130_lefpin.map @@ -44,4 +44,5 @@ met5 LEFPIN,LEFOBS,PIN,NET,SPNET,VIA 72 20 met5 PIN 72 16 NAME met5/PIN,met5/LEFPIN 72 5 -DIEAREA ALL 235 4 \ No newline at end of file +AREAIDLD ALL 81 14 +DIEAREA ALL 235 4 diff --git a/hammer/technology/sky130/sram-cache.json b/hammer/technology/sky130/sram-cache.json index 045da80ef..150eb9f0d 100644 --- a/hammer/technology/sky130/sram-cache.json +++ b/hammer/technology/sky130/sram-cache.json @@ -1,10 +1,10 @@ [ { "type": "sram", - "name": "sram22_512x32m4w32", + "name": "sram22_64x24m4w8", "source": "sram22", - "depth": "512", - "width": 32, + "depth": "64", + "width": 24, "family": "1rw", "mask": "true", "vt": "svt", @@ -15,6 +15,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -22,14 +24,22 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 32, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x32m4w32", + "name": "sram22_64x32m4w8", "source": "sram22", "depth": "64", "width": 32, @@ -43,6 +53,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -50,17 +62,25 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 32, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_512x64m4w8", + "name": "sram22_128x16m4w8", "source": "sram22", - "depth": "512", - "width": 64, + "depth": "128", + "width": 16, "family": "1rw", "mask": "true", "vt": "svt", @@ -71,6 +91,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -81,14 +103,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_512x32m4w8", + "name": "sram22_128x24m4w8", "source": "sram22", - "depth": "512", - "width": 32, + "depth": "128", + "width": 24, "family": "1rw", "mask": "true", "vt": "svt", @@ -99,6 +129,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -109,14 +141,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x24m4w24", + "name": "sram22_128x32m4w8", "source": "sram22", - "depth": "64", - "width": 24, + "depth": "128", + "width": 32, "family": "1rw", "mask": "true", "vt": "svt", @@ -127,6 +167,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -134,9 +176,93 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 24, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_256x8m8w1", + "source": "sram22", + "depth": "256", + "width": 8, + "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", + "chip enable port name": "ce", + "chip enable 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": 1, + "mask port polarity": "active high" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_256x16m8w8", + "source": "sram22", + "depth": "256", + "width": 16, + "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", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { @@ -155,6 +281,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -165,14 +293,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x4m4w2", + "name": "sram22_256x64m4w8", "source": "sram22", - "depth": "64", - "width": 4, + "depth": "256", + "width": 64, "family": "1rw", "mask": "true", "vt": "svt", @@ -183,6 +319,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -190,17 +328,63 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 2, + "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_2048x32m8w8", + "name": "sram22_256x128m4w8", "source": "sram22", - "depth": "2048", - "width": 32, + "depth": "256", + "width": 128, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_512x8m8w1", + "source": "sram22", + "depth": "512", + "width": 8, "family": "1rw", "mask": "true", "vt": "svt", @@ -211,6 +395,46 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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": 1, + "mask port polarity": "active high" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_512x32m4w8", + "source": "sram22", + "depth": "512", + "width": 32, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -221,14 +445,98 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_1024x32m8w32", + "name": "sram22_512x64m4w8", + "source": "sram22", + "depth": "512", + "width": 64, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_512x128m4w8", + "source": "sram22", + "depth": "512", + "width": 128, + "family": "1rw", + "mask": "true", + "vt": "svt", + "mux": 4, + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable 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" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_1024x8m8w1", "source": "sram22", "depth": "1024", - "width": 32, + "width": 8, "family": "1rw", "mask": "true", "vt": "svt", @@ -239,6 +547,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -246,9 +556,17 @@ "input port name": "din", "input port polarity": "active high", "mask port name": "wmask", - "mask granularity": 32, + "mask granularity": 1, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { @@ -267,6 +585,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -277,14 +597,22 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] }, { "type": "sram", - "name": "sram22_64x32m4w8", + "name": "sram22_1024x64m4w8", "source": "sram22", - "depth": "64", - "width": 32, + "depth": "1024", + "width": 64, "family": "1rw", "mask": "true", "vt": "svt", @@ -295,6 +623,8 @@ "address port polarity": "active high", "clock port name": "clk", "clock port polarity": "active high", + "chip enable port name": "ce", + "chip enable port polarity": "active high", "write enable port name": "we", "write enable port polarity": "active high", "output port name": "dout", @@ -305,6 +635,52 @@ "mask granularity": 8, "mask port polarity": "active high" } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } + ] + }, + { + "type": "sram", + "name": "sram22_2048x8m8w1", + "source": "sram22", + "depth": "2048", + "width": 8, + "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", + "chip enable port name": "ce", + "chip enable 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": 1, + "mask port polarity": "active high" + } + ], + "extra ports": [ + { + "name": "rstb", + "width": 1, + "type": "constant", + "value": 1 + } ] } ] diff --git a/hammer/technology/sky130/sram_compiler/__init__.py b/hammer/technology/sky130/sram_compiler/__init__.py index 7bf277a54..29b544433 100644 --- a/hammer/technology/sky130/sram_compiler/__init__.py +++ b/hammer/technology/sky130/sram_compiler/__init__.py @@ -1,14 +1,23 @@ - -import os, tempfile, subprocess +import os +import tempfile +import subprocess from pathlib import Path -from hammer.vlsi import MMMCCorner, MMMCCornerType, HammerTool, HammerToolStep, HammerSRAMGeneratorTool, SRAMParameters +from hammer.vlsi import ( + MMMCCorner, + MMMCCornerType, + HammerTool, + HammerToolStep, + HammerSRAMGeneratorTool, + SRAMParameters, +) from hammer.tech import Corner, Supplies, Provide from hammer.vlsi.units import VoltageValue, TemperatureValue from hammer.tech import Library, ExtraLibrary from typing import NamedTuple, Dict, Any, List, Optional from abc import ABCMeta, abstractmethod + class SKY130SRAMGenerator(HammerSRAMGeneratorTool): def tool_config_prefix(self) -> str: return "sram_generator.sky130" @@ -20,7 +29,7 @@ def version_number(self, version: str) -> int: def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibrary: cache_dir = os.path.abspath(self.technology.cache_dir) speed_name: Optional[str] = None - #TODO: this is really an abuse of the corner stuff + # TODO: this is really an abuse of the corner stuff if corner.type == MMMCCornerType.Setup: speed_name = "slow" speed = "SS" @@ -34,169 +43,225 @@ def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibr speed = "TT" if params.family != "1rw" and params.family != "1rw1r": - self.logger.error("SKY130 SRAM cache does not support family:{f}".format(f=params.family)) + self.logger.error( + "SKY130 SRAM cache does not support family:{f}".format(f=params.family) + ) return ExtraLibrary(prefix=None, library=None) # type: ignore + # SRAM22 SRAMs if params.name.startswith("sram22"): self.logger.info(f"Compiling {params.family} memories to SRAM22 instances") # s=round(round(params.width*params.depth/8, -3)/1000) # size in kiB - w=params.width - d=params.depth + w = params.width + d = params.depth sram_name = params.name - #TODO: replace this if SRAM22 characterization done for other corners + # TODO: replace this if SRAM22 characterization done for other corners # we only have typical lib for sky130 srams - corner_str = "tt_025C_1v80" - #corner_str = "{speed}_{volt}V_{temp}C".format( - # speed = speed, - # volt = str(corner.voltage.value_in_units("V")).replace(".","p"), - # temp = str(int(corner.temp.value_in_units("C"))).replace(".","p")) + temp = corner.temp.value_in_units("C") + corner_str = "{speed}_{temp}C_{volt}".format( + speed=speed.lower(), + volt="{:.2f}".format(corner.voltage.value_in_units("V")).replace( + ".", "v" + ), + temp=( + "{:03g}".format(temp).replace(".", "p") + if temp > 0 + else "n{:02g}".format(-temp).replace(".", "p") + ), + ) + + base_dir = self.get_setting("technology.sky130.sram22_sky130_macros") + lib_path = "{b}/{n}/{n}_{c}.lib".format( + b=base_dir, n=sram_name, c=corner_str + ) + if not os.path.exists(lib_path): + self.logger.error( + f"""SKY130 {params.family} SRAM cache does not support corner: { + corner_str}""" + ) - base_dir=self.get_setting('technology.sky130.sram22_sky130_macros') + lef_file = "{b}/{n}/{n}.lef".format(b=base_dir, n=sram_name) + if not os.path.exists(lef_file): + self.logger.error(f"No LEF for: {sram_name} ({lef_file})") - found = False - lib_path: Optional[str] = None - for fidelity in ["rcc", "rc", "c"]: - lib_path="{b}/{n}/{n}_{c}.{f}.lib".format(b=base_dir,n=sram_name,c=corner_str, f=fidelity) - if os.path.exists(lib_path): - found = True - break - else: - self.logger.warning(f"SKY130 {params.name} SRAM cache does not support corner {corner_str} with {fidelity} extraction") + return ExtraLibrary( + prefix=None, + library=Library( + name=sram_name, + nldm_liberty_file=lib_path, + lef_file="{b}/{n}/{n}.lef".format(b=base_dir, n=sram_name), + gds_file="{b}/{n}/{n}.gds".format(b=base_dir, n=sram_name), + verilog_sim="{b}/{n}/{n}.v".format(b=base_dir, n=sram_name), + corner=Corner( + nmos=speed_name, + pmos=speed_name, + temperature=str(corner.temp.value_in_units("C")) + " C", + ), + supplies=Supplies( + VDD=str(corner.voltage.value_in_units("V")) + " V", GND="0 V" + ), + provides=[Provide(lib_type="sram", vt=params.vt)], + ), + ) - if not found: - self.logger.error(f"SKY130 {params.name} SRAM cache does not support corner {corner_str}") - assert speed_name - return ExtraLibrary(prefix=None, library=Library( - name=sram_name, - nldm_liberty_file=lib_path, - lef_file="{b}/{n}/{n}.lef".format(b=base_dir,n=sram_name), - gds_file="{b}/{n}/{n}.gds".format(b=base_dir,n=sram_name), - spice_file="{b}/{n}/{n}.spice".format(b=base_dir,n=sram_name), - verilog_sim="{b}/{n}/{n}.v".format(b=base_dir,n=sram_name), - corner=Corner(nmos=speed_name, pmos=speed_name, temperature=str(corner.temp.value_in_units("C")) + " C"), - supplies=Supplies(VDD=str(corner.voltage.value_in_units("V")) + " V", GND="0 V"), - provides=[Provide(lib_type="sram", vt=params.vt)])) - - # TODO: remove OpenRAM support very soon + # OpenRAM SRAMs elif params.name.startswith("sky130_sram_"): self.logger.info(f"Compiling {params.family} memories to OpenRAM instances") base_dir = self.get_setting("technology.sky130.openram_lib") - s=round(round(params.width*params.depth/8, -3)/1000) # size in kiB - w=params.width - d=params.depth - m=8 + # size in kiB + s = round(round(params.width * params.depth / 8, -3) / 1000) + w = params.width + d = params.depth + m = 8 sram_name = f"sky130_sram_{s}kbyte_{params.family}_{w}x{d}_{m}" - #TODO: Hammer SRAMParameters doesn't have this info - #TODO: replace this if OpenRAM characterization done for other corners + # TODO: Hammer SRAMParameters doesn't have this info + # TODO: replace this if OpenRAM characterization done for other corners # we only have typical lib for sky130 srams corner_str = "TT_1p8V_25C" - #corner_str = "{speed}_{volt}V_{temp}C".format( + # corner_str = "{speed}_{volt}V_{temp}C".format( # speed = speed, # volt = str(corner.voltage.value_in_units("V")).replace(".","p"), # temp = str(int(corner.temp.value_in_units("C"))).replace(".","p")) lib_path = "{b}/{n}/{n}_{c}.lib".format( - b=base_dir, - n=sram_name, - c=corner_str) + b=base_dir, n=sram_name, c=corner_str + ) if not os.path.exists(lib_path): - self.logger.error(f"SKY130 {params.family} SRAM cache does not support corner: {corner_str}") + self.logger.error( + f"""SKY130 {params.family} SRAM cache does not support corner: { + corner_str}""" + ) self.setup_openram_spice(sram_name) self.setup_openram_lef(sram_name) self.setup_openram_verilog(sram_name) # self.setup_sram_lib(sram_name) assert speed_name - return ExtraLibrary(prefix=None, library=Library( - name=sram_name, - nldm_liberty_file="{b}/{n}/{n}_{c}.lib".format(b=base_dir,n=sram_name,c=corner_str), - lef_file="{b}/{n}/{n}.lef".format(b=cache_dir,n=sram_name), - gds_file="{b}/{n}/{n}.gds".format(b=base_dir,n=sram_name), - spice_file="{b}/{n}/{n}.lvs.sp".format(b=cache_dir,n=sram_name), - verilog_sim="{b}/{n}/{n}.v".format(b=cache_dir,n=sram_name), - corner=Corner(nmos=speed_name, pmos=speed_name, temperature=str(corner.temp.value_in_units("C")) + " C"), - supplies=Supplies(VDD=str(corner.voltage.value_in_units("V")) + " V", GND="0 V"), - provides=[Provide(lib_type="sram", vt=params.vt)])) + return ExtraLibrary( + prefix=None, + library=Library( + name=sram_name, + nldm_liberty_file="{b}/{n}/{n}_{c}.lib".format( + b=base_dir, n=sram_name, c=corner_str + ), + lef_file="{b}/{n}/{n}.lef".format(b=cache_dir, n=sram_name), + gds_file="{b}/{n}/{n}.gds".format(b=base_dir, n=sram_name), + spice_file="{b}/{n}/{n}.lvs.sp".format(b=cache_dir, n=sram_name), + verilog_sim="{b}/{n}/{n}.v".format(b=cache_dir, n=sram_name), + corner=Corner( + nmos=speed_name, + pmos=speed_name, + temperature=str(corner.temp.value_in_units("C")) + " C", + ), + supplies=Supplies( + VDD=str(corner.voltage.value_in_units("V")) + " V", GND="0 V" + ), + provides=[Provide(lib_type="sram", vt=params.vt)], + ), + ) else: self.logger.error(f"SRAM {params.name} not supported") return ExtraLibrary(prefix=None, library=Library()) - - def setup_openram_spice(self,sram_name) -> None: - source_path = Path(self.get_setting("technology.sky130.openram_lib")) / sram_name / f"{sram_name}.lvs.sp" - dest_path = f"{os.path.abspath(self.technology.cache_dir)}/{sram_name}/{sram_name}.lvs.sp" + def setup_openram_spice(self, sram_name) -> None: + source_path = ( + Path(self.get_setting("technology.sky130.openram_lib")) + / sram_name + / f"{sram_name}.lvs.sp" + ) + dest_path = f"""{os.path.abspath( + self.technology.cache_dir)}/{sram_name}/{sram_name}.lvs.sp""" self.technology.ensure_dirs_exist(dest_path) if not source_path.exists(): - raise FileNotFoundError(f"SRAM Spice file not found: {source_path}") - with open(source_path,'r') as sf: - with open(dest_path,'w') as df: - self.logger.info("Modifying SRAM SPICE file: {} -> {}".format - (source_path, dest_path)) + raise FileNotFoundError(f"SRAM Spice file not found: {source_path}") + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying SRAM SPICE file: {} -> {}".format(source_path, dest_path) + ) for line in sf: - line = line.replace('sky130_fd_pr__pfet_01v8','pshort') - line = line.replace('sky130_fd_pr__nfet_01v8','nshort') + line = line.replace("sky130_fd_pr__pfet_01v8", "pshort") + line = line.replace("sky130_fd_pr__nfet_01v8", "nshort") if sram_name == "sky130_sram_1kbyte_1rw1r_8x1024_8": - line = line.replace('wmask0[0]' , 'wmask0') + line = line.replace("wmask0[0]", "wmask0") df.write(line) - - def setup_openram_lef(self,sram_name) -> None: - source_path = Path(self.get_setting("technology.sky130.openram_lib")) / sram_name / f"{sram_name}.lef" - dest_path = f"{os.path.abspath(self.technology.cache_dir)}/{sram_name}/{sram_name}.lef" + def setup_openram_lef(self, sram_name) -> None: + source_path = ( + Path(self.get_setting("technology.sky130.openram_lib")) + / sram_name + / f"{sram_name}.lef" + ) + dest_path = f"""{os.path.abspath(self.technology.cache_dir) + }/{sram_name}/{sram_name}.lef""" self.technology.ensure_dirs_exist(dest_path) if not source_path.exists(): raise FileNotFoundError(f"SRAM LEF file not found: {source_path}") - with open(source_path,'r') as sf: - with open(dest_path,'w') as df: - self.logger.info("Modifying SRAM LEF file: {} -> {}".format - (source_path, dest_path)) - units=False + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying SRAM LEF file: {} -> {}".format(source_path, dest_path) + ) + units = False for line in sf: if line.strip().startswith("UNITS"): - units=True + units = True if line.strip().startswith("END UNITS"): - units=False + units = False continue if not units: df.write(line) - def setup_openram_verilog(self, sram_name) -> None: - """ Move 'mem' declaration before it is referenced in the verilog. """ - source_path = Path(self.get_setting("technology.sky130.openram_lib")) / sram_name / f"{sram_name}.v" - dest_path = f"{os.path.abspath(self.technology.cache_dir)}/{sram_name}/{sram_name}.v" + """Move 'mem' declaration before it is referenced in the verilog.""" + source_path = ( + Path(self.get_setting("technology.sky130.openram_lib")) + / sram_name + / f"{sram_name}.v" + ) + dest_path = f"""{os.path.abspath(self.technology.cache_dir) + }/{sram_name}/{sram_name}.v""" if not source_path.exists(): raise FileNotFoundError(f"SRAM Spice file not found: {source_path}") self.technology.ensure_dirs_exist(dest_path) - with open(source_path,'r') as sf: - with open(dest_path,'w') as df: - self.logger.info("Modifying SRAM Verilog file: {} -> {}".format - (source_path, dest_path)) + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying SRAM Verilog file: {} -> {}".format( + source_path, dest_path + ) + ) lines = sf.readlines() insert_idx = 0 - for i,line in enumerate(lines): - if insert_idx == 0 and line.strip().startswith('always'): + for i, line in enumerate(lines): + if insert_idx == 0 and line.strip().startswith("always"): insert_idx = i elif line.strip() == "reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];": lines.pop(i) - lines.insert(insert_idx,line) - df.write(''.join(lines)) + lines.insert(insert_idx, line) + df.write("".join(lines)) def setup_sram_lib(self, sram_name) -> None: - """ Flip endianness of SRAM ports. """ - source_path = Path(self.get_setting("technology.sky130.openram_lib")) / sram_name / f"{sram_name}_TT_1p8V_25C.lib" - dest_path = f"{os.path.abspath(self.technology.cache_dir)}/{sram_name}/{sram_name}.v" + """Flip endianness of SRAM ports.""" + source_path = ( + Path(self.get_setting("technology.sky130.openram_lib")) + / sram_name + / f"{sram_name}_TT_1p8V_25C.lib" + ) + dest_path = f"""{os.path.abspath(self.technology.cache_dir) + }/{sram_name}/{sram_name}.v""" if not source_path.exists(): raise FileNotFoundError(f"SRAM Lib file not found: {source_path}") self.technology.ensure_dirs_exist(dest_path) - with open(source_path,'r') as sf: - with open(dest_path,'w') as df: - self.logger.info("Modifying SRAM Lib file: {} -> {}".format - (source_path, dest_path)) + with open(source_path, "r") as sf: + with open(dest_path, "w") as df: + self.logger.info( + "Modifying SRAM Lib file: {} -> {}".format(source_path, dest_path) + ) lines = sf.readlines() insert_idx = 0 - bit_from_line, bit_to_line = None,None + bit_from_line, bit_to_line = None, None # swap_bits = False - for i,line in enumerate(lines): + for i, line in enumerate(lines): if line.strip().startswith("bit_from"): bit_from_line = line elif line.strip().startswith("bit_to"): @@ -204,13 +269,24 @@ def setup_sram_lib(self, sram_name) -> None: else: df.write(line) if bit_from_line is not None and bit_to_line is not None: - bit_from = bit_from_line.strip().replace(':','').replace(';','').split()[1] - bit_to = bit_to_line.strip().replace(':','').replace(';','').split()[1] + bit_from = ( + bit_from_line.strip() + .replace(":", "") + .replace(";", "") + .split()[1] + ) + bit_to = ( + bit_to_line.strip() + .replace(":", "") + .replace(";", "") + .split()[1] + ) if int(bit_from) > int(bit_to): - bit_from_line = bit_from_line.replace(bit_from,bit_to) - bit_to_line = bit_to_line.replace(bit_to,bit_from) + bit_from_line = bit_from_line.replace(bit_from, bit_to) + bit_to_line = bit_to_line.replace(bit_to, bit_from) df.write(bit_from_line) df.write(bit_to_line) - bit_from_line, bit_to_line = None,None + bit_from_line, bit_to_line = None, None + -tool=SKY130SRAMGenerator +tool = SKY130SRAMGenerator 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 eedc9af9d..fa817eedd 100644 --- a/hammer/vlsi/driver.py +++ b/hammer/vlsi/driver.py @@ -152,18 +152,17 @@ 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.override_tech_libraries() tech.get_lib_units() self.tech = tech diff --git a/hammer/vlsi/units.py b/hammer/vlsi/units.py index e3129f0ba..8f3a884ea 100644 --- a/hammer/vlsi/units.py +++ b/hammer/vlsi/units.py @@ -74,7 +74,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,