diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 3e8fd1f4..594c4032 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -29,7 +29,7 @@ jobs: run: | eval "$(micromamba shell hook --shell=bash)" micromamba activate - micromamba install -c conda-forge pymeep=*=mpi_mpich_* nlopt -y + micromamba install -c conda-forge pymeep=*=mpi_mpich_* nlopt hdl21 -y make dev test-data make docs - name: Upload artifact diff --git a/.github/workflows/test_code.yml b/.github/workflows/test_code.yml index 8152c256..9e568d20 100644 --- a/.github/workflows/test_code.yml +++ b/.github/workflows/test_code.yml @@ -29,7 +29,7 @@ jobs: fail-fast: false max-parallel: 12 matrix: - plugin: [femwell, gmsh, meow, sax, tidy3d, klayout, vlsir] + plugin: [femwell, gmsh, meow, sax, tidy3d, klayout, vlsir, hdl21] name: Test ${{ matrix.plugin }} steps: diff --git a/.gitignore b/.gitignore index d489743c..06a660b2 100644 --- a/.gitignore +++ b/.gitignore @@ -172,6 +172,7 @@ cython_debug/ .DS_Store *Thumbs.db + # Possible generated files *.cmd *.tcl @@ -180,3 +181,5 @@ cython_debug/ *.BAK *.sav *.plt +.virtual_documents +.idea diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..7cd96c2e --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +gplugins_spice diff --git a/gplugins/hdl21/__init__.py b/gplugins/hdl21/__init__.py new file mode 100644 index 00000000..8f04598f --- /dev/null +++ b/gplugins/hdl21/__init__.py @@ -0,0 +1,19 @@ +from .netlist import ( + ParsedProtoVLSIR, + generate_raw_netlist_dict_from_module, + generate_raw_yaml_from_module, +) +from .sky130 import ( + filter_port, + find_most_relevant_gds, + hdl21_module_to_schematic_editor, +) + +__all__ = [ + "filter_port", + "find_most_relevant_gds", + "hdl21_module_to_schematic_editor", + "generate_raw_yaml_from_module", + "generate_raw_netlist_dict_from_module", + "ParsedProtoVLSIR", +] diff --git a/gplugins/hdl21/netlist.py b/gplugins/hdl21/netlist.py new file mode 100644 index 00000000..2b7e11cb --- /dev/null +++ b/gplugins/hdl21/netlist.py @@ -0,0 +1,293 @@ +""" +This module provides functions to generate a raw netlist semi-compatible with gdsfactory from a hdl21 module object. +""" + +import hdl21 as h +import yaml + +ParsedProtoVLSIR = dict + + +def _parse_module_to_proto_dict(module: h.module) -> ParsedProtoVLSIR: + """ + Parse a hdl21 module object into a dictionary with the same structure as the proto VLSIR format. + """ + + def parse_value(lines, index): + value = {} + while index < len(lines): + line = lines[index].strip() + if line == "}": + return value, index + elif line.endswith("{"): + key = line[:-1].strip() + sub_value, new_index = parse_value(lines, index + 1) + if key not in value: + value[key] = [] + value[key].append(sub_value) + index = new_index + else: + key, val = line.split(":", 1) + value[key.strip()] = val.strip().strip('"') + index += 1 + return value, index + + raw_proto_str = str(h.to_proto(module)) + lines = raw_proto_str.split("\n") + result = {} + index = 0 + while index < len(lines): + line = lines[index].strip() + if line.endswith("{"): + key = line[:-1].strip() + sub_value, new_index = parse_value(lines, index + 1) + if key not in result: + result[key] = [] + result[key].append(sub_value) + index = new_index + else: + index += 1 + + return result + + +def _parse_connections(proto_dict: ParsedProtoVLSIR) -> dict: + """ + Extract the connections from the proto_dict and return a dictionary with the connections. + """ + connections = {} + + # Extract the instances and their connections + for module in proto_dict.get("modules", []): + for instance in module.get("instances", []): + instance_name = instance["name"] + for connection in instance.get("connections", []): + portname = connection["portname"] + target = connection["target"][0] + + # Handle different structures of target + if "sig" in target: + target_signal = target["sig"] + elif "slice" in target: + target_signal = target["slice"][0]["signal"] + else: + # Log a warning or provide a default value for unknown structures + target_signal = "unknown_signal" + print( + f"Warning: Unknown target structure in connection for instance '{instance_name}', port '{portname}'" + ) + + connection_key = f"{instance_name},{portname}" + # Find the target instance and port + target_instance_port = _find_target_instance_port( + proto_dict, target_signal, instance_name + ) + if target_instance_port: + connections[connection_key] = target_instance_port + + return connections + + +def _find_target_instance_port( + proto_dict: ParsedProtoVLSIR, target_signal, current_instance_name +): + """ + Find the target instance and port of the target signal in the proto_dict. + """ + # Search in the same module + for module in proto_dict.get("modules", []): + for instance in module.get("instances", []): + if instance["name"] == current_instance_name: + continue + for connection in instance.get("connections", []): + target = connection["target"][0] + + # Handle different structures of target + if "sig" in target: + signal = target["sig"] + elif "slice" in target: + signal = target["slice"][0]["signal"] + else: + signal = None + print( + f"Warning: Unknown target structure for instance '{instance['name']}', port '{connection['portname']}'" + ) + + if signal == target_signal: + return f"{instance['name']},{connection['portname']}" + + # Search in external modules + for ext_module in proto_dict.get("ext_modules", []): + for port in ext_module.get("ports", []): + if port["signal"] == target_signal: + for instance in module.get("instances", []): + if instance["name"] == current_instance_name: + continue + for connection in instance.get("connections", []): + target = connection["target"][0] + + if "sig" in target: + signal = target["sig"] + elif "slice" in target: + signal = target["slice"][0]["signal"] + else: + signal = None + print( + f"Warning: Unknown target structure for instance '{instance['name']}', port '{connection['portname']}'" + ) + + if signal == target_signal: + return f"{instance['name']},{connection['portname']}" + + return None + + +def _generate_top_level_connections(proto_dict: ParsedProtoVLSIR): + """ + Generate the top-level connections from the proto_dict. + """ + top_level_connections = {} + + # Iterate over the top-level module ports + for module in proto_dict.get("modules", []): + for port in module.get("ports", []): + port_signal = port["signal"] + connection = _find_port_connection(proto_dict, port_signal) + if connection: + top_level_connections[port_signal] = connection + + return top_level_connections + + +def _find_port_connection(proto_dict: ParsedProtoVLSIR, port_signal): + """ + Find the connection of the port signal in the proto_dict. + """ + # Search within the module instances + for module in proto_dict.get("modules", []): + for instance in module.get("instances", []): + instance_name = instance["name"] + for connection in instance.get("connections", []): + target = connection["target"][0] + + # Handle different structures of target + if "sig" in target: + signal = target["sig"] + elif "slice" in target: + signal = target["slice"][0]["signal"] + else: + signal = None + print( + f"Warning: Unknown target structure in connection for instance '{instance_name}', port '{connection['portname']}'" + ) + + if signal == port_signal: + return f"{instance_name},{connection['portname']}" + return None + + +def _extract_instance_parameters(proto_dict: ParsedProtoVLSIR): + """ + Extract the instance parameters from the proto_dict. + """ + instance_parameters = {} + + for module in proto_dict.get("modules", []): + for instance in module.get("instances", []): + instance_name = instance["name"] + instance_info = { + "component": _extract_component_name(instance), + "info": {}, + "settings": {}, + } + + # Extract parameters into the settings + for parameter in instance.get("parameters", []): + param_name = parameter["name"] + param_value = _extract_parameter_value(parameter["value"]) + instance_info["settings"][param_name] = param_value + + # Extract connections and add to settings + instance_info["settings"]["ports"] = {} + for connection in instance.get("connections", []): + portname = connection["portname"] + target = connection["target"][0] + + if "sig" in target: + target_signal = target["sig"] + elif "slice" in target: + target_signal = target["slice"][0]["signal"] + else: + # Handle cases where 'target' does not have 'sig' or 'slice' + target_signal = "unknown_signal" + + instance_info["settings"]["ports"][portname] = target_signal + + instance_parameters[instance_name] = instance_info + + return instance_parameters + + +def _extract_component_name(instance): + """ + Extract the component name from the instance. + """ + external_modules = instance.get("module", []) + if external_modules: + name = external_modules[0].get("external", [{}])[0].get("name", "") + return f"{name}" + return "unknown_component" + + +def _extract_parameter_value(value): + """ + Extract the parameter value from the value dictionary. + """ + if value and "literal" in value[0]: + return value[0]["literal"] + elif value and "prefixed" in value[0]: + prefix = value[0]["prefixed"][0].get("prefix", "") + int64_value = value[0]["prefixed"][0].get("int64_value", "") + return f"{prefix}_{int64_value}" + return None + + +def _generate_raw_netlist_dict_from_proto_dict(proto_dict: ParsedProtoVLSIR): + """ + Generate a raw netlist dictionary from the proto_dict. + """ + raw_netlist_dict = {"name": "", "instances": {}, "connections": {}, "ports": {}} + + # Extract the top-level module name + if proto_dict.get("modules"): + raw_netlist_dict["name"] = proto_dict["modules"][0].get("name", "") + + # Generate instances information + raw_netlist_dict["instances"] = _extract_instance_parameters(proto_dict) + + # Generate connections + raw_netlist_dict["connections"] = _parse_connections(proto_dict) + + # Generate top-level connections + raw_netlist_dict["ports"] = _generate_top_level_connections(proto_dict) + + return raw_netlist_dict + + +def generate_raw_netlist_dict_from_module(module: h.module): + """ + Generate a raw netlist dictionary from a hdl21 module object. + This just gives us a raw structure of the hdl21 modules, we cannot use this json equivalently to a gdsfactory netlist. + """ + proto_dict = _parse_module_to_proto_dict(module) + return _generate_raw_netlist_dict_from_proto_dict(proto_dict) + + +def generate_raw_yaml_from_module(module: h.module): + """ + Generate a raw netlist yaml from a hdl21 module object which could be manually edited for specific instances + related to the corresponding SPICE. + """ + + raw_netlist = generate_raw_netlist_dict_from_module(module) + return yaml.dump(raw_netlist, default_flow_style=False) diff --git a/gplugins/hdl21/sky130.py b/gplugins/hdl21/sky130.py new file mode 100644 index 00000000..e957737e --- /dev/null +++ b/gplugins/hdl21/sky130.py @@ -0,0 +1,96 @@ +from collections.abc import Callable +from difflib import get_close_matches + +import hdl21 as h +import sky130 + +from ..schematic_editor import SchematicEditor +from .netlist import ( + _generate_raw_netlist_dict_from_proto_dict, + _parse_module_to_proto_dict, +) + +custom_mapping_dict = { + "sky130_fd_pr__nfet_01v8": "sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p15", + "sky130_fd_pr__pfet_01v8": "sky130_fd_pr__rf_pfet_01v8_mcM04W3p00L0p15", + "sky130_fd_pr__res_generic_po": "p_n_poly", +} + + +def find_most_relevant_gds( + component_name, component_dict=sky130.cells, custom_mapping=None +): + if custom_mapping is None: + custom_mapping = custom_mapping_dict + + if component_name in custom_mapping.keys(): + print(f"Mapping for {component_name}: {custom_mapping[component_name]}") + return custom_mapping[component_name] + + all_components = [ + name for name in component_dict.keys() if "rf_test_coil" not in name + ] + closest_matches = get_close_matches(component_name, all_components, n=1, cutoff=0.1) + print(f"Closest matches for {component_name}: {closest_matches}") + return closest_matches[0] if closest_matches else component_name + + +def filter_port(port): + """ + Filter the port name to match spice declaration to gds port name, specifically focused on the SKY130nm technology. + """ + if port == "d": + return "DRAIN" + elif port == "g": + return "GATE" + elif port == "s": + return "SOURCE" + else: + return port + + +def hdl21_module_to_schematic_editor( + module: h.module, + yaml_schematic_file_name: str, + spice_gds_mapping_method: Callable | None = find_most_relevant_gds, + port_filter_method: Callable = filter_port, +) -> SchematicEditor: + """ + Constructs a SchematicEditor instance from a hdl21 module object. + + Args: + module (h.module): The hdl21 module object. + yaml_schematic_file_name (str): The yaml schematic file name. + spice_gds_mapping_method (Callable): The method to map the spice instance name to the component name. + port_filter_method (Callable): The method to filter the port name. + """ + proto_dict = _parse_module_to_proto_dict(module) + raw_netlist_dict = _generate_raw_netlist_dict_from_proto_dict(proto_dict) + + # This just gives us a raw structure of the hdl21 modules. + se = SchematicEditor(yaml_schematic_file_name) + + for instance_name_i, instance_i in raw_netlist_dict["instances"].items(): + # Maps the spice instance name to the component name. + # TODO implement setting mapping and custom name mapping + if spice_gds_mapping_method is None: + gds_component_name_i = instance_i["component"] + else: + gds_component_name_i = spice_gds_mapping_method( + instance_i["component"], sky130.cells + ) + se.add_instance( + instance_name=instance_name_i, + component=sky130.cells[gds_component_name_i](), + ) + + for connection_source_i, connection_target_i in raw_netlist_dict[ + "connections" + ].items(): + source_instance, source_port = connection_source_i.split(",") + target_instance, target_port = connection_target_i.split(",") + source_port = port_filter_method(source_port) + target_port = port_filter_method(target_port) + se.add_net(source_instance, source_port, target_instance, target_port) + + return se diff --git a/gplugins/schematic_editor/schematic_editor.py b/gplugins/schematic_editor/schematic_editor.py index 5c280947..8350efcc 100644 --- a/gplugins/schematic_editor/schematic_editor.py +++ b/gplugins/schematic_editor/schematic_editor.py @@ -327,16 +327,19 @@ def update_settings( instance_name=instance, settings=settings, old_settings=old_settings ) - def add_net(self, inst1, port1, inst2, port2): + def add_net(self, inst1, port1, inst2, port2, allow_multiple: bool = False) -> None: p1 = f"{inst1},{port1}" p2 = f"{inst2},{port2}" if p1 in self._connected_ports: - if self._connected_ports[p1] == p2: - return - current_port = self._connected_ports[p1] - raise ValueError( - f"{p1} is already connected to {current_port}. Can't connect to {p2}" - ) + if allow_multiple: + pass + else: + if self._connected_ports[p1] == p2: + return + current_port = self._connected_ports[p1] + raise ValueError( + f"{p1} is already connected to {current_port}. Can't connect to {p2}" + ) self._connected_ports[p1] = p2 self._connected_ports[p2] = p1 old_nets = self._schematic.nets.copy() diff --git a/gplugins/spice/parse_netlist.py b/gplugins/spice/parse_netlist.py new file mode 100644 index 00000000..37909d74 --- /dev/null +++ b/gplugins/spice/parse_netlist.py @@ -0,0 +1,180 @@ +import re +from typing import Literal + +# Your netlist text as a string +# TODO CHECK This is from lumerical interconnect right? +netlist_text = """ +* Netlist generated with INTERCONNECT on Fri Dec 8 11:06:53 2023 + +* +* Component pathname : compound_1 +* +.subckt COMPOUND_1 PORT_1 PORT_2 PORT_3 PORT_4 PORT_5 PORT_6 PORT_7 PORT_8 + X_dc_1 PORT_1 PORT_2 N$1 N$3 ebeam_dc_te1550 coupling_length=17.5u sch_x=-0.245 sch_y=1.205 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_dc_2 N$1 N$3 PORT_3 PORT_4 ebeam_dc_te1550 coupling_length=17.5u sch_x=0.79 sch_y=0.38 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_dc_3 PORT_5 PORT_7 N$11 N$13 ebeam_dc_te1550 coupling_length={%test_param1%*1e-6} sch_x=-1.3 sch_y=-1.585 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_ebeam_y_1550_1 N$8 N$13 N$11 ebeam_y_1550 sch_x=0.95 sch_y=-1.58 sch_r=180 sch_f=f lay_x=0 lay_y=0 + X_ebeam_y_1550_2 N$8 PORT_6 PORT_8 ebeam_y_1550 sch_x=1.89 sch_y=-1.58 sch_r=0 sch_f=f lay_x=0 lay_y=0 +.ends COMPOUND_1 + +* +* MAIN CELL: Component pathname : root_element +* + .MODEL ebeam_dc_te1550 radius=5u gap=0.2u note=".- The current model only supports "coupling_length" as an input parameter..- The other parameters + (i.e., "wg_width", "gap", "radius") are now fixed but will be parameterized in the future." + + wg_width=0.5u library="design_kit/ebeam" + .MODEL ebeam_gc_te1550 MC_grid={%MC_grid%} MC_non_uniform={%MC_non_uniform%} MC_resolution_x={%MC_resolution_x%} + + MC_resolution_y={%MC_resolution_y%} MC_uniformity_thickness={%MC_uniformity_thickness%} MC_uniformity_width={%MC_uniformity_width%} + + library="design_kit/ebeam" + .MODEL ebeam_y_1550 Model_Version="2016/04/07" MC_grid={%MC_grid%} MC_non_uniform={%MC_non_uniform%} + + MC_resolution_x={%MC_resolution_x%} MC_resolution_y={%MC_resolution_y%} MC_uniformity_thickness={%MC_uniformity_thickness%} + + MC_uniformity_width={%MC_uniformity_width%} library="design_kit/ebeam" + .MODEL wg_heater wg_length=0.0001 library="design_kit/ebeam" + X_COMPOUND_1 N$1 N$2 N$5 N$4 N$7 N$10 N$9 N$8 COMPOUND_1 test_param2=2 test_param1=3 sch_x=0.75 sch_y=0 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_ebeam_y_1550_1 N$6 N$1 N$2 ebeam_y_1550 sch_x=-0.22 sch_y=0.005 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_ebeam_y_1550_2 N$3 N$4 N$5 ebeam_y_1550 sch_x=2.795 sch_y=1.665 sch_r=180 sch_f=f lay_x=0 lay_y=0 + X_TE1550_SubGC_neg31_oxide_1 N$17 N$6 ebeam_gc_te1550 sch_x=-2.175 sch_y=-0.05 sch_r=180 sch_f=f lay_x=0 lay_y=0 + X_TE1550_SubGC_neg31_oxide_2 N$18 N$3 ebeam_gc_te1550 sch_x=4.435 sch_y=2.655 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_ebeam_y_1550_3 N$14 N$7 N$9 ebeam_y_1550 sch_x=-1.42 sch_y=-1.31 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_ebeam_y_1550_4 N$16 N$8 N$10 ebeam_y_1550 sch_x=4.525 sch_y=-1.395 sch_r=180 sch_f=f lay_x=0 lay_y=0 + X_wg_heater_1 N$12 N$11 N$13 N$15 wg_heater sch_x=2.11 sch_y=-3.82 sch_r=180 sch_f=f lay_x=0 lay_y=0 + X_wg_heater_2 N$11 N$12 N$16 N$14 wg_heater sch_x=2.085 sch_y=-2.645 sch_r=180 sch_f=f lay_x=0 lay_y=0 + X_TE1550_SubGC_neg31_oxide_3 N$19 N$13 ebeam_gc_te1550 sch_x=4.205 sch_y=-3.99 sch_r=0 sch_f=f lay_x=0 lay_y=0 + X_TE1550_SubGC_neg31_oxide_4 N$20 N$15 ebeam_gc_te1550 sch_x=-4.305 sch_y=-4.13 sch_r=180 sch_f=f lay_x=0 lay_y=0 +* +.end + +*# ebeam_dc_te1550 opt_1(opt) opt_2(opt) opt_3(opt) opt_4(opt) +*# ebeam_gc_te1550 opt_fiber(opt) opt_wg(opt) +*# ebeam_y_1550 opt_a1(opt) opt_b1(opt) opt_b(opt) +*# wg_heater ele_1(ele) ele_2(ele) opt_1(opt) opt_2(opt) +""" +SupportedSpiceTypes = Literal["lumerical", "xschem"] + + +def parse_netlist_and_extract_elements( + netlist_text, spice_type: SupportedSpiceTypes = "lumerical" +): + elements = [] # To store elements like components and subcircuits + connections = [] # To store connections (routes) between elements + settings = [] # To store settings like .MODEL definitions + + if spice_type == "lumerical": + lines = netlist_text.split("\n") + for line in lines: + line = line.strip() + # Skip comments and empty lines + if not line or line.startswith("*"): + continue + + # Handle .subckt, .ends, and .MODEL lines specifically + if line.startswith(".subckt"): + parts = re.split(r"\s+", line) + subckt_name = parts[1] + ports = parts[2:] + elements.append({"type": "subckt", "name": subckt_name, "ports": ports}) + elif line.startswith(".ends"): + continue + elif line.startswith(".MODEL"): + model_definition = re.split(pattern=r"\s+", string=line, maxsplit=1)[1] + model_name, model_params = model_definition.split(" ", 1) + elements.append( + {"type": "model", "name": model_name, "params": model_params} + ) + else: + # Assuming remaining lines are component instances + parts = re.split(r"\s+", line) + component_type = parts[0] + component_name = parts[-1] + # Extract connections from the nodes + parts = parts[1:-1] + nodes = [] + for i in range(len(parts) - 1): + if "=" not in parts[i + 1]: + nodes.append({"from": component_name, "to": parts[i]}) + else: + component_name = parts[i] + settings.append(parts[i + 1 :]) + break + + elements.append( + { + "type": "component", + "name": component_name, + "component_type": component_type, + "nodes": nodes, + "settings": settings, + } + ) + + elif spice_type == "xschem": + lines = netlist_text.split("\n") + for line in lines: + line = line.strip() + if not line or line.startswith( + "v {" + ): # Skip the version line and empty lines + continue + + if line.startswith("C {"): + parts = line.split(" ") + component_info = parts[1].strip("{}") + x, y = parts[2], parts[3] + attributes_str = " ".join(parts[4:]) + match = re.search( + r"\{(.*)\}", attributes_str + ) # Attempt to find the attributes + + if match: # Check if a match was found + attributes = match.group(1) + name_match = re.search(r"name=([^ ]+)", attributes) + label_match = re.search(r"lab=([^}\n]+)", attributes) + name = name_match.group(1) if name_match else "" + label = label_match.group(1) if label_match else "" + + additional_settings = re.findall(r"(\w+)=([^\s}]+)", attributes) + settings_dict = dict(additional_settings) + + elements.append( + { + "type": "component", + "component_type": component_info, + "position": {"x": x, "y": y}, + "name": name, + "label": label, + "settings": settings_dict, + } + ) + else: + # Handle lines that do not match the expected format + print(f"Warning: Line skipped due to unexpected format: {line}") + elif line.startswith("N "): + parts = line.split(" ") + x1, y1, x2, y2 = parts[1], parts[2], parts[3], parts[4] + attributes_str = " ".join(parts[5:]) + label_match = re.search(r"lab=([^}\n]+)", attributes_str) + label = label_match.group(1) if label_match else "" + + connections.append( + { + "start": {"x": x1, "y": y1}, + "end": {"x": x2, "y": y2}, + "label": label, + } + ) + + return elements, connections, settings + + +if __name__ == "__main__": + # Extract elements and connections + elements, connections = parse_netlist_and_extract_elements(netlist_text) + + # Example output + print("Elements:") + for element in elements: + print(element) + + print("\nConnections:") + for connection in connections: + print(connection) diff --git a/notebooks/20_schematic_driven_layout.ipynb b/notebooks/20_schematic_driven_layout.ipynb index 661f36e2..951a3425 100644 --- a/notebooks/20_schematic_driven_layout.ipynb +++ b/notebooks/20_schematic_driven_layout.ipynb @@ -360,7 +360,7 @@ "custom_cell_magics": "kql" }, "kernelspec": { - "display_name": "base", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -374,7 +374,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/notebooks/22_sky130nm_inverter_schematic_to_layout.ipynb b/notebooks/22_sky130nm_inverter_schematic_to_layout.ipynb new file mode 100644 index 00000000..e78dca39 --- /dev/null +++ b/notebooks/22_sky130nm_inverter_schematic_to_layout.ipynb @@ -0,0 +1,690 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# SkyWater Inverter Design using GPlugins\n", + "\n", + "The goal of this notebook is to demonstrate the integration of the `sky130nm` electronic PDK within a gdsfactory-based schematic driven layout. Broadly, we will explore:\n", + "\n", + "* A little introduction at setting up the existing open-source electronic EDA development flow with `xschem` using the latest `sky130nm` library\n", + "* Exporting that schematic into a SPICE model, which is used to schematic-driven-layout using gdsfactory.\n", + "* Example inverter design and layout between the toolsets." + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "## Using the `gdsfactory-sky130nm` Repository" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "The goal of this notebook is to show that analogue simulation and layout can be performed together within a `gdsfactory` environment." + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "```\n", + "pip install gplugins[hdl21,sky130]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "import hdl21 as h\n", + "import gdsfactory as gf\n", + "import gplugins.hdl21 as gph\n", + "import sky130\n", + "import sky130_hdl21\n", + "\n", + "from bokeh.io import output_notebook\n", + "from gdsfactory.config import rich_output\n", + "from gplugins.schematic_editor import SchematicEditor\n", + "\n", + "gf.config.rich_output()\n", + "\n", + "%env BOKEH_ALLOW_WS_ORIGIN=*\n", + "\n", + "output_notebook()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": {}, + "outputs": [], + "source": [ + "# sky130.cells\n", + "# sky130.cells[\"sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield\"]()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "@h.module\n", + "class SkyInv:\n", + " \"\"\" An inverter, demonstrating using PDK modules \"\"\"\n", + "\n", + " # Create some IO\n", + " i, o, VDD, VSS = h.Ports(4)\n", + "\n", + " p = sky130_hdl21.Sky130MosParams(w=1,l=1)\n", + "\n", + " # And create some transistors!\n", + " ps = sky130_hdl21.primitives.PMOS_1p8V_STD(p)(d=o, g=i, s=VDD, b=VDD)\n", + " ns = sky130_hdl21.primitives.NMOS_1p8V_STD(p)(d=VSS, g=i, s=o, b=VSS)" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "### Manually editing the `SPICE`-generated `gdsfactory` component YAML\n", + "\n", + "It is important to know that with the SPICE-generated YAML, we cannot actually create a layout on its own. This is because the SPICE models do not exactly directly map to layout instances. SPICE models can represent performance corners for the same device, with multiple temperature or yield quality variations. As such, we need to assign the corresponding gds we want to layout for our specific schematic model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "example_inverter_manual_yaml = gph.generate_raw_yaml_from_module(\n", + " SkyInv\n", + ")\n", + "print(example_inverter_manual_yaml)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "example_inverter_manual_yaml = \"\"\"\n", + "connections:\n", + " ns,d: ps,d\n", + " ns,g: ps,g\n", + " ps,d: ns,d\n", + " ps,g: ns,g\n", + "instances:\n", + " ns:\n", + " component: sky130_fd_pr__nfet_01v8\n", + " info: {}\n", + " settings:\n", + " As: int((nf+2)/2) * w/nf * 0.29\n", + " ad: int((nf+1)/2) * w/nf * 0.29\n", + " l: UNIT_1\n", + " m: UNIT_1\n", + " mult: UNIT_1\n", + " nf: UNIT_1\n", + " nrd: 0.29 / w\n", + " nrs: 0.29 / w\n", + " pd: 2*int((nf+1)/2) * (w/nf + 0.29)\n", + " ports:\n", + " b: VSS\n", + " d: o\n", + " g: i\n", + " s: VSS\n", + " ps: 2*int((nf+2)/2) * (w/nf + 0.29)\n", + " sa: UNIT_0\n", + " sb: UNIT_0\n", + " sd: UNIT_0\n", + " w: UNIT_1\n", + " ps:\n", + " component: sky130_fd_pr__pfet_01v8\n", + " info: {}\n", + " settings:\n", + " As: int((nf+2)/2) * w/nf * 0.29\n", + " ad: int((nf+1)/2) * w/nf * 0.29\n", + " l: UNIT_1\n", + " m: UNIT_1\n", + " mult: UNIT_1\n", + " nf: UNIT_1\n", + " nrd: 0.29 / w\n", + " nrs: 0.29 / w\n", + " pd: 2*int((nf+1)/2) * (w/nf + 0.29)\n", + " ports:\n", + " b: VDD\n", + " d: o\n", + " g: i\n", + " s: VDD\n", + " ps: 2*int((nf+2)/2) * (w/nf + 0.29)\n", + " sa: UNIT_0\n", + " sb: UNIT_0\n", + " sd: UNIT_0\n", + " w: UNIT_1\n", + "name: SkyInv\n", + "ports:\n", + " VDD: ps,s\n", + " VSS: ns,s\n", + " i: ps,g\n", + " o: ps,d\n", + "\"\"\"\n", + "with open(\"data/sky130nm/example_inverter_manual.schem.yaml\", 'w') as file:\n", + " file.write(example_inverter_manual_yaml)" + ] + }, + { + "cell_type": "markdown", + "id": "10", + "metadata": {}, + "source": [ + "### Automatically mapping layout instances to the YAML - Inverter" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11", + "metadata": {}, + "outputs": [], + "source": [ + "example_inverter_schematic_editor = gph.hdl21_module_to_schematic_editor(\n", + " module=SkyInv,\n", + " yaml_schematic_file_name=\"data/sky130nm/example_inverter_auto.schem.yaml\",\n", + ")\n", + "example_inverter_schematic_editor.visualize()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "example_inverter_layout = \"data/sky130nm/example_inverter_auto.layout.yaml\"\n", + "example_inverter_schematic_editor.instantiate_layout(example_inverter_layout, default_router=\"get_bundle\", default_cross_section=\"xs_metal1\")\n", + "c = gf.read.from_yaml(example_inverter_layout)\n", + "c.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "### More Advanced Example - R2R DAC\n", + "\n", + "\n", + "An example of using `hdl21.ExternalModule`s representing an implementation technology/ PDK\n", + "in a parametric resistive DAC generator mapping to a gdsfactory implementation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "from typing import Optional\n", + "\n", + "import hdl21 as h\n", + "\n", + "PdkResistor = sky130_hdl21.ress[\"GEN_PO\"]\n", + "Nch = sky130_hdl21.primitives.NMOS_1p8V_STD\n", + "Pch = sky130_hdl21.primitives.PMOS_1p8V_STD\n", + "\n", + "\n", + "@h.paramclass\n", + "class RLadderParams:\n", + " \"\"\"# Resistor Ladder Parameters\n", + "\n", + " Note the use of the `hdl21.Instantiable` type for the unit resistor element.\n", + " This generally means \"something we can make an `Instance` of\" - most commonly a `Module`.\n", + "\n", + " Here we will be using a combination of an `ExternalModule` and its parameter-values,\n", + " in something like:\n", + "\n", + " ```python\n", + " RLadderParams(res=PdkResistor(w=4 * µ, l=10 * µ))\n", + " ```\n", + " \"\"\"\n", + "\n", + " nseg = h.Param(dtype=int, desc=\"Number of segments\")\n", + " res = h.Param(dtype=h.Instantiable, desc=\"Unit resistor, with params applied\")\n", + "\n", + "\n", + "@h.generator\n", + "def rladder(params: RLadderParams) -> h.Module:\n", + " \"\"\"# Resistor Ladder Generator\"\"\"\n", + "\n", + " @h.module\n", + " class RLadder:\n", + " # IO\n", + " top = h.Inout()\n", + " bot = h.Inout()\n", + " taps = h.Output(width=params.nseg - 1)\n", + "\n", + " # Create concatenations for the P and N sides of each resistor\n", + " nsides = h.Concat(bot, taps)\n", + " psides = h.Concat(taps, top)\n", + "\n", + " # And create our unit resistor array\n", + " runits = params.nseg * params.res(p=psides, n=nsides)\n", + "\n", + " return RLadder\n", + "\n", + "\n", + "@h.paramclass\n", + "class PassGateParams:\n", + " \"\"\"# Pass Gate Parameters\n", + "\n", + " See the commentary on `RLadderParams` above regarding the use of `hdl21.Instantiable`,\n", + " which here serves as the parameter type for each transistor. It will generally be used like:\n", + "\n", + " ```python\n", + " PassGateParams(\n", + " nmos=Nch(PdkMosParams(l=1 * n)),\n", + " pmos=Pch(PdkMosParams(l=1 * n)),\n", + " )\n", + " ```\n", + "\n", + " Both `nmos` and `pmos` parameters are `Optional`, which means they can be set to the Python built-in `None` value.\n", + " If either is `None`, its \"half\" of the pass gate will be omitted.\n", + " Setting *both* to `None` will cause a generator exception.\n", + " \"\"\"\n", + "\n", + " nmos = h.Param(dtype=Optional[h.Instantiable], desc=\"NMOS. Disabled if None.\")\n", + " pmos = h.Param(dtype=Optional[h.Instantiable], desc=\"PMOS. Disabled if None\")\n", + "\n", + "\n", + "@h.generator\n", + "def passgate(params: PassGateParams) -> h.Module:\n", + " \"\"\"# Pass Gate Generator\"\"\"\n", + " if params.nmos is None and params.pmos is None:\n", + " raise RuntimeError(\"A pass gate needs at least *one* transistor!\")\n", + "\n", + " @h.module\n", + " class PassGate:\n", + " source = h.Inout()\n", + " drain = h.Inout()\n", + "\n", + " if params.pmos is not None:\n", + " PassGate.VDD = h.Inout()\n", + " PassGate.en_b = h.Input()\n", + " PassGate.PSW = params.pmos(\n", + " d=PassGate.drain, s=PassGate.source, g=PassGate.en_b, b=PassGate.VDD\n", + " )\n", + "\n", + " if params.nmos is not None:\n", + " PassGate.VSS = h.Inout()\n", + " PassGate.en = h.Input()\n", + " PassGate.NSW = params.nmos(\n", + " d=PassGate.drain, s=PassGate.source, g=PassGate.en, b=PassGate.VSS\n", + " )\n", + "\n", + " return PassGate\n", + "\n", + "\n", + "@h.generator\n", + "def mux(params: PassGateParams) -> h.Module:\n", + " \"\"\"# Pass-Gate Analog Mux Generator\"\"\"\n", + "\n", + " @h.module\n", + " class Mux:\n", + " sourceA = h.Input()\n", + " sourceB = h.Input()\n", + " out = h.Output()\n", + " ctrl = h.Input()\n", + " ctrl_b = h.Input()\n", + "\n", + " aconns, bconns = (\n", + " dict(source=Mux.sourceA, drain=Mux.out),\n", + " dict(source=Mux.sourceB, drain=Mux.out),\n", + " )\n", + " if params.pmos is not None:\n", + " Mux.VDD = h.Inout()\n", + " aconns[\"VDD\"] = Mux.VDD\n", + " aconns[\"en_b\"] = Mux.ctrl_b\n", + " bconns[\"VDD\"] = Mux.VDD\n", + " bconns[\"en_b\"] = Mux.ctrl\n", + " if params.nmos is not None:\n", + " Mux.VSS = h.Inout()\n", + " aconns[\"VSS\"] = Mux.VSS\n", + " aconns[\"en\"] = Mux.ctrl\n", + " bconns[\"VSS\"] = Mux.VSS\n", + " bconns[\"en\"] = Mux.ctrl_b\n", + " Mux.passgate_a = passgate(params)(**aconns)\n", + " Mux.passgate_b = passgate(params)(**bconns)\n", + " return Mux\n", + "\n", + "\n", + "@h.paramclass\n", + "class MuxTreeParams:\n", + " \"\"\"# Mux Tree Parameters\"\"\"\n", + "\n", + " nbit = h.Param(dtype=int, desc=\"Number of bits\")\n", + " mux_params = h.Param(dtype=PassGateParams, desc=\"Parameters for the MUX generator\")\n", + "\n", + "\n", + "@h.generator\n", + "def mux_tree(params: MuxTreeParams) -> h.Module:\n", + " \"\"\"Binary Mux Tree Generator\"\"\"\n", + "\n", + " n_inputs = 2**params.nbit\n", + " p_ctrl = params.mux_params.nmos is not None\n", + " n_ctrl = params.mux_params.pmos is not None\n", + "\n", + " # Base module\n", + " @h.module\n", + " class MuxTree:\n", + " out = h.Output()\n", + " v_in = h.Input(width=n_inputs)\n", + " ctrl = h.Input(width=params.nbit)\n", + " ctrl_b = h.Input(width=params.nbit)\n", + "\n", + " base_mux_conns = dict()\n", + " if p_ctrl:\n", + " MuxTree.VSS = h.Inout()\n", + " base_mux_conns[\"VSS\"] = MuxTree.VSS\n", + " if n_ctrl:\n", + " MuxTree.VDD = h.Inout()\n", + " base_mux_conns[\"VDD\"] = MuxTree.VDD\n", + "\n", + " # Build the MUX tree layer by layer\n", + " curr_input = MuxTree.v_in\n", + " for layer in range(params.nbit - 1, -1, -1):\n", + " layer_mux_conns = base_mux_conns.copy()\n", + " layer_mux_conns[\"ctrl\"] = MuxTree.ctrl[layer]\n", + " layer_mux_conns[\"ctrl_b\"] = MuxTree.ctrl_b[layer]\n", + " if layer != 0:\n", + " curr_output = MuxTree.add(\n", + " name=f\"sig_{layer}\", val=h.Signal(width=2**layer)\n", + " )\n", + " else:\n", + " curr_output = MuxTree.out\n", + " for mux_idx in range(2**layer):\n", + " mux_conns = layer_mux_conns.copy()\n", + " mux_conns[\"sourceA\"] = curr_input[2 * mux_idx]\n", + " mux_conns[\"sourceB\"] = curr_input[2 * mux_idx + 1]\n", + " mux_conns[\"out\"] = curr_output[mux_idx]\n", + " MuxTree.add(\n", + " name=f\"mux_{layer}_{mux_idx}\", val=mux(params.mux_params)(**mux_conns)\n", + " )\n", + " curr_input = curr_output\n", + " return MuxTree\n", + "\n", + "\n", + "\"\"\"Main function, generating an `rladder` and `mux_tree` and netlisting each.\"\"\"\n", + "\n", + "# Create parameter values for each of our top-level generators\n", + "rparams = RLadderParams(\n", + " nseg=15,\n", + " res=PdkResistor(),\n", + ")\n", + "mparams = MuxTreeParams(\n", + " nbit=4,\n", + " mux_params=PassGateParams(\n", + " nmos=Nch(),\n", + " pmos=Pch(),\n", + " ),\n", + ")\n", + "\n", + "# Netlist in a handful of formats\n", + "duts = [rladder(rparams)]\n", + "# h.netlist(duts, sys.stdout, fmt=\"verilog\")\n", + "# h.netlist(duts, sys.stdout, fmt=\"spectre\")\n", + "# h.netlist(duts, sys.stdout, fmt=\"spice\")\n", + "# h.netlist(duts, sys.stdout, fmt=\"xyce\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "example_resistor_ladder_schematic_editor = gph.hdl21_module_to_schematic_editor(\n", + " module=rladder(rparams),\n", + " yaml_schematic_file_name=\"data/sky130nm/rladder.schem.yaml\",\n", + ")\n", + "example_resistor_ladder_schematic_editor.visualize()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "example_inverter_layout = \"data/sky130nm/example_inverter_auto.layout.yaml\"\n", + "example_inverter_schematic_editor.instantiate_layout(example_inverter_layout, default_router=\"get_bundle\", default_cross_section=\"xs_metal1\")\n", + "c = gf.read.from_yaml(example_inverter_layout)\n", + "c.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "## (WIP, future integrations) Setting up the required tools: `xschem`, `volare` and the `sky130nm` PDKs\n", + "\n", + "I will say early on, you would benefit from working in a UNIX or Debian Linux environment. Most EDA tools either proprietary or open-source only work within these operating systems or a Docker environment of these operating systems.\n", + "\n", + "There are multiple ways to get started with the environment, you could, for example:\n", + "1. Work within a [IIC-OSIC-TOOLS docker environment](https://github.com/iic-jku/IIC-OSIC-TOOLS). There is also a nice [OSIC-multitool project](https://github.com/iic-jku/osic-multitool) specifically for SKY130nm designs.\n", + "2. Install these tools natively in your operating system. You could follow one of these tutorials, for example:\n", + " * https://www.engineerwikis.com/wikis/installation-of-xschem\n", + " * https://www.youtube.com/watch?v=jXmmxO8WG8s&t=7s\n", + "\n", + "This tutorial assumes the tools have already been installed in a local operating system. We will use some design files generated by these toolsets as guided by this [OSIC-Multitool example](https://github.com/iic-jku/osic-multitool/tree/main/example/ana). Note we recommend cloning the `gplugins` repository." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "from gplugins.spice import parse_netlist as spice" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "Our example files are under the directory of `gplugins/notebooks/data`, let's extract our SPICE declaration:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "def read_file(file_path):\n", + " try:\n", + " with open(file_path, 'r') as file:\n", + " text = file.read()\n", + " return text\n", + " except FileNotFoundError:\n", + " print(\"File not found. Please provide a valid file path.\")\n", + " return None" + ] + }, + { + "cell_type": "markdown", + "id": "21", + "metadata": {}, + "source": [ + "Let's list the files we're going to be reading into:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22", + "metadata": {}, + "outputs": [], + "source": [ + "inverter_spice_file = pathlib.Path(\"data\") / \"sky130nm\" / \"inv.sch\"" + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "Let's extract our raw spice netlist. An important aspect to understand is that unfortunately, every SPICE tool developed their own file format. So in this sense, netlist parsing function is implemented according to the type of spice toolset that has generated this netlist.\n", + "\n", + "We aim to support:\n", + "\n", + "- `xschem`\n", + "- `lumerical?`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24", + "metadata": {}, + "outputs": [], + "source": [ + "inverter_spice_text = read_file(inverter_spice_file)\n", + "inverter_spice_text" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "spice.netlist_text" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "elements, _, _ = spice.parse_netlist_and_extract_elements(netlist_text=spice.netlist_text, spice_type=\"lumerical\")\n", + "elements" + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "So we can use our `netlist` parsing function to convert this to a compatible netlist for gdsfactory plugins into the extracted elements and the extracted connections:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28", + "metadata": {}, + "outputs": [], + "source": [ + "inverter_netlist_elements, inverter_netlist_connections, _ = spice.parse_netlist_and_extract_elements(netlist_text=inverter_spice_text, spice_type=\"xschem\")\n", + "inverter_netlist_elements, inverter_netlist_connections, _" + ] + }, + { + "cell_type": "markdown", + "id": "29", + "metadata": {}, + "source": [ + "### Automated schematic-driven-layout" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "We have now extracted our spice elements and our connectivity. Let's explore what we have there:" + ] + }, + { + "cell_type": "raw", + "id": "31", + "metadata": {}, + "source": [ + "# Current TODOs\n", + "\n", + "1. Update the extraction function to add xschem compatibility.\n", + "2. Create the mapping between the extracted netlist and the corresponding SKY130nm elements." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/data/sky130nm/example_inverter_auto.layout.yaml b/notebooks/data/sky130nm/example_inverter_auto.layout.yaml new file mode 100644 index 00000000..eb4ce2d0 --- /dev/null +++ b/notebooks/data/sky130nm/example_inverter_auto.layout.yaml @@ -0,0 +1,22 @@ +schema_version: 1 +schema: null +instances: + ps: + component: sky130_fd_pr__rf_pfet_01v8_mcM04W3p00L0p15 + settings: {} + ns: + component: sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p15 + settings: {} +placements: + ps: {x: null, y: null, port: null, rotation: 0, dx: null, dy: null, mirror: null} + ns: {x: null, y: null, port: null, rotation: 0, dx: null, dy: null, mirror: null} +routes: + r0: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'ps,DRAIN': 'ns,SOURCE'} + r1: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'ps,GATE': 'ns,GATE'} +ports: {} diff --git a/notebooks/data/sky130nm/example_inverter_auto.schem.yaml b/notebooks/data/sky130nm/example_inverter_auto.schem.yaml new file mode 100644 index 00000000..2b9f3dbb --- /dev/null +++ b/notebooks/data/sky130nm/example_inverter_auto.schem.yaml @@ -0,0 +1,16 @@ +schema: null +instances: + ps: + component: sky130_fd_pr__rf_pfet_01v8_mcM04W3p00L0p15 + settings: {} + ns: + component: sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p15 + settings: {} +schematic_placements: + ps: {x: null, y: null, port: null, rotation: 0, dx: null, dy: null, mirror: null} + ns: {x: null, y: null, port: null, rotation: 0, dx: null, dy: null, mirror: null} +nets: +- ['ps,DRAIN', 'ns,SOURCE'] +- ['ps,GATE', 'ns,GATE'] +ports: {} +schema_version: 1 diff --git a/notebooks/data/sky130nm/example_inverter_manual.schem.yaml b/notebooks/data/sky130nm/example_inverter_manual.schem.yaml new file mode 100644 index 00000000..a295c4d5 --- /dev/null +++ b/notebooks/data/sky130nm/example_inverter_manual.schem.yaml @@ -0,0 +1,59 @@ + +connections: + ns,d: ps,d + ns,g: ps,g + ps,d: ns,d + ps,g: ns,g +instances: + ns: + component: sky130_fd_pr__nfet_01v8 + info: {} + settings: + As: int((nf+2)/2) * w/nf * 0.29 + ad: int((nf+1)/2) * w/nf * 0.29 + l: UNIT_1 + m: UNIT_1 + mult: UNIT_1 + nf: UNIT_1 + nrd: 0.29 / w + nrs: 0.29 / w + pd: 2*int((nf+1)/2) * (w/nf + 0.29) + ports: + b: VSS + d: o + g: i + s: VSS + ps: 2*int((nf+2)/2) * (w/nf + 0.29) + sa: UNIT_0 + sb: UNIT_0 + sd: UNIT_0 + w: UNIT_1 + ps: + component: sky130_fd_pr__pfet_01v8 + info: {} + settings: + As: int((nf+2)/2) * w/nf * 0.29 + ad: int((nf+1)/2) * w/nf * 0.29 + l: UNIT_1 + m: UNIT_1 + mult: UNIT_1 + nf: UNIT_1 + nrd: 0.29 / w + nrs: 0.29 / w + pd: 2*int((nf+1)/2) * (w/nf + 0.29) + ports: + b: VDD + d: o + g: i + s: VDD + ps: 2*int((nf+2)/2) * (w/nf + 0.29) + sa: UNIT_0 + sb: UNIT_0 + sd: UNIT_0 + w: UNIT_1 +name: SkyInv +ports: + VDD: ps,s + VSS: ns,s + i: ps,g + o: ps,d diff --git a/notebooks/data/sky130nm/example_resistor_ladder.layout.yaml b/notebooks/data/sky130nm/example_resistor_ladder.layout.yaml new file mode 100644 index 00000000..55aace17 --- /dev/null +++ b/notebooks/data/sky130nm/example_resistor_ladder.layout.yaml @@ -0,0 +1,519 @@ +schema_version: 1 +schema: null +instances: + runits_0: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_1: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_2: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_3: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_4: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_5: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_6: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_7: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_8: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_9: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_10: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_11: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_12: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_13: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_14: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] +placements: + runits_0: {x: null, y: null, port: null, rotation: 0, dx: -4.426076548125775, dy: 0.2228959412725211, + mirror: null} + runits_1: {x: null, y: null, port: null, rotation: 0, dx: 3.574295629691498, dy: -0.3821073278957504, + mirror: null} + runits_2: {x: null, y: null, port: null, rotation: 0, dx: -4.72288495924887, dy: -6.032254367480482, + mirror: null} + runits_3: {x: null, y: null, port: null, rotation: 0, dx: 2.8681354173915055, dy: -5.868066502994218, + mirror: null} + runits_4: {x: null, y: null, port: null, rotation: 0, dx: -1.8664830368064012, dy: 3.994876027391382, + mirror: null} + runits_5: {x: null, y: null, port: null, rotation: 0, dx: 1.2576437297169987, dy: 2.9869038580778717, + mirror: null} + runits_6: {x: null, y: null, port: null, rotation: 0, dx: -1.7607012216037983, dy: -2.5886500103341556, + mirror: null} + runits_7: {x: null, y: null, port: null, rotation: 0, dx: 1.2576437297169987, dy: -6.361581199485151, + mirror: null} + runits_8: {x: null, y: null, port: null, rotation: 0, dx: 6.518786665699776, dy: 1.655897577460715, + mirror: null} + runits_9: {x: null, y: null, port: null, rotation: 0, dx: 0.1152840085573914, dy: -0.4401753054009496, + mirror: null} + runits_10: {x: null, y: null, port: null, rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757, + mirror: null} + runits_11: {x: null, y: null, port: null, rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757, + mirror: null} + runits_12: {x: null, y: null, port: null, rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757, + mirror: null} + runits_13: {x: null, y: null, port: null, rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757, + mirror: null} + runits_14: {x: null, y: null, port: null, rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757, + mirror: null} +routes: + r0: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_0,p': 'runits_1,p'} + r1: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_1,n': 'runits_0,p'} + r2: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_2,p': 'runits_0,p'} + r3: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_2,n': 'runits_0,p'} + r4: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_3,p': 'runits_0,p'} + r5: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_3,n': 'runits_0,p'} + r6: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_4,p': 'runits_0,p'} + r7: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_4,n': 'runits_0,p'} + r8: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_5,p': 'runits_0,p'} + r9: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_5,n': 'runits_0,p'} + r10: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_6,p': 'runits_0,p'} + r11: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_6,n': 'runits_0,p'} + r12: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_7,p': 'runits_0,p'} + r13: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_7,n': 'runits_0,p'} + r14: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_8,p': 'runits_0,p'} + r15: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_8,n': 'runits_0,p'} + r16: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_9,p': 'runits_0,p'} + r17: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_9,n': 'runits_0,p'} + r18: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_10,p': 'runits_0,p'} + r19: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_10,n': 'runits_0,p'} + r20: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_11,p': 'runits_0,p'} + r21: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_11,n': 'runits_0,p'} + r22: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_12,p': 'runits_0,p'} + r23: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_12,n': 'runits_0,p'} + r24: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_13,p': 'runits_0,p'} + r25: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_13,n': 'runits_0,p'} + r26: + routing_strategy: get_bundle + settings: {cross_section: xs_metal1, separation: 5.0} + links: {'runits_14,n': 'runits_0,p'} +ports: {} diff --git a/notebooks/data/sky130nm/example_resistor_ladder.schem.yaml b/notebooks/data/sky130nm/example_resistor_ladder.schem.yaml new file mode 100644 index 00000000..cdcfbb6f --- /dev/null +++ b/notebooks/data/sky130nm/example_resistor_ladder.schem.yaml @@ -0,0 +1,422 @@ +instances: + runits_0: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_1: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_2: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_3: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_4: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_5: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_6: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_7: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_8: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_9: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_10: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_11: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_12: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_13: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] + runits_14: + component: p_n_poly + settings: + p_poly_width: 0.35 + p_poly_length: 0.5 + poly_res_layer: [66, 13] + poly_layer: [66, 20] + psdm_layer: [94, 20] + sdm_enclosure: [0.125, 0.125] + contact_size: [0.17, 0.17] + contact_spacing: [0.17, 0.17] + licon_slots_size: [0.19, 2] + licon_slots_spacing: [0.51, 0.51] + contact_layer: [66, 44] + contact_enclosure: [0.06, 0.06] + li_layer: [67, 20] + li_enclosure: 0.08 + mcon_layer: [67, 44] + mcon_enclosure: [0.09, 0.09] + m1_layer: [68, 20] + urpm_layer: [79, 20] + urpm_min_width: 1.27 + urpm_enclosure: [0.2, 0.2] + npc_layer: [95, 20] + npc_enclosure: [0.095, 0.095] +schematic_placements: + runits_0: {rotation: 0, dx: -4.426076548125775, dy: 0.2228959412725211} + runits_1: {rotation: 0, dx: 3.574295629691498, dy: -0.3821073278957504} + runits_2: {rotation: 0, dx: -4.72288495924887, dy: -6.032254367480482} + runits_3: {rotation: 0, dx: 2.8681354173915055, dy: -5.868066502994218} + runits_4: {rotation: 0, dx: -1.8664830368064012, dy: 3.994876027391382} + runits_5: {rotation: 0, dx: 1.2576437297169987, dy: 2.9869038580778717} + runits_6: {rotation: 0, dx: -1.7607012216037983, dy: -2.5886500103341556} + runits_7: {rotation: 0, dx: 1.2576437297169987, dy: -6.361581199485151} + runits_8: {rotation: 0, dx: 6.518786665699776, dy: 1.655897577460715} + runits_9: {rotation: 0, dx: 0.1152840085573914, dy: -0.4401753054009496} + runits_10: {rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757} + runits_11: {rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757} + runits_12: {rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757} + runits_13: {rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757} + runits_14: {rotation: 0, dx: 0.817468424316049, dy: 1.079477534673757} +nets: +- ['runits_0,p', 'runits_1,p'] +- ['runits_1,n', 'runits_0,p'] +- ['runits_2,p', 'runits_0,p'] +- ['runits_2,n', 'runits_0,p'] +- ['runits_3,p', 'runits_0,p'] +- ['runits_3,n', 'runits_0,p'] +- ['runits_4,p', 'runits_0,p'] +- ['runits_4,n', 'runits_0,p'] +- ['runits_5,p', 'runits_0,p'] +- ['runits_5,n', 'runits_0,p'] +- ['runits_6,p', 'runits_0,p'] +- ['runits_6,n', 'runits_0,p'] +- ['runits_7,p', 'runits_0,p'] +- ['runits_7,n', 'runits_0,p'] +- ['runits_8,p', 'runits_0,p'] +- ['runits_8,n', 'runits_0,p'] +- ['runits_9,p', 'runits_0,p'] +- ['runits_9,n', 'runits_0,p'] +- ['runits_10,p', 'runits_0,p'] +- ['runits_10,n', 'runits_0,p'] +- ['runits_11,p', 'runits_0,p'] +- ['runits_11,n', 'runits_0,p'] +- ['runits_12,p', 'runits_0,p'] +- ['runits_12,n', 'runits_0,p'] +- ['runits_13,p', 'runits_0,p'] +- ['runits_13,n', 'runits_0,p'] +- ['runits_14,n', 'runits_0,p'] +ports: {} +schema_version: 1 diff --git a/notebooks/data/sky130nm/inv.mag b/notebooks/data/sky130nm/inv.mag new file mode 100644 index 00000000..a02e00b6 --- /dev/null +++ b/notebooks/data/sky130nm/inv.mag @@ -0,0 +1,59 @@ +magic +tech sky130A +magscale 1 2 +timestamp 1640640991 +<< nwell >> +rect 86 1006 122 1120 +rect 402 1006 438 1120 +<< pwell >> +rect 174 -918 208 -806 +<< viali >> +rect 32 1116 492 1152 +rect 118 -954 422 -916 +<< metal1 >> +rect -126 1152 650 1230 +rect -126 1116 32 1152 +rect 492 1116 650 1152 +rect -126 1090 650 1116 +rect 80 992 128 1090 +rect 196 204 206 1002 +rect 322 204 332 1002 +rect 396 992 444 1090 +rect 212 134 304 162 +rect 212 116 316 134 +rect 224 -336 316 116 +rect 300 -420 402 -404 +rect 300 -802 310 -420 +rect 392 -802 402 -420 +rect 168 -898 214 -802 +rect -126 -916 650 -898 +rect -126 -954 118 -916 +rect 422 -954 650 -916 +rect -126 -1038 650 -954 +<< via1 >> +rect 206 204 322 1002 +rect 310 -802 392 -420 +<< metal2 >> +rect 206 1002 322 1012 +rect 322 204 392 348 +rect 206 194 392 204 +rect 310 -420 392 194 +rect 310 -812 392 -802 +use sky130_fd_pr__nfet_g5v0d10v5_H9JWFY sky130_fd_pr__nfet_g5v0d10v5_H9JWFY_0 +timestamp 1639595562 +transform 1 0 270 0 1 -573 +box -278 -427 278 427 +use sky130_fd_pr__pfet_g5v0d10v5_5AEDG4 sky130_fd_pr__pfet_g5v0d10v5_5AEDG4_0 +timestamp 1639595562 +transform -1 0 262 0 1 567 +box -387 -662 387 662 +<< labels >> +rlabel metal1 -126 1152 650 1230 1 VDD +port 3 n default input +rlabel metal1 -126 -1038 650 -954 1 VSS +port 4 n +rlabel metal1 224 -336 316 134 1 in +port 1 n +rlabel metal2 310 -420 392 204 1 out +port 2 n +<< end >> diff --git a/notebooks/data/sky130nm/inv.pex.sch b/notebooks/data/sky130nm/inv.pex.sch new file mode 100644 index 00000000..cc207f35 --- /dev/null +++ b/notebooks/data/sky130nm/inv.pex.sch @@ -0,0 +1,21 @@ +v {xschem version=3.0.0 file_version=1.2 } +G {} +K {} +V {} +S {} +E {} +N 560 -1020 600 -1020 { lab=VDD} +N 560 -890 600 -890 { lab=in} +N 560 -760 600 -760 { lab=VSS} +N 840 -890 880 -890 { lab=out} +C {devices/ipin.sym} 560 -890 0 0 {name=p1 lab=in} +C {devices/opin.sym} 880 -890 0 0 {name=p3 lab=out +} +C {devices/ipin.sym} 560 -1020 0 0 {name=p5 lab=VDD +} +C {devices/ipin.sym} 560 -760 0 0 {name=p6 lab=VSS} +C {devices/noconn.sym} 840 -890 0 0 {name=l1} +C {devices/noconn.sym} 600 -1020 0 1 {name=l2} +C {devices/noconn.sym} 600 -890 0 1 {name=l3} +C {devices/noconn.sym} 600 -760 0 1 {name=l4} +C {devices/code.sym} 660 -930 0 0 {name=s1 only_toplevel=false value=".include inv.pex.spice"} diff --git a/notebooks/data/sky130nm/inv.pex.sym b/notebooks/data/sky130nm/inv.pex.sym new file mode 100644 index 00000000..a48c5037 --- /dev/null +++ b/notebooks/data/sky130nm/inv.pex.sym @@ -0,0 +1,26 @@ +v {xschem version=3.0.0 file_version=1.2 } +G {} +K {type=subcircuit +format="@name @pinlist @symname" +template="name=x1"} +V {} +S {} +E {} +L 4 -130 -30 130 -30 {} +L 4 -130 30 130 30 {} +L 4 -130 -30 -130 30 {} +L 4 130 -30 130 30 {} +L 4 -150 -20 -130 -20 {} +L 4 -150 0 -130 0 {} +L 4 130 -20 150 -20 {} +L 4 -150 20 -130 20 {} +B 5 -152.5 -22.5 -147.5 -17.5 {name=VDD dir=in } +B 5 -152.5 -2.5 -147.5 2.5 {name=in dir=in } +B 5 147.5 -22.5 152.5 -17.5 {name=out dir=out } +B 5 -152.5 17.5 -147.5 22.5 {name=VSS dir=in } +T {@symname} -72 -6 0 0 0.3 0.3 {} +T {@name} 135 -42 0 0 0.2 0.2 {} +T {VDD} -125 -24 0 0 0.2 0.2 {} +T {in} -125 -4 0 0 0.2 0.2 {} +T {out} 125 -24 0 1 0.2 0.2 {} +T {VSS} -125 16 0 0 0.2 0.2 {} diff --git a/notebooks/data/sky130nm/inv.sch b/notebooks/data/sky130nm/inv.sch new file mode 100644 index 00000000..7ff4ae84 --- /dev/null +++ b/notebooks/data/sky130nm/inv.sch @@ -0,0 +1,46 @@ +v {xschem version=3.0.0 file_version=1.2 } +G {} +K {} +V {} +S {} +E {} +N 720 -800 720 -760 { lab=VSS} +N 720 -1020 720 -980 { lab=VDD} +N 720 -950 790 -950 { lab=VDD} +N 790 -1020 790 -950 { lab=VDD} +N 720 -830 790 -830 { lab=VSS} +N 790 -830 790 -760 { lab=VSS} +N 720 -890 720 -860 { lab=out} +N 660 -950 680 -950 { lab=in} +N 660 -890 660 -830 { lab=in} +N 660 -830 680 -830 { lab=in} +N 720 -890 880 -890 { lab=out} +N 720 -1020 790 -1020 { lab=VDD} +N 720 -760 790 -760 { lab=VSS} +N 660 -950 660 -890 { lab=in} +N 720 -920 720 -890 { lab=out} +N 560 -760 720 -760 { lab=VSS} +N 560 -890 660 -890 { lab=in} +N 560 -1020 720 -1020 { lab=VDD} +C {devices/ipin.sym} 560 -890 0 0 {name=p1 lab=in} +C {devices/opin.sym} 880 -890 0 0 {name=p2 lab=out +} +C {devices/ipin.sym} 560 -1020 0 0 {name=p3 lab=VDD +} +C {devices/ipin.sym} 560 -760 0 0 {name=p4 lab=VSS} +C {sky130_fd_pr/pfet_g5v0d10v5.sym} 700 -950 0 0 {name=M10 + +L=0.5 +W=8 +nf=2 mult=1 +model=pfet_g5v0d10v5 +spiceprefix=X +} +C {sky130_fd_pr/nfet_g5v0d10v5.sym} 700 -830 0 0 {name=M9 + +L=0.5 +W=2 +nf=1 mult=1 +model=nfet_g5v0d10v5 +spiceprefix=X +} diff --git a/notebooks/data/sky130nm/inv.sym b/notebooks/data/sky130nm/inv.sym new file mode 100644 index 00000000..710c1b36 --- /dev/null +++ b/notebooks/data/sky130nm/inv.sym @@ -0,0 +1,23 @@ +v {xschem version=3.0.0 file_version=1.2} +K {type=subcircuit +format="@name @pinlist @symname" +template="name=x1" +} +T {@symname} -72 -6 0 0 0.3 0.3 {} +T {@name} 135 -42 0 0 0.2 0.2 {} +L 4 -130 -30 130 -30 {} +L 4 -130 30 130 30 {} +L 4 -130 -30 -130 30 {} +L 4 130 -30 130 30 {} +B 5 -152.5 -22.5 -147.5 -17.5 {name=VDD dir=in } +L 4 -150 -20 -130 -20 {} +T {VDD} -125 -24 0 0 0.2 0.2 {} +B 5 -152.5 -2.5 -147.5 2.5 {name=in dir=in } +L 4 -150 0 -130 0 {} +T {in} -125 -4 0 0 0.2 0.2 {} +B 5 147.5 -22.5 152.5 -17.5 {name=out dir=out } +L 4 130 -20 150 -20 {} +T {out} 125 -24 0 1 0.2 0.2 {} +B 5 -152.5 17.5 -147.5 22.5 {name=VSS dir=in } +L 4 -150 20 -130 20 {} +T {VSS} -125 16 0 0 0.2 0.2 {} diff --git a/notebooks/data/sky130nm/sky130_fd_pr__nfet_g5v0d10v5_H9JWFY.mag b/notebooks/data/sky130nm/sky130_fd_pr__nfet_g5v0d10v5_H9JWFY.mag new file mode 100644 index 00000000..817e34d4 --- /dev/null +++ b/notebooks/data/sky130nm/sky130_fd_pr__nfet_g5v0d10v5_H9JWFY.mag @@ -0,0 +1,70 @@ +magic +tech sky130A +magscale 1 2 +timestamp 1639595562 +<< pwell >> +rect -278 -427 278 427 +<< mvnmos >> +rect -50 -231 50 169 +<< mvndiff >> +rect -108 157 -50 169 +rect -108 -219 -96 157 +rect -62 -219 -50 157 +rect -108 -231 -50 -219 +rect 50 157 108 169 +rect 50 -219 62 157 +rect 96 -219 108 157 +rect 50 -231 108 -219 +<< mvndiffc >> +rect -96 -219 -62 157 +rect 62 -219 96 157 +<< mvpsubdiff >> +rect -242 333 242 391 +rect -242 -333 -184 333 +rect 184 -333 242 333 +rect -242 -345 242 -333 +rect -242 -379 -134 -345 +rect 134 -379 242 -345 +rect -242 -391 242 -379 +<< mvpsubdiffcont >> +rect -134 -379 134 -345 +<< poly >> +rect -50 241 50 257 +rect -50 207 -34 241 +rect 34 207 50 241 +rect -50 169 50 207 +rect -50 -257 50 -231 +<< polycont >> +rect -34 207 34 241 +<< locali >> +rect -50 207 -34 241 +rect 34 207 50 241 +rect -96 157 -62 173 +rect -96 -235 -62 -219 +rect 62 157 96 173 +rect 62 -235 96 -219 +rect -150 -379 -134 -345 +rect 134 -379 150 -345 +<< viali >> +rect -34 207 34 241 +rect -96 -219 -62 157 +rect 62 -219 96 157 +<< metal1 >> +rect -46 241 46 247 +rect -46 207 -34 241 +rect 34 207 46 241 +rect -46 201 46 207 +rect -102 157 -56 169 +rect -102 -219 -96 157 +rect -62 -219 -56 157 +rect -102 -231 -56 -219 +rect 56 157 102 169 +rect 56 -219 62 157 +rect 96 -219 102 157 +rect 56 -231 102 -219 +<< properties >> +string gencell sky130_fd_pr__nfet_g5v0d10v5 +string FIXED_BBOX -213 -362 213 362 +string parameters w 2 l 0.50 m 1 nf 1 diffcov 100 polycov 100 guard 1 glc 0 grc 0 gtc 0 gbc 1 tbcov 100 rlcov 100 topc 1 botc 0 poverlap 0 doverlap 1 lmin 0.50 wmin 0.42 compatible {sky130_fd_pr__nfet_01v8 sky130_fd_pr__nfet_01v8_lvt sky130_fd_bs_flash__special_sonosfet_star sky130_fd_pr__nfet_g5v0d10v5 sky130_fd_pr__nfet_05v0_nvt sky130_fd_pr__nfet_03v3_nvt} full_metal 0 viasrc 100 viadrn 100 viagate 100 viagb 0 viagr 0 viagl 0 viagt 0 +string library sky130 +<< end >> diff --git a/notebooks/data/sky130nm/sky130_fd_pr__pfet_g5v0d10v5_5AEDG4.mag b/notebooks/data/sky130nm/sky130_fd_pr__pfet_g5v0d10v5_5AEDG4.mag new file mode 100644 index 00000000..e87fb0b5 --- /dev/null +++ b/notebooks/data/sky130nm/sky130_fd_pr__pfet_g5v0d10v5_5AEDG4.mag @@ -0,0 +1,96 @@ +magic +tech sky130A +magscale 1 2 +timestamp 1639595562 +<< nwell >> +rect -387 -662 387 662 +<< mvpmos >> +rect -129 -364 -29 436 +rect 29 -364 129 436 +<< mvpdiff >> +rect -187 424 -129 436 +rect -187 -352 -175 424 +rect -141 -352 -129 424 +rect -187 -364 -129 -352 +rect -29 424 29 436 +rect -29 -352 -17 424 +rect 17 -352 29 424 +rect -29 -364 29 -352 +rect 129 424 187 436 +rect 129 -352 141 424 +rect 175 -352 187 424 +rect 129 -364 187 -352 +<< mvpdiffc >> +rect -175 -352 -141 424 +rect -17 -352 17 424 +rect 141 -352 175 424 +<< mvnsubdiff >> +rect -321 584 321 596 +rect -321 550 -213 584 +rect 213 550 321 584 +rect -321 538 321 550 +rect -321 -538 -263 538 +rect 263 -538 321 538 +rect -321 -596 321 -538 +<< mvnsubdiffcont >> +rect -213 550 213 584 +<< poly >> +rect -129 436 -29 462 +rect 29 436 129 462 +rect -129 -411 -29 -364 +rect -129 -445 -113 -411 +rect -45 -445 -29 -411 +rect -129 -461 -29 -445 +rect 29 -411 129 -364 +rect 29 -445 45 -411 +rect 113 -445 129 -411 +rect 29 -461 129 -445 +<< polycont >> +rect -113 -445 -45 -411 +rect 45 -445 113 -411 +<< locali >> +rect -229 550 -213 584 +rect 213 550 229 584 +rect -175 424 -141 440 +rect -175 -368 -141 -352 +rect -17 424 17 440 +rect -17 -368 17 -352 +rect 141 424 175 440 +rect 141 -368 175 -352 +rect -129 -445 -113 -411 +rect -45 -445 -29 -411 +rect 29 -445 45 -411 +rect 113 -445 129 -411 +<< viali >> +rect -175 -352 -141 424 +rect -17 -352 17 424 +rect 141 -352 175 424 +rect -113 -445 -45 -411 +rect 45 -445 113 -411 +<< metal1 >> +rect -181 424 -135 436 +rect -181 -352 -175 424 +rect -141 -352 -135 424 +rect -181 -364 -135 -352 +rect -23 424 23 436 +rect -23 -352 -17 424 +rect 17 -352 23 424 +rect -23 -364 23 -352 +rect 135 424 181 436 +rect 135 -352 141 424 +rect 175 -352 181 424 +rect 135 -364 181 -352 +rect -125 -411 -33 -405 +rect -125 -445 -113 -411 +rect -45 -445 -33 -411 +rect -125 -451 -33 -445 +rect 33 -411 125 -405 +rect 33 -445 45 -411 +rect 113 -445 125 -411 +rect 33 -451 125 -445 +<< properties >> +string gencell sky130_fd_pr__pfet_g5v0d10v5 +string FIXED_BBOX -292 -567 292 567 +string parameters w 4 l 0.50 m 1 nf 2 diffcov 100 polycov 100 guard 1 glc 0 grc 0 gtc 1 gbc 0 tbcov 100 rlcov 100 topc 0 botc 1 poverlap 0 doverlap 1 lmin 0.50 wmin 0.42 compatible {sky130_fd_pr__pfet_01v8 sky130_fd_pr__pfet_01v8_lvt sky130_fd_pr__pfet_01v8_hvt sky130_fd_pr__pfet_g5v0d10v5} full_metal 0 viasrc 100 viadrn 100 viagate 100 viagb 0 viagr 0 viagl 0 viagt 0 +string library sky130 +<< end >> diff --git a/notebooks/data/sky130nm/tb_inv.sch b/notebooks/data/sky130nm/tb_inv.sch new file mode 100644 index 00000000..f79138c4 --- /dev/null +++ b/notebooks/data/sky130nm/tb_inv.sch @@ -0,0 +1,78 @@ +v {xschem version=3.0.0 file_version=1.2 } +G {} +K {} +V {} +S {} +E {} +T {(c) 2021 Harald Pretl, JKU, IIC + +Inverter Testbench + +Here a simple inverter (cell "inv") is instantiated as a symbol, and this +can be simulated.} 140 -690 0 0 0.4 0.4 {} +N 240 -100 240 -40 { lab=GND} +N 240 -40 360 -40 { lab=GND} +N 360 -100 360 -40 { lab=GND} +N 360 -200 360 -160 { lab=in} +N 240 -380 240 -160 { lab=vdd_hi} +N 360 -40 600 -40 { lab=GND} +N 360 -200 620 -200 { lab=in} +N 600 -180 620 -180 { lab=GND} +N 600 -180 600 -40 { lab=GND} +N 600 -220 620 -220 { lab=vdd_hi} +N 600 -380 600 -220 { lab=vdd_hi} +N 240 -380 600 -380 { lab=vdd_hi} +N 240 -40 240 -20 { lab=GND} +N 600 -40 1020 -40 { lab=GND} +N 1020 -100 1020 -40 { lab=GND} +N 1020 -220 1020 -160 { lab=out} +N 920 -220 1020 -220 { lab=out} +C {devices/code.sym} -230 -190 0 0 {name=TT_MODELS +only_toplevel=true +format="tcleval( @value )" +value="** manual skywater pdks install (with patches applied) +* .lib \\\\$::SKYWATER_MODELS\\\\/models/sky130.lib.spice tt + +** opencircuitdesign pdks install +.lib \\\\$::SKYWATER_MODELS\\\\/sky130.lib.spice.tt.red tt + +.param mc_mm_switch=0 +.param mc_pr_switch=0 +" +spice_ignore=false} +C {devices/launcher.sym} -150 -30 0 0 {name=h2 +descr="Simulate" +tclcommand="xschem netlist; xschem simulate"} +C {devices/vsource.sym} 240 -130 0 0 {name=V2 value=5 +} +C {devices/lab_wire.sym} 310 -380 0 0 {name=l2 lab=vdd_hi} +C {devices/code_shown.sym} -250 -470 0 0 {name=NGSPICE +only_toplevel=true +value=" +.control +set noaskquit +set filetype=ascii +save all + +op +tran 0.1n 1u + +write tb_inv.raw +exit + +.endc +"} +C {devices/lab_wire.sym} 400 -200 0 0 {name=l3 lab=in} +C {devices/vsource.sym} 360 -130 0 0 {name=V5 +value1="dc 5 " +value="dc 5 pulse 5 0 0 1n 1n 0.05u 0.1u"} +C {inv.sym} 770 -200 0 0 {name=x1} +C {devices/gnd.sym} 240 -20 0 0 {name=l1 lab=GND} +C {devices/capa.sym} 1020 -130 0 0 {name=C1 +m=1 +value=10f + +footprint=1206 +device="ceramic capacitor"} +C {devices/lab_wire.sym} 990 -220 0 0 {name=l4 lab=out +} diff --git a/notebooks/data/sky130nm/tb_inv_pex.sch b/notebooks/data/sky130nm/tb_inv_pex.sch new file mode 100644 index 00000000..d1b9c769 --- /dev/null +++ b/notebooks/data/sky130nm/tb_inv_pex.sch @@ -0,0 +1,78 @@ +v {xschem version=3.0.0 file_version=1.2 } +G {} +K {} +V {} +S {} +E {} +T {(c) 2021 Harald Pretl, JKU, IIC + +Inverter Testbench + +Here a simple inverter (cell "inv") is instantiated as a symbol, and this +can be simulated.} 140 -690 0 0 0.4 0.4 {} +N 240 -100 240 -40 { lab=GND} +N 240 -40 360 -40 { lab=GND} +N 360 -100 360 -40 { lab=GND} +N 360 -200 360 -160 { lab=in} +N 240 -380 240 -160 { lab=vdd_hi} +N 360 -40 600 -40 { lab=GND} +N 360 -200 620 -200 { lab=in} +N 600 -180 620 -180 { lab=GND} +N 600 -180 600 -40 { lab=GND} +N 600 -220 620 -220 { lab=vdd_hi} +N 600 -380 600 -220 { lab=vdd_hi} +N 240 -380 600 -380 { lab=vdd_hi} +N 240 -40 240 -20 { lab=GND} +N 600 -40 1020 -40 { lab=GND} +N 1020 -100 1020 -40 { lab=GND} +N 1020 -220 1020 -160 { lab=out} +N 920 -220 1020 -220 { lab=out} +C {devices/code.sym} -230 -190 0 0 {name=TT_MODELS +only_toplevel=true +format="tcleval( @value )" +value="** manual skywater pdks install (with patches applied) +* .lib \\\\$::SKYWATER_MODELS\\\\/models/sky130.lib.spice tt + +** opencircuitdesign pdks install +.lib \\\\$::SKYWATER_MODELS\\\\/sky130.lib.spice.tt.red tt + +.param mc_mm_switch=0 +.param mc_pr_switch=0 +" +spice_ignore=false} +C {devices/launcher.sym} -150 -30 0 0 {name=h2 +descr="Simulate" +tclcommand="xschem netlist; xschem simulate"} +C {devices/vsource.sym} 240 -130 0 0 {name=V2 value=5 +} +C {devices/lab_wire.sym} 310 -380 0 0 {name=l2 lab=vdd_hi} +C {devices/code_shown.sym} -250 -470 0 0 {name=NGSPICE +only_toplevel=true +value=" +.control +set noaskquit +set filetype=ascii +save all + +op +tran 0.1n 1u + +write tb_inv.raw +exit + +.endc +"} +C {devices/lab_wire.sym} 400 -200 0 0 {name=l3 lab=in} +C {devices/vsource.sym} 360 -130 0 0 {name=V5 +value1="dc 5 " +value="dc 5 pulse 5 0 0 1n 1n 0.05u 0.1u"} +C {inv.pex.sym} 770 -200 0 0 {name=x1} +C {devices/gnd.sym} 240 -20 0 0 {name=l1 lab=GND} +C {devices/capa.sym} 1020 -130 0 0 {name=C1 +m=1 +value=10f + +footprint=1206 +device="ceramic capacitor"} +C {devices/lab_wire.sym} 990 -220 0 0 {name=l4 lab=out +} diff --git a/notebooks/data/sky130nm/tb_most.sch b/notebooks/data/sky130nm/tb_most.sch new file mode 100644 index 00000000..d2ae00a6 --- /dev/null +++ b/notebooks/data/sky130nm/tb_most.sch @@ -0,0 +1,106 @@ +v {xschem version=3.0.0 file_version=1.2 } +G {} +K {} +V {} +S {} +E {} +T {(c) 2021 Harald Pretl, JKU, IIC + +MOSFET Testbench + +Use this to explore the dc and ac behavior of the various MOSFET devices. + +CTRL-click on "Simulate" to create netlist and start the simulation.} 100 -720 0 0 0.4 0.4 {} +N 240 -100 240 -40 { lab=GND} +N 240 -40 560 -40 { lab=GND} +N 120 -100 120 -40 { lab=GND} +N 120 -40 240 -40 { lab=GND} +N 710 -40 900 -40 { lab=GND} +N 560 -200 630 -200 { lab=GND} +N 560 -170 560 -40 { lab=GND} +N 240 -200 240 -160 { lab=vgs} +N 240 -200 520 -200 { lab=vgs} +N 120 -300 120 -160 { lab=vds} +N 120 -300 560 -300 { lab=vds} +N 560 -420 560 -300 { lab=vds} +N 900 -420 900 -380 { lab=vds} +N 560 -40 630 -40 { lab=GND} +N 560 -420 820 -420 { lab=vds} +N 760 -420 760 -380 { lab=vds} +N 630 -40 710 -40 { lab=GND} +N 630 -200 640 -200 { lab=GND} +N 640 -200 640 -40 { lab=GND} +N 760 -320 760 -280 { lab=#net1} +N 760 -280 820 -280 { lab=#net1} +N 820 -350 820 -280 { lab=#net1} +N 820 -350 860 -350 { lab=#net1} +N 820 -420 900 -420 { lab=vds} +N 700 -330 720 -330 { lab=GND} +N 700 -330 700 -40 { lab=GND} +N 400 -370 400 -200 { lab=vgs} +N 400 -370 720 -370 { lab=vgs} +N 900 -350 1000 -350 { lab=vds} +N 1000 -420 1000 -350 { lab=vds} +N 900 -420 1000 -420 { lab=vds} +N 560 -300 560 -290 { lab=vds} +N 900 -260 900 -40 { lab=GND} +C {devices/code.sym} -230 -190 0 0 {name=TT_MODELS +only_toplevel=true +format="tcleval( @value )" +value="** manual skywater pdks install (with patches applied) +* .lib \\\\$::SKYWATER_MODELS\\\\/models/sky130.lib.spice tt + +** opencircuitdesign pdks install +.lib \\\\$::SKYWATER_MODELS\\\\/sky130.lib.spice.tt.red tt + +.param mc_mm_switch=0 +.param mc_pr_switch=0 +" +spice_ignore=false} +C {devices/launcher.sym} -150 -30 0 0 {name=h2 +descr="Simulate" +tclcommand="xschem netlist; xschem simulate"} +C {devices/vsource.sym} 240 -130 0 0 {name=Vg value=5 +} +C {devices/code_shown.sym} -240 -590 0 0 {name=NGSPICE only_toplevel=true value=" +.control + +set noaskquit +set filetype=ascii +save all + +op +dc Vd 0 5 0.01 Vg 0 5 1 + +write tb_most.raw + +plot i(Vnid) +plot i(Vpid) + +* exit + +.endc +"} +C {devices/vsource.sym} 120 -130 0 0 {name=Vd + value=5 +} +C {sky130_fd_pr/nfet_g5v0d10v5.sym} 540 -200 0 0 {name=M1 +L=0.5 +W=5 +nf=1 mult=1 +model=nfet_g5v0d10v5 +spiceprefix=X +} +C {sky130_fd_pr/pfet_g5v0d10v5.sym} 880 -350 0 0 {name=M9 +L=0.5 +W=5 +nf=1 mult=1 +model=pfet_g5v0d10v5 +spiceprefix=X +} +C {devices/lab_wire.sym} 470 -200 0 0 {name=l2 lab=vgs} +C {devices/lab_wire.sym} 470 -300 0 0 {name=l3 lab=vds} +C {devices/vcvs.sym} 760 -350 0 0 {name=E1 value=1} +C {devices/gnd.sym} 160 -40 0 0 {name=l4 lab=GND} +C {devices/ammeter.sym} 900 -290 0 0 {name=Vpid} +C {devices/ammeter.sym} 560 -260 0 0 {name=Vnid} diff --git a/pyproject.toml b/pyproject.toml index 4410b861..30273f12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,6 +82,12 @@ gmsh = [ "shapely", "meshwell>=1.0.7,<=1.1" ] +hdl21 = [ + "hdl21>=6.0.0,<7.0.0", + "vlsir>=6.0.0", + "sky130-hdl21>=6.0.0", + "sky130 @ git+https://github.com/gdsfactory/skywater130.git@main" +] klayout = [ "klayout", "pyvis<=0.3.1" @@ -116,8 +122,8 @@ vlsir = [ ] [tool.codespell] -ignore-words-list = 'te, te/tm, te, ba, fpr, fpr_spacing, ro, nd, donot, schem, Ue' -skip = 'notebooks/palace_02_fullwave.ipynb' +ignore-words-list = 'te, te/tm, te, ba, fpr, fpr_spacing, ro, nd, donot, schem, Ue, Inout' +skip = 'notebooks/palace_02_fullwave.ipynb, notebooks/22_sky130nm_inverter_schematic_to_layout.ipynb' [tool.mypy] python_version = "3.10"