From 97244cc0b84c6d3535e6234680dae0c96ca0f655 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 02:21:28 +0530 Subject: [PATCH 01/57] feat: added prepex spice generation code --- .../glayout/pdk/gf180_mapped/gf180_mapped.py | 5 + .../gdsfactory-gen/glayout/pdk/mappedpdk.py | 24 +- .../pdk/sky130_mapped/sky130_mapped.py | 7 +- .../gdsfactory-gen/glayout/spice/netlist.py | 223 ++++++++++++++++++ 4 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py diff --git a/openfasoc/generators/gdsfactory-gen/glayout/pdk/gf180_mapped/gf180_mapped.py b/openfasoc/generators/gdsfactory-gen/glayout/pdk/gf180_mapped/gf180_mapped.py index e4cab6e41..406fb619a 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/pdk/gf180_mapped/gf180_mapped.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/pdk/gf180_mapped/gf180_mapped.py @@ -41,6 +41,11 @@ gf180_mapped_pdk = MappedPDK( name="gf180", glayers=gf180_glayer_mapping, + models={ + 'nfet': 'nfet_03v3', + 'pfet': 'pfet_03v3', + 'mimcap': 'mimcap_1p0fF' + }, layers=LAYER, klayout_lydrc_file=gf180_lydrc_file_path, grules=grulesobj, diff --git a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py index 62729d531..6cd47ea4f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py @@ -5,7 +5,7 @@ from gdsfactory.pdk import Pdk from gdsfactory.typings import Component, PathType, Layer from pydantic import validator, StrictStr, ValidationError -from typing import ClassVar, Optional, Any, Union, Literal, Iterable +from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict from pathlib import Path from decimal import Decimal, ROUND_UP import tempfile @@ -14,6 +14,11 @@ from pydantic import validate_arguments import xml.etree.ElementTree as ET +class SpiceModels(TypedDict): + nfet: str + pfet: str + mimcap: str + class MappedPDK(Pdk): """Inherits everything from the pdk class but also requires mapping to glayers glayers are generic layers which can be returned with get_glayer(name: str) @@ -42,11 +47,24 @@ class MappedPDK(Pdk): "capmet", ) + models: SpiceModels = { + "nfet": "", + "pfet": "", + "mimcap": "" + } + glayers: dict[StrictStr, Union[StrictStr, tuple[int,int]]] # friendly way to implement a graph grules: dict[StrictStr, dict[StrictStr, Optional[dict[StrictStr, Any]]]] klayout_lydrc_file: Optional[Path] = None + @validator("models") + def models_check(cls, models_obj: dict[StrictStr, StrictStr]): + for model in models_obj.key(): + if not model in ["nmos","pmos","mimcap"]: + raise ValueError("specify nmos, pmos, or mimcap models only") + return models_obj + @validator("glayers") def glayers_check_keys(cls, glayers_obj: dict[StrictStr, Union[StrictStr, tuple[int,int]]]): """force people to pick glayers from a finite set of string layers that you define @@ -127,7 +145,7 @@ def drc( # there is a drc parsing open-source at: # https://github.com/google/globalfoundries-pdk-libs-gf180mcu_fd_pr/blob/main/rules/klayout/drc # eventually I can return more info on the drc run, but for now just void and view the lyrdb in klayout - + # Open DRC output XML file drc_tree = ET.parse(report_path.resolve()) drc_root = drc_tree.getroot() @@ -286,7 +304,7 @@ def util_max_metal_seperation(self, metal_levels: Union[list[int],list[str], str for met in metal_levels: sep_rules.append(self.get_grule(met)["min_separation"]) return self.snap_to_2xgrid(max(sep_rules)) - + @validate_arguments def snap_to_2xgrid(self, dims: Union[list[Union[float,Decimal]], Union[float,Decimal]], return_type: Literal["decimal","float","same"]="float", snap4: bool=False) -> Union[list[Union[float,Decimal]], Union[float,Decimal]]: """snap all numbers in dims to double the grid size. diff --git a/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py b/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py index 1e982d3fd..06e5f995a 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py @@ -38,6 +38,11 @@ sky130_mapped_pdk = MappedPDK( name="sky130", glayers=sky130_glayer_mapping, + models={ + 'nfet': 'sky130_fd_pr__nfet_01v8__model', + 'pfet': 'sky130_fd_pr__pfet_01v8__model', + 'mimcap': 'sky130_fd_pr__cap_mim_m3_1' + }, grules=grulesobj, klayout_lydrc_file=sky130_lydrc_file_path, default_decorator=sky130_add_npc @@ -45,4 +50,4 @@ # set the grid size sky130_mapped_pdk.gds_write_settings.precision = 5*10**-9 sky130_mapped_pdk.cell_decorator_settings.cache=False -sky130_mapped_pdk.gds_write_settings.flatten_invalid_refs=False +sky130_mapped_pdk.gds_write_settings.flatten_invalid_refs=False \ No newline at end of file diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py new file mode 100644 index 000000000..6380bbb74 --- /dev/null +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -0,0 +1,223 @@ +from os.path import join, dirname +from typing import Union + +import re + +class Netlist: + """Represents a SPICE netlist/subcircuit.""" + + circuit_name: str = "" + """Name of the subcircuit.""" + nodes: list[str] = [] + """List of nodes in the subcircuit.""" + global_nodes: list[str] = [] + """List of the global nodes in the subcircuit.""" + + designs_dir: str = join(dirname(__file__), 'designs') + """Path to the src/designs/ directory.""" + + source_netlist: str = "" + """The source SPICE subcircuit (template) for the subcircuit. [Mako](https://makotemplates.org) templating syntax is supported.""" + spice_netlist: str = "" + """The generated SPICE netlist.""" + + sub_netlists: list['Netlist'] + """List of the sub-netlists.""" + netlist_connections: list[list[str]] + """2D matrix of interconnections of the sub-netlists. + + The row and column number in the matrix represent the indices of the connected sub-netlists. The value represents the name of the wire connecting the nodes. + """ + + # Variable to determine how many wires were created + wire_index: int = 0 + """The index of the next interconnection wire. + + The wires for interconnecting sub-netlists are named `wire{wire_index}`. This index is incremented each time a sub-netlist connection is made. + """ + + parameters: dict = {} + """Dictionary of the high-level parameters.""" + + def __init__(self, circuit_name: str, parameters: dict, sub_netlists: list['Netlist']): + """Initializes a Netlist object. + + Override to load sub-netlists and parameters on initialization. + """ + self.parameters = {**self.parameters, **parameters} + self.circuit_name = circuit_name + + self.sub_netlists = [] + self.netlist_connections = [] + + self.add_netlists(sub_netlists) + + def extract_subckt_name(self, netlist: str): + """Extracts the subcircuit name from the source SPICE.""" + for line in netlist.split('\n'): + if line.count('subckt') != 0: + return line.split(' ')[1] + + def generate_instance(self, name: str, nodes: list[str]) -> str: + """Generates an instance of the netlist subcircuit. + Override to insert parameters in the instance. + """ + return f"X{name} {' '.join(nodes)} {self.circuit_name}" + + def read_source_netlist(self, netlist_src: str) -> str: + """Reads a source SPICE subcircuit template from a SPICE file. [Mako](https://makotemplates.org) templating syntax is supported in the source SPICE netlist.""" + self.source_netlist = open(join(self.designs_dir, netlist_src)).read() + return self.source_netlist + + def connect_subnets( + self, + net1: Union[int, 'Netlist'], + net2: Union[int, 'Netlist'], + node_mapping: list[tuple[str, str]] + ): + """Adds a connection between two sub-netlists. + + Parameters: + - `net1`: The netlist to connect. Either a reference to the Netlist object or it's index in the `sub_netlists` list. + - `net2`: The netlist to connect to. Either a reference to the Netlist object or it's index in the `sub_netlists` list. + - `node_mapping`: A list of 2-element tuples representing the connections between nodes of the netlists. The first element in the tuple is the name of the node of `net1` and the second value is the name of the node in `net2` to connect to. + """ + for mapping in node_mapping: + node1, node2 = mapping + + net1_index = net1 if type(net1) == int else self.sub_netlists.index(net1) + net2_index = net2 if type(net2) == int else self.sub_netlists.index(net2) + + netlist1 = self.sub_netlists[net1_index] + netlist2 = self.sub_netlists[net2_index] + + node1_index = netlist1.nodes.index(node1) + node2_index = netlist2.nodes.index(node2) + + connection_wire = "" + # if one of the nodes is already connected, then use that wire instead of creating a new wire + if re.match("^wire[\d]+$", self.netlist_connections[net1_index][node1_index]): + connection_wire = self.netlist_connections[net1_index][node1_index] + + elif re.match("^wire[\d]+$", self.netlist_connections[net2_index][node2_index]): + connection_wire = self.netlist_connections[net2_index][node2_index] + + else: + connection_wire = f"wire{self.wire_index}" + self.wire_index += 1 + + self.netlist_connections[net1_index][node1_index] = connection_wire + self.netlist_connections[net2_index][node2_index] = connection_wire + + + def connect_node( + self, + net: Union[int, 'Netlist'], + node_mapping: list[tuple[str, str]] + ): + """Connects a sub-netlist to a top-level node. + + Parameters: + - `net`: The sub-netlist to connect. Either a reference to the Netlist object or it's index in the `sub_netlists` list. + - `node_mapping`: A list of 2-element tuples representing the connections between the netlist nodes and the top-level nodes. The first element in the tuple is the name of the node of `net` and the second value is the name of the top-level to connect to. + """ + net_index = net if type(net) == int else self.sub_netlists.index(net) + + for mapping in node_mapping: + net_node, top_level_node = mapping + + net = self.sub_netlists[net_index] + node_index = net.nodes.index(net_node) + + self.netlist_connections[net_index][node_index] = top_level_node + + def add_netlists(self, netlists: list['Netlist']): + """Adds sub-netlists. + + Parameters: + - `netlists`: A list of Netlist objects to add. + """ + for netlist in netlists: + self.sub_netlists.append(netlist) + self.netlist_connections.append(netlist.nodes.copy()) + + def connect_netlist(self, netlist: 'Netlist', node_mapping: list[tuple[str, str]]): + """Adds a sub-netlist and connects it to top-level nodes. + + Parameters: + - `netlist`: The netlist object to add. + - `node_mapping`: A list of 2-element tuples representing the connections between the netlist nodes and the top-level nodes. The first element in the tuple is the name of the node of `netlist` and the second value is the name of the top-level to connect to. + """ + self.add_netlists([netlist]) + netlist_index = len(self.sub_netlists) - 1 + + self.connect_node(net=netlist_index, node_mapping=node_mapping) + + return netlist_index + + def generate_source_netlist_params(self) -> dict: + """Generates the [Mako](https://makotemplates.org) parameters to be inserted in the source SPICE netlist.""" + return self.parameters + + def __generate_self_subcircuit(self) -> str: + """Generates the top-level SPICE subcircuit directive. + The name of the subcircuit is set by `self.circuit_name`. + """ + if self.source_netlist != "": + text = self.source_netlist + + elif len(self.sub_netlists) > 0: + main_circuit = f".subckt {self.circuit_name} {' '.join(self.nodes)}\n" + + for i, netlist in enumerate(self.sub_netlists): + main_circuit += netlist.generate_instance(i, self.netlist_connections[i]) + "\n" + + main_circuit += f".ends {self.circuit_name}" + + return main_circuit + + else: + return "" + + def get_subcircuits_list(self, sub_netlists_only = False) -> set[str]: + """Generates a list of all the unique SPICE subcircuits directives used in the netlist.""" + subcircuits = set() + + for netlist in self.sub_netlists: + subcircuits.update(netlist.get_subcircuits_list()) + + if not sub_netlists_only: subcircuits.add(self.__generate_self_subcircuit()) + + return subcircuits + + def get_global_nodes_list(self) -> set[str]: + """Generates a list of unique global nodes used in the netlist.""" + global_nodes = set() + + for netlist in self.sub_netlists: + global_nodes.update(netlist.global_nodes) + + global_nodes.update(set(self.global_nodes)) + + return global_nodes + + def generate_netlist(self, only_subcircuits: bool = False): + """Generates the final SPICE netlist for the design. + + The final netlist is a set of SPICE subcircuit directives and global directives. The top-level subcircuit is set by `self.circuit_name`. + + Parameters: + - `only_subcircuits`: Only generates the subcircuit directives if set to `True`. (Default: `False`) + """ + subcircuits = '\n'.join(self.get_subcircuits_list(sub_netlists_only=True)) + main_circuit = self.__generate_self_subcircuit() + global_nodes = ' '.join(self.get_global_nodes_list()) + + self.spice_netlist = "" + + if len(global_nodes) > 0 and not only_subcircuits: self.spice_netlist += f".global {global_nodes}\n" + + self.spice_netlist += subcircuits + "\n" + self.spice_netlist += main_circuit + + return self.spice_netlist From b7a8dcf7ca66246bc69e42d3e7f492ae5b1bb684 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 02:21:41 +0530 Subject: [PATCH 02/57] feat: added prepex spice generation in mimcap --- .../glayout/primitives/mimcap.py | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 2bf381c1b..864604b54 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -9,7 +9,7 @@ from pydantic import validate_arguments from glayout.routing.straight_route import straight_route from decimal import ROUND_UP, Decimal - +from glayout.spice.netlist import Netlist @validate_arguments def __get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: @@ -22,6 +22,17 @@ def __get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: pdk.activate() return capmettop, capmetbottom +class __mimcap_netlist(Netlist): + nodes = ['V1', 'V2'] + + def __init__(self, pdk: MappedPDK, size: tuple[float, float] = (5, 5)): + super().__init__(pdk, 'MIMCap', {}, []) + + self.source_netlist = f""" +.subckt MIMCAP V1 V2 +C1 V1 V2 ${pdk.models['mimcap']} l={size[0]} w={size[1]} +.ends MIMCAP + """ @cell def mimcap( @@ -37,7 +48,7 @@ def mimcap( bottom_met_...all edges, this is the metal below capmet """ size = pdk.snap_to_2xgrid(size) - # error checking and + # error checking and capmettop, capmetbottom = __get_mimcap_layerconstruction_info(pdk) # create top component mim_cap = Component() @@ -50,8 +61,13 @@ def mimcap( # flatten and create ports mim_cap = add_ports_perimeter(mim_cap, layer=pdk.get_glayer(capmetbottom), prefix="bottom_met_") mim_cap.add_ports(top_met_ref.get_ports_list()) - return rename_ports_by_orientation(mim_cap).flatten() + component = rename_ports_by_orientation(mim_cap).flatten() + + # netlist generation + component.info['netlist'] = __mimcap_netlist(pdk, size) + + return component @cell def mimcap_array(pdk: MappedPDK, rows: int, columns: int, size: tuple[float,float] = (5.0,5.0), rmult: Optional[int]=1) -> Component: From 6723c9761e92d129da0756c446d2bbf36f89bc35 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:24:21 +0530 Subject: [PATCH 03/57] feat: directly instantiated Netlist for mimcap --- .../glayout/primitives/mimcap.py | 22 ++++++++----------- .../gdsfactory-gen/glayout/spice/netlist.py | 4 +++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 864604b54..6abc4b26f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -22,18 +22,6 @@ def __get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: pdk.activate() return capmettop, capmetbottom -class __mimcap_netlist(Netlist): - nodes = ['V1', 'V2'] - - def __init__(self, pdk: MappedPDK, size: tuple[float, float] = (5, 5)): - super().__init__(pdk, 'MIMCap', {}, []) - - self.source_netlist = f""" -.subckt MIMCAP V1 V2 -C1 V1 V2 ${pdk.models['mimcap']} l={size[0]} w={size[1]} -.ends MIMCAP - """ - @cell def mimcap( pdk: MappedPDK, size: tuple[float,float]=(5.0, 5.0) @@ -65,7 +53,15 @@ def mimcap( component = rename_ports_by_orientation(mim_cap).flatten() # netlist generation - component.info['netlist'] = __mimcap_netlist(pdk, size) + component.info['netlist'] = Netlist( + 'MIMCap', + source_netlist = f""" +.subckt MIMCAP V1 V2 +C1 V1 V2 ${pdk.models['mimcap']} l={size[0]} w={size[1]} +.ends MIMCAP + """, + nodes = ['V1', 'V2'] + ) return component diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 6380bbb74..9bc23e74f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -39,7 +39,7 @@ class Netlist: parameters: dict = {} """Dictionary of the high-level parameters.""" - def __init__(self, circuit_name: str, parameters: dict, sub_netlists: list['Netlist']): + def __init__(self, circuit_name: str, source_netlist: str = '', nodes: list[str] = [], parameters: dict = {}, sub_netlists: list['Netlist'] = []): """Initializes a Netlist object. Override to load sub-netlists and parameters on initialization. @@ -49,6 +49,8 @@ def __init__(self, circuit_name: str, parameters: dict, sub_netlists: list['Netl self.sub_netlists = [] self.netlist_connections = [] + self.source_netlist = source_netlist + self.nodes = nodes self.add_netlists(sub_netlists) From af485da8a161362d5702d666a71697a02f67a5ec Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:37:12 +0530 Subject: [PATCH 04/57] refactor: added default argument for circuit_name --- .../gdsfactory-gen/glayout/primitives/mimcap.py | 3 +-- .../gdsfactory-gen/glayout/spice/netlist.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 6abc4b26f..9c95d2769 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -54,8 +54,7 @@ def mimcap( # netlist generation component.info['netlist'] = Netlist( - 'MIMCap', - source_netlist = f""" + source_netlist=f""" .subckt MIMCAP V1 V2 C1 V1 V2 ${pdk.models['mimcap']} l={size[0]} w={size[1]} .ends MIMCAP diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 9bc23e74f..771384f45 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -39,27 +39,33 @@ class Netlist: parameters: dict = {} """Dictionary of the high-level parameters.""" - def __init__(self, circuit_name: str, source_netlist: str = '', nodes: list[str] = [], parameters: dict = {}, sub_netlists: list['Netlist'] = []): + def __init__(self, source_netlist: str = '', nodes: list[str] = [], circuit_name: Union[str, None] = None, parameters: dict = {}, sub_netlists: list['Netlist'] = []): """Initializes a Netlist object. Override to load sub-netlists and parameters on initialization. """ self.parameters = {**self.parameters, **parameters} - self.circuit_name = circuit_name self.sub_netlists = [] self.netlist_connections = [] self.source_netlist = source_netlist self.nodes = nodes + if circuit_name != None: + self.circuit_name = circuit_name + else: + self.circuit_name = self.extract_subckt_name(self.source_netlist) + self.add_netlists(sub_netlists) - def extract_subckt_name(self, netlist: str): + def extract_subckt_name(self, netlist: str) -> str: """Extracts the subcircuit name from the source SPICE.""" for line in netlist.split('\n'): if line.count('subckt') != 0: return line.split(' ')[1] + return 'Netlist' + def generate_instance(self, name: str, nodes: list[str]) -> str: """Generates an instance of the netlist subcircuit. Override to insert parameters in the instance. From 397d0e1d1f30c811f463e103cc1ccd4df4dce1db Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:37:37 +0530 Subject: [PATCH 05/57] feat: added fet netlist --- .../gdsfactory-gen/glayout/primitives/fet.py | 62 ++++++++++++++++--- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index 4d0b37545..f12ea1444 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -14,6 +14,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from decimal import Decimal from glayout.routing.straight_route import straight_route +from glayout.spice.netlist import Netlist @validate_arguments @@ -99,8 +100,8 @@ def multiplier( sd_route_extension = float, how far extra to extend the source/drain connections (default=0) gate_route_extension = float, how far extra to extend the gate connection (default=0) dummy_routes: bool default=True, if true add add vias and short dummy poly,source,drain - - ports (one port for each edge), + + ports (one port for each edge), ****NOTE: source is below drain: gate_... all edges (top met route of gate connection) source_...all edges (top met route of source connections) @@ -134,7 +135,7 @@ def multiplier( width = min_width if (width or min_width) <= min_width else width width = pdk.snap_to_2xgrid(width) poly_height = width + 2 * pdk.get_grule("poly", "active_diff")["overhang"] - # call finger array + # call finger array multiplier = __gen_fingers_macro(pdk, interfinger_rmult, fingers, length, width, poly_height, sdlayer, inter_finger_topmet) # route all drains/ gates/ sources if routing: @@ -212,13 +213,13 @@ def __mult_array_macro( width: Optional[float] = 3, fingers: Optional[int] = 1, multipliers: Optional[int] = 1, - routing: Optional[bool] = True, + routing: Optional[bool] = True, # dummy: Optional[Union[bool, tuple[bool, bool]]] = True, length: Optional[float] = None, - sd_route_topmet: Optional[str] = "met2", - gate_route_topmet: Optional[str] = "met2", - sd_route_left: Optional[bool] = True, - sd_rmult: int = 1, + sd_route_topmet: Optional[str] = "met2", # + gate_route_topmet: Optional[str] = "met2", # + sd_route_left: Optional[bool] = True, # + sd_rmult: int = 1, # gate_rmult: int=1, interfinger_rmult: int=1, dummy_routes: bool=True @@ -422,7 +423,28 @@ def nmos( ) tapring_ref = nfet << ringtoadd nfet.add_ports(tapring_ref.get_ports_list(),prefix="guardring_") - return rename_ports_by_orientation(nfet).flatten() + + component = rename_ports_by_orientation(nfet).flatten() + + # add spice netlist + dummy_tuple = (True, True) + if with_dummy == False: + dummy_tuple = (False, False) + else: + dummy_tuple = with_dummy + + component.info['netlist'] = Netlist( + source_netlist=f""" +.subckt NMOS D G S B +{f"M1 B B B B {pdk.models['nfet']} l={length} w={width} m={fingers}" if dummy_tuple[0] else ""} +M2 D G S B {pdk.models['nfet']} l={length} w={width} m={fingers * multiplier} +{f"M3 B B B B {pdk.models['nfet']} l={length} w={width} m={fingers}" if dummy_tuple[1] else ""} +.ends NMOS + """, + nodes=['D', 'G', 'S', 'B'] + ) + + return component @cell @@ -547,6 +569,26 @@ def pmos( horizontal_glayer=substrate_tap_layers[0], vertical_glayer=substrate_tap_layers[1], ) - return rename_ports_by_orientation(pfet).flatten() + component = rename_ports_by_orientation(pfet).flatten() + + # add spice netlist + dummy_tuple = (True, True) + if with_dummy == False: + dummy_tuple = (False, False) + else: + dummy_tuple = with_dummy + + component.info['netlist'] = Netlist( + source_netlist=f""" +.subckt NMOS D G S B +{f"M1 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[0] else ""} +M2 D G S B {pdk.models['pfet']} l={length} w={width} m={fingers * multiplier} +{f"M3 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[1] else ""} +.ends NMOS + """, + nodes=['D', 'G', 'S', 'B'] + ) + + return component From 04b292018bc06a38b40faaa9b885d2e6dd102db6 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:43:55 +0530 Subject: [PATCH 06/57] fix: fixed typo --- openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py index 6cd47ea4f..520e393ee 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py @@ -60,7 +60,7 @@ class MappedPDK(Pdk): @validator("models") def models_check(cls, models_obj: dict[StrictStr, StrictStr]): - for model in models_obj.key(): + for model in models_obj.keys(): if not model in ["nmos","pmos","mimcap"]: raise ValueError("specify nmos, pmos, or mimcap models only") return models_obj From f6923ab81aee584d0dbf299adff68cacc202662d Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:44:54 +0530 Subject: [PATCH 07/57] fix: used the correct keys in validation --- openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py index 520e393ee..70cbc8813 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py @@ -61,8 +61,8 @@ class MappedPDK(Pdk): @validator("models") def models_check(cls, models_obj: dict[StrictStr, StrictStr]): for model in models_obj.keys(): - if not model in ["nmos","pmos","mimcap"]: - raise ValueError("specify nmos, pmos, or mimcap models only") + if not model in ["nfet","pfet","mimcap"]: + raise ValueError(f"specify nfet, pfet, or mimcap models only") return models_obj @validator("glayers") From 5d5413c0bdbd32502b47e2a4caae80808b83fcf8 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:46:06 +0530 Subject: [PATCH 08/57] fix: fixed dummy tuple --- .../generators/gdsfactory-gen/glayout/primitives/fet.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index f12ea1444..35b71a7f0 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -427,9 +427,10 @@ def nmos( component = rename_ports_by_orientation(nfet).flatten() # add spice netlist - dummy_tuple = (True, True) if with_dummy == False: dummy_tuple = (False, False) + elif with_dummy == True: + dummy_tuple = (True, True) else: dummy_tuple = with_dummy @@ -572,9 +573,10 @@ def pmos( component = rename_ports_by_orientation(pfet).flatten() # add spice netlist - dummy_tuple = (True, True) if with_dummy == False: dummy_tuple = (False, False) + elif with_dummy == True: + dummy_tuple = (True, True) else: dummy_tuple = with_dummy From 29b7d7837f02f79bcb6b6511322728ee3d3d751d Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:46:36 +0530 Subject: [PATCH 09/57] fix: fixed multiplier typo --- openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index 35b71a7f0..3e0481b16 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -438,7 +438,7 @@ def nmos( source_netlist=f""" .subckt NMOS D G S B {f"M1 B B B B {pdk.models['nfet']} l={length} w={width} m={fingers}" if dummy_tuple[0] else ""} -M2 D G S B {pdk.models['nfet']} l={length} w={width} m={fingers * multiplier} +M2 D G S B {pdk.models['nfet']} l={length} w={width} m={fingers * multipliers} {f"M3 B B B B {pdk.models['nfet']} l={length} w={width} m={fingers}" if dummy_tuple[1] else ""} .ends NMOS """, @@ -584,7 +584,7 @@ def pmos( source_netlist=f""" .subckt NMOS D G S B {f"M1 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[0] else ""} -M2 D G S B {pdk.models['pfet']} l={length} w={width} m={fingers * multiplier} +M2 D G S B {pdk.models['pfet']} l={length} w={width} m={fingers * multipliers} {f"M3 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[1] else ""} .ends NMOS """, From bcee192116b49f5818300e37d0146eb6cff05de1 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:49:36 +0530 Subject: [PATCH 10/57] refactor: made generate_instance parameters optional --- .../generators/gdsfactory-gen/glayout/spice/netlist.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 771384f45..60ab85fb9 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -1,5 +1,5 @@ from os.path import join, dirname -from typing import Union +from typing import Union, Optional import re @@ -66,10 +66,16 @@ def extract_subckt_name(self, netlist: str) -> str: return 'Netlist' - def generate_instance(self, name: str, nodes: list[str]) -> str: + def generate_instance(self, name: Optional[str], nodes: Optional[list[str]]) -> str: """Generates an instance of the netlist subcircuit. Override to insert parameters in the instance. """ + if name == None: + name = self.circuit_name + + if nodes == None: + nodes = self.nodes + return f"X{name} {' '.join(nodes)} {self.circuit_name}" def read_source_netlist(self, netlist_src: str) -> str: From 0a278362db6a27ec6e77d6bce7cab6a63fe1dcb3 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:54:39 +0530 Subject: [PATCH 11/57] fix: fixed netlist generation --- openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 60ab85fb9..364daa43b 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -66,7 +66,7 @@ def extract_subckt_name(self, netlist: str) -> str: return 'Netlist' - def generate_instance(self, name: Optional[str], nodes: Optional[list[str]]) -> str: + def generate_instance(self, name: Optional[str] = None, nodes: Optional[list[str]] = None) -> str: """Generates an instance of the netlist subcircuit. Override to insert parameters in the instance. """ @@ -178,7 +178,7 @@ def __generate_self_subcircuit(self) -> str: The name of the subcircuit is set by `self.circuit_name`. """ if self.source_netlist != "": - text = self.source_netlist + return self.source_netlist elif len(self.sub_netlists) > 0: main_circuit = f".subckt {self.circuit_name} {' '.join(self.nodes)}\n" From 30e724c40ff26383c83f8bfaeb05baf16aa63ce8 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 20:55:05 +0530 Subject: [PATCH 12/57] fix: renamed pmos subcircuit to PMOS --- openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index 3e0481b16..a081f7ffb 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -582,11 +582,11 @@ def pmos( component.info['netlist'] = Netlist( source_netlist=f""" -.subckt NMOS D G S B +.subckt PMOS D G S B {f"M1 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[0] else ""} M2 D G S B {pdk.models['pfet']} l={length} w={width} m={fingers * multipliers} {f"M3 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[1] else ""} -.ends NMOS +.ends PMOS """, nodes=['D', 'G', 'S', 'B'] ) From 4882375fe953cd215e73d8cd17272781164e4f30 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 21:10:50 +0530 Subject: [PATCH 13/57] fix: fixed dummy fet multipliers --- .../generators/gdsfactory-gen/glayout/primitives/fet.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index a081f7ffb..d23d20724 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -437,9 +437,9 @@ def nmos( component.info['netlist'] = Netlist( source_netlist=f""" .subckt NMOS D G S B -{f"M1 B B B B {pdk.models['nfet']} l={length} w={width} m={fingers}" if dummy_tuple[0] else ""} +{f"M1 B B B B {pdk.models['nfet']} l={length} w={width} m={multipliers}" if dummy_tuple[0] else ""} M2 D G S B {pdk.models['nfet']} l={length} w={width} m={fingers * multipliers} -{f"M3 B B B B {pdk.models['nfet']} l={length} w={width} m={fingers}" if dummy_tuple[1] else ""} +{f"M3 B B B B {pdk.models['nfet']} l={length} w={width} m={multipliers}" if dummy_tuple[1] else ""} .ends NMOS """, nodes=['D', 'G', 'S', 'B'] @@ -583,9 +583,9 @@ def pmos( component.info['netlist'] = Netlist( source_netlist=f""" .subckt PMOS D G S B -{f"M1 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[0] else ""} +{f"M1 B B B B {pdk.models['pfet']} l={length} w={width} m={multipliers}" if dummy_tuple[0] else ""} M2 D G S B {pdk.models['pfet']} l={length} w={width} m={fingers * multipliers} -{f"M3 B B B B {pdk.models['pfet']} l={length} w={width} m={fingers}" if dummy_tuple[1] else ""} +{f"M3 B B B B {pdk.models['pfet']} l={length} w={width} m={multipliers}" if dummy_tuple[1] else ""} .ends PMOS """, nodes=['D', 'G', 'S', 'B'] From 73ed4eef6781fa0841643da22d94d23297ef4fab Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 21:45:30 +0530 Subject: [PATCH 14/57] feat: updated Netlist to support multiple subcircuits with same name --- .../gdsfactory-gen/glayout/primitives/fet.py | 56 +++++++++++++------ .../glayout/primitives/mimcap.py | 16 ++++-- .../gdsfactory-gen/glayout/spice/netlist.py | 25 ++++++--- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index d23d20724..fdcc1319d 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -434,15 +434,27 @@ def nmos( else: dummy_tuple = with_dummy + nmos_netlist=""".subckt {circuit_name} {nodes} +M1 D G S B {model} l={length} w={width} m={mult}""" + + if dummy_tuple[0]: + nmos_netlist += "\nM2 B B B B {model} l={length} w={width} m={dummy_mult}" + if dummy_tuple[1]: + nmos_netlist += "\nM3 B B B B {model} l={length} w={width} m={dummy_mult}" + + nmos_netlist += "\n.ends {circuit_name}" + component.info['netlist'] = Netlist( - source_netlist=f""" -.subckt NMOS D G S B -{f"M1 B B B B {pdk.models['nfet']} l={length} w={width} m={multipliers}" if dummy_tuple[0] else ""} -M2 D G S B {pdk.models['nfet']} l={length} w={width} m={fingers * multipliers} -{f"M3 B B B B {pdk.models['nfet']} l={length} w={width} m={multipliers}" if dummy_tuple[1] else ""} -.ends NMOS - """, - nodes=['D', 'G', 'S', 'B'] + circuit_name="NMOS", + nodes=['D', 'G', 'S', 'B'], + source_netlist=nmos_netlist, + parameters={ + 'model': pdk.models['nfet'], + 'length': length, + 'width': width, + 'mult': fingers * multipliers, + 'dummy_mult': multipliers + } ) return component @@ -580,15 +592,27 @@ def pmos( else: dummy_tuple = with_dummy + pmos_netlist=""".subckt {circuit_name} {nodes} +M1 D G S B {model} l={length} w={width} m={mult}""" + + if dummy_tuple[0]: + pmos_netlist += "\nM2 B B B B {model} l={length} w={width} m={dummy_mult}" + if dummy_tuple[1]: + pmos_netlist += "\nM3 B B B B {model} l={length} w={width} m={dummy_mult}" + + pmos_netlist += "\n.ends {circuit_name}" + component.info['netlist'] = Netlist( - source_netlist=f""" -.subckt PMOS D G S B -{f"M1 B B B B {pdk.models['pfet']} l={length} w={width} m={multipliers}" if dummy_tuple[0] else ""} -M2 D G S B {pdk.models['pfet']} l={length} w={width} m={fingers * multipliers} -{f"M3 B B B B {pdk.models['pfet']} l={length} w={width} m={multipliers}" if dummy_tuple[1] else ""} -.ends PMOS - """, - nodes=['D', 'G', 'S', 'B'] + circuit_name="PMOS", + nodes=['D', 'G', 'S', 'B'], + source_netlist=pmos_netlist, + parameters={ + 'model': pdk.models['pfet'], + 'length': length, + 'width': width, + 'mult': fingers * multipliers, + 'dummy_mult': multipliers + } ) return component diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 9c95d2769..bb138dbfd 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -54,12 +54,18 @@ def mimcap( # netlist generation component.info['netlist'] = Netlist( - source_netlist=f""" -.subckt MIMCAP V1 V2 -C1 V1 V2 ${pdk.models['mimcap']} l={size[0]} w={size[1]} -.ends MIMCAP + circuit_name="MIMCap", + nodes = ['V1', 'V2'], + source_netlist=""" +.subckt {circuit_name} {nodes} +C1 V1 V2 {model} l={length} w={width} +.ends {circuit_name} """, - nodes = ['V1', 'V2'] + parameters={ + 'model': pdk.models['mimcap'], + 'length': size[0], + 'width': size[1] + } ) return component diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 364daa43b..96d438fb6 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -169,24 +169,30 @@ def connect_netlist(self, netlist: 'Netlist', node_mapping: list[tuple[str, str] return netlist_index - def generate_source_netlist_params(self) -> dict: - """Generates the [Mako](https://makotemplates.org) parameters to be inserted in the source SPICE netlist.""" - return self.parameters - - def __generate_self_subcircuit(self) -> str: + def generate_source_netlist_params(self, circuit_name: Optional[str] = None) -> dict: + """Generates the parameters to be inserted in the source SPICE netlist. Uses the Python template string format.""" + return { + 'circuit_name': circuit_name if circuit_name != None else self.circuit_name, + 'nodes': ' '.join(self.nodes), + **self.parameters + } + + def __generate_self_subcircuit(self, prefix: str = '', suffix: str = '') -> str: """Generates the top-level SPICE subcircuit directive. The name of the subcircuit is set by `self.circuit_name`. """ + generated_circuit_name = f"{prefix}{self.circuit_name}{suffix}" + if self.source_netlist != "": - return self.source_netlist + return self.source_netlist.format(**self.generate_source_netlist_params(generated_circuit_name)) elif len(self.sub_netlists) > 0: - main_circuit = f".subckt {self.circuit_name} {' '.join(self.nodes)}\n" + main_circuit = f".subckt {generated_circuit_name} {' '.join(self.nodes)}\n" for i, netlist in enumerate(self.sub_netlists): main_circuit += netlist.generate_instance(i, self.netlist_connections[i]) + "\n" - main_circuit += f".ends {self.circuit_name}" + main_circuit += f".ends {generated_circuit_name}" return main_circuit @@ -197,7 +203,8 @@ def get_subcircuits_list(self, sub_netlists_only = False) -> set[str]: """Generates a list of all the unique SPICE subcircuits directives used in the netlist.""" subcircuits = set() - for netlist in self.sub_netlists: + for i, netlist in enumerate(self.sub_netlists): + netlist.circuit_name = f"{self.circuit_name}_{i}_{netlist.circuit_name}" subcircuits.update(netlist.get_subcircuits_list()) if not sub_netlists_only: subcircuits.add(self.__generate_self_subcircuit()) From 3f72a0816e879c9b8c69fd9d3a4bfd69402aa936 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Mon, 13 Nov 2023 21:45:43 +0530 Subject: [PATCH 15/57] feat: added diff pair netlist --- .../glayout/components/diff_pair.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py index 6b7e96de5..93b8cf357 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py @@ -13,7 +13,7 @@ from glayout.primitives.via_gen import via_stack from glayout.primitives.guardring import tapring from glayout.pdk.util.snap_to_grid import component_snap_to_grid - +from glayout.spice.netlist import Netlist @cell def diff_pair( @@ -141,7 +141,23 @@ def diff_pair( diffpair.add_ports(PLUSgate_routeW.get_ports_list(),prefix="PLUSgateroute_W_") diffpair.add_ports(PLUSgate_routeE.get_ports_list(),prefix="PLUSgateroute_E_") diffpair.add_padding(layers=(pdk.get_glayer(well),), default=0) - return component_snap_to_grid(rename_ports_by_orientation(diffpair)) + + component = component_snap_to_grid(rename_ports_by_orientation(diffpair)) + + # add spice netlist + diff_pair_netlist = Netlist(circuit_name='DIFF_PAIR', nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VTAIL', 'B']) + diff_pair_netlist.connect_netlist( + fetL.info['netlist'], + [('D', 'VDD1'), ('G', 'VP'), ('S', 'VTAIL'), ('B', 'B')] + ) + diff_pair_netlist.connect_netlist( + fetR.info['netlist'], + [('D', 'VDD2'), ('G', 'VN'), ('S', 'VTAIL'), ('B', 'B')] + ) + + component.info['netlist'] = diff_pair_netlist + return component + From 9c878dcfc9128b6c0aabbe43eae90e0b44ec9162 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Wed, 15 Nov 2023 01:41:10 +0530 Subject: [PATCH 16/57] feat: added differential to single netlist --- .../differential_to_single_ended_converter.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index cf4e5e97c..4172e5d01 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -18,6 +18,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized +from glayout.spice.netlist import Netlist @@ -83,6 +84,7 @@ def __create_sharedgatecomps(pdk: MappedPDK, rmult: int, half_pload: tuple[float ytranslation_pcenter = 2 * pcenterfourunits.ymax + 5*pdk.util_max_metal_seperation() ptop_AB = (shared_gate_comps << twomultpcomps).movey(ytranslation_pcenter) pbottom_AB = (shared_gate_comps << twomultpcomps).movey(-1 * ytranslation_pcenter) + return shared_gate_comps, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports @@ -150,4 +152,28 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa pmos_comps, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports = __create_sharedgatecomps(pdk, rmult,half_pload) clear_cache() pmos_comps = __route_sharedgatecomps(pdk, pmos_comps, via_xlocation, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports) + + # add spice netlist + diff_to_single_netlist = Netlist( + circuit_name="DIFF_TO_SINGLE", + nodes=['VIN', 'VOUT', 'VSS', 'VSS2', 'VBB'] + source_netlist=""" +.subckt {circuit_name} {nodes} +X1 V1 VIN VSS VSS ${model} l={length} w={width} m={mult_top} +X2 VSS2 VIN VSS VSS ${model} l={length} w={width} m={mult_top} +X3 VIN VIN V1 VSS ${model} l={length} w={width} m={mult_bot} +X4 VOUT VIN VSS2 VSS ${model} l={length} w={width} m={mult_bot} +.ends {circuit_name} + """, + parameters={ + 'model': pdk.models['pfet'], + 'width': half_pload[0], + 'length': half_pload[1], + 'mult_top': 4 * 2, + 'mult_bot': half_pload[2] * 2 + } + ) + + pmos_comps.info['netlist'] = diff_to_single_netlist + return pmos_comps From 4fd153bf0fc52cd9b8a35a1f37dbdff3b501ddce Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Wed, 15 Nov 2023 02:36:35 +0530 Subject: [PATCH 17/57] feat: added diff_pair_cmirrorbias netlist --- .../components/diff_pair_cmirrorbias.py | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 1aa06da39..782428c27 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -35,7 +35,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized - +from glayout.spice.netlist import Netlist @validate_arguments def diff_pair_ibias( @@ -145,6 +145,23 @@ def diff_pair_ibias( viaoffset=False, ) cmirror.add_ports(srcshort.get_ports_list(), prefix="purposegndports") + # current mirror netlist + cmirror.info['netlist'] = Netlist( + circuit_name='CURRENT_MIRROR', + nodes=['VREF', 'VCOPY', 'VSS'], + source_netlist=""" +.subckt {circuit_name} {nodes} +M1 VREF VREF VSS VSS {model} l={length} w={width} m={mult} +M2 VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} +.ends {circuit_name} + """, + parameters={ + 'model': pdk.models['nfet'], + 'width': diffpair_bias[0], + 'length': diffpair_bias[1] + } + ) + # add cmirror tailcurrent_ref = diffpair_i_ << cmirror tailcurrent_ref.movey( @@ -158,6 +175,29 @@ def diff_pair_ibias( purposegndPort.name = "ibias_purposegndport" diffpair_i_.add_ports([purposegndPort]) diffpair_i_.add_ports(tailcurrent_ref.get_ports_list(), prefix="ibias_") + + # complete netlist + diffpair_i_.info['netlist'] = Netlist( + circuit_name="DIFFPAIR_CMIRROR_BIAS", + nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VBIAS', 'VSS', 'B'] + ) + + diffpair_i_.info['netlist'].connect_netlist( + center_diffpair_comp.info['netlist'], + [] + ) + + diffpair_i_.info['netlist'].connect_netlist( + cmirror.info['netlist'], + [('VREF', 'VBIAS')] + ) + + diffpair_i_.info['netlist'].connect_subnets( + cmirror.info['netlist'], + center_diffpair_comp.info['netlist'], + [('VCOPY', 'VTAIL')] + ) + diffpair_i_ref = prec_ref_center(diffpair_i_) return diffpair_i_ref From b03685e226294b7f06b0eb5131681cfdd25f085e Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Wed, 15 Nov 2023 23:19:28 +0530 Subject: [PATCH 18/57] feat: added netlist for mimcap array --- .../gdsfactory-gen/glayout/primitives/mimcap.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index bb138dbfd..3776d9f1f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -111,6 +111,18 @@ def mimcap_array(pdk: MappedPDK, rows: int, columns: int, size: tuple[float,floa port_pairs.append((bl_north_port,top_south_port,layer)) for port_pair in port_pairs: mimcap_arr << straight_route(pdk,port_pair[0],port_pair[1],width=rmult*pdk.get_grule(port_pair[2])["min_width"]) + + # add netlist + mimcap_arr.info['netlist'] = Netlist( + nodes = ['V1', 'V2'] + ) + + for _ in range(rows * columns): + mimcap_arr.info['netlist'].connect_netlist( + mimcap_single.info['netlist'], + [('V1', 'V1'), ('V2', 'V2')] + ) + return mimcap_arr.flatten() From f790d354fa5c9ddafe3c12aa016d84e4c086d88e Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Wed, 15 Nov 2023 23:21:19 +0530 Subject: [PATCH 19/57] feat: added more netlists --- .../gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py | 3 ++- .../components/differential_to_single_ended_converter.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 782428c27..c48c43021 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -158,7 +158,8 @@ def diff_pair_ibias( parameters={ 'model': pdk.models['nfet'], 'width': diffpair_bias[0], - 'length': diffpair_bias[1] + 'length': diffpair_bias[1], + 'mult': diffpair_bias[2] } ) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 4172e5d01..4f41301dc 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -156,7 +156,7 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa # add spice netlist diff_to_single_netlist = Netlist( circuit_name="DIFF_TO_SINGLE", - nodes=['VIN', 'VOUT', 'VSS', 'VSS2', 'VBB'] + nodes=['VIN', 'VOUT', 'VSS', 'VSS2', 'VBB'], source_netlist=""" .subckt {circuit_name} {nodes} X1 V1 VIN VSS VSS ${model} l={length} w={width} m={mult_top} From a2ef9ffe01b90a8aedf52d76dccebf57a24759b7 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 16 Nov 2023 15:09:54 +0530 Subject: [PATCH 20/57] feat: added input and gain stages' netlists --- .../components/diff_pair_stackedcmirror.py | 12 ++-- .../differential_to_single_ended_converter.py | 2 +- .../glayout/components/opamp_twostage.py | 67 ++++++++++++++++++- ...mplifier_diff_to_single_ended_converter.py | 27 +++++++- 4 files changed, 100 insertions(+), 8 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_stackedcmirror.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_stackedcmirror.py index 40418bea1..7e98e6118 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_stackedcmirror.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_stackedcmirror.py @@ -31,6 +31,9 @@ def __add_diff_pair_and_bias(pdk: MappedPDK, toplevel_stacked: Component, half_d diffpair_i_ref = diff_pair_ibias(pdk, half_diffpair_params, diffpair_bias, rmult, with_antenna_diode_on_diffinputs) toplevel_stacked.add(diffpair_i_ref) toplevel_stacked.add_ports(diffpair_i_ref.get_ports_list(),prefix="diffpair_") + + toplevel_stacked.info['netlist'] = diffpair_i_ref.info['netlist'] + return toplevel_stacked @validate_arguments @@ -103,11 +106,11 @@ def __route_bottom_ncomps_except_drain_nbias(pdk: MappedPDK, toplevel_stacked: C def diff_pair_stackedcmirror( - pdk: MappedPDK, - half_diffpair_params: tuple[float, float, int], - diffpair_bias: tuple[float, float, int], + pdk: MappedPDK, + half_diffpair_params: tuple[float, float, int], + diffpair_bias: tuple[float, float, int], half_common_source_nbias: tuple[float, float, int, int], - rmult: int, + rmult: int, with_antenna_diode_on_diffinputs: int ) -> Component: # create toplevel_stacked component @@ -123,4 +126,5 @@ def diff_pair_stackedcmirror( # route bottom ncomps except drain of nbias (still need to place common source pmos amp) toplevel_stacked, halfmultn_drain_routeref, halfmultn_gate_routeref, _cref = __route_bottom_ncomps_except_drain_nbias(pdk, toplevel_stacked, gndpin, half_common_source_nbias[3]) toplevel_stacked.add_ports(gndpin.get_ports_list(), prefix="pin_gnd_") + return toplevel_stacked, halfmultn_drain_routeref, halfmultn_gate_routeref, _cref diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 4f41301dc..8881f1efe 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -156,7 +156,7 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa # add spice netlist diff_to_single_netlist = Netlist( circuit_name="DIFF_TO_SINGLE", - nodes=['VIN', 'VOUT', 'VSS', 'VSS2', 'VBB'], + nodes=['VIN', 'VOUT', 'VSS', 'VSS2'], source_netlist=""" .subckt {circuit_name} {nodes} X1 V1 VIN VSS VSS ${model} l={length} w={width} m={mult_top} diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index a9dca9b80..2604094fd 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -24,7 +24,7 @@ from glayout.components.differential_to_single_ended_converter import differential_to_single_ended_converter from glayout.components.row_csamplifier_diff_to_single_ended_converter import row_csamplifier_diff_to_single_ended_converter from glayout.components.diff_pair_stackedcmirror import diff_pair_stackedcmirror - +from glayout.spice.netlist import Netlist @validate_arguments @@ -159,10 +159,48 @@ def opamp_twostage( if half_common_source_bias[3] < 2: raise ValueError("half_common_source_bias num multiplier must be >= 2") opamp_top, halfmultn_drain_routeref, halfmultn_gate_routeref, _cref = diff_pair_stackedcmirror(pdk, half_diffpair_params, diffpair_bias, half_common_source_bias, rmult, with_antenna_diode_on_diffinputs) + + opamp_top.info['netlist'].circuit_name = "INPUT_STAGE" + # place pmos components pmos_comps = differential_to_single_ended_converter(pdk, rmult, half_pload, opamp_top.ports["diffpair_tl_multiplier_0_drain_N"].center[0]) clear_cache() + pmos_comps = row_csamplifier_diff_to_single_ended_converter(pdk, pmos_comps, half_common_source_params, rmult) + + cs_bias_netlist = Netlist( + circuit_name='CURRENT_MIRROR', + nodes=['VREF', 'VCOPY', 'VSS'], + source_netlist=""" +.subckt {circuit_name} {nodes} +M1 VREF VREF VSS VSS {model} l={length} w={width} m={mult} +M2 VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} +.ends {circuit_name} + """, + parameters={ + 'model': pdk.models['nfet'], + 'width': diffpair_bias[0], + 'length': diffpair_bias[1], + 'mult': diffpair_bias[2] + } + ) + + diff_cs_netlist = pmos_comps.info['netlist'] + pmos_comps.info['netlist'] = Netlist( + circuit_name="GAIN_STAGE", + nodes=['VIN', 'VOUT', 'VSS2', 'VSS', 'VBIAS', 'GND'] + ) + + pmos_comps.info['netlist'].connect_netlist( + diff_cs_netlist, + [('CSOUT', 'VOUT')] + ) + + pmos_comps.info['netlist'].connect_netlist( + cs_bias_netlist, + [('VREF', 'VBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] + ) + ydim_ncomps = opamp_top.ymax pmos_comps_ref = opamp_top << pmos_comps pmos_comps_ref.movey(round(ydim_ncomps + pmos_comps_ref.ymax+10)) @@ -178,6 +216,33 @@ def opamp_twostage( opamp_top.add_ports(n_to_p_output_route.get_ports_list(),"special_con_npr_") # return opamp_top.add_ports(_cref.get_ports_list(), prefix="gnd_route_") + + two_stage_netlist = Netlist( + circuit_name="OPAMP_TWO_STAGE", + nodes=['VDD', 'GND', 'VBIAS1', 'VP', 'VN', 'VSS2', 'VBIAS2', 'VOUT'] + ) + + input_stage_netlist = opamp_top.info['netlist'] + gain_stage_netlist = pmos_comps.info['netlist'] + + two_stage_netlist.connect_netlist( + input_stage_netlist, + [('VBIAS', 'VBIAS1'), ('VSS', 'GND'), ('B', 'GND')] + ) + + two_stage_netlist.connect_netlist( + gain_stage_netlist, + [('VSS', 'GND')] + ) + + two_stage_netlist.connect_subnets( + input_stage_netlist, + gain_stage_netlist, + [('VDD1', 'VIN1'), ('VDD2', 'VIN2')] + ) + + opamp_top.info['netlist'] = two_stage_netlist + return opamp_top diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py index 12763dbb9..c3dc7ec43 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py @@ -18,11 +18,24 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized - +from glayout.spice.netlist import Netlist def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_single_ended_converter: Component, pamp_hparams, rmult) -> Component: pmos_comps = diff_to_single_ended_converter + + overall_netlist = Netlist( + circuit_name="DIFF_TO_SINGLE_CS", + nodes=['VIN1', 'VIN2', 'VOUT', 'VSS', 'VSS2'] + ) + + overall_netlist.connect_netlist( + pmos_comps.info['netlist'], + [('VIN', 'VIN1'), ('VOUT', 'VIN2')] + ) + + pmos_comps.info['netlist'] = overall_netlist + x_dim_center = max(abs(pmos_comps.xmax),abs(pmos_comps.xmin)) for direction in [-1, 1]: halfMultp = pmos( @@ -43,6 +56,16 @@ def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_singl label = "L_" if direction==-1 else "R_" # this special marker is used to rename these ports in the opamp to commonsource_Pamp_ pmos_comps.add_ports(halfMultp_ref.get_ports_list(),prefix="halfpspecialmarker_"+label) + + pmos_comps.info['netlist'].connect_netlist( + halfMultp.info['netlist'], + [('D', 'VOUT'), ('S', 'VSS'), ('B', 'VSS')] + ) + + pmos_comps.info['netlist'].connect_subnets( + 0, halfMultp.info['netlist'], [('VOUT', 'G')] + ) + # add npadding and add ports nwellbbox = pmos_comps.extract(layers=[pdk.get_glayer("poly"),pdk.get_glayer("active_diff"),pdk.get_glayer("active_tap"), pdk.get_glayer("nwell"),pdk.get_glayer("dnwell")]).bbox nwellspacing = pdk.get_grule("nwell", "active_tap")["min_enclosure"] @@ -58,4 +81,4 @@ def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_singl pmos_comps << straight_route(pdk, pmos_comps.ports["pbottomAB_L_welltap_W_top_met_W"],pmos_comps.ports["halfpspecialmarker_L_tie_E_top_met_W"],width=2,glayer1="met2",via1_alignment=('c','c'),via2_alignment=('c','c'),fullbottom=True) pmos_comps << straight_route(pdk, pmos_comps.ports["pbottomAB_R_welltap_E_top_met_E"],pmos_comps.ports["halfpspecialmarker_R_tie_W_top_met_E"],width=2,glayer1="met2",via1_alignment=('c','c'),via2_alignment=('c','c'),fullbottom=True) return pmos_comps - + From 1f2fafeaaf422eee7fec4057226dfb3588fdea66 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 16 Nov 2023 15:14:49 +0530 Subject: [PATCH 21/57] fix: fixed netlist node naming issues --- .../gdsfactory-gen/glayout/components/opamp_twostage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index 2604094fd..fec8ce78c 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -193,7 +193,7 @@ def opamp_twostage( pmos_comps.info['netlist'].connect_netlist( diff_cs_netlist, - [('CSOUT', 'VOUT')] + [] ) pmos_comps.info['netlist'].connect_netlist( @@ -238,7 +238,7 @@ def opamp_twostage( two_stage_netlist.connect_subnets( input_stage_netlist, gain_stage_netlist, - [('VDD1', 'VIN1'), ('VDD2', 'VIN2')] + [('VDD1', 'VIN'), ('VDD2', 'VOUT')] ) opamp_top.info['netlist'] = two_stage_netlist From 4e79c65263a93595473caba74997590a4f2f5ecd Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 16 Nov 2023 15:25:37 +0530 Subject: [PATCH 22/57] feat: named mimcap array netlist --- openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 3776d9f1f..67030563f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -114,6 +114,7 @@ def mimcap_array(pdk: MappedPDK, rows: int, columns: int, size: tuple[float,floa # add netlist mimcap_arr.info['netlist'] = Netlist( + circuit_name="MIMCAP_ARR", nodes = ['V1', 'V2'] ) From 0f0107421c517e91072e9912b49d50b34c97ea24 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 16 Nov 2023 15:44:20 +0530 Subject: [PATCH 23/57] feat: connected miller capacitor netlist --- .../glayout/components/opamp_twostage.py | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index fec8ce78c..271621d95 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -106,10 +106,13 @@ def __create_and_route_pins( @validate_arguments -def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap_rows, ymin: float, n_to_p_output_route) -> Component: +def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap_rows, ymin: float, n_to_p_output_route) -> tuple[Component, Netlist]: mim_cap_size = pdk.snap_to_2xgrid(mim_cap_size, return_type="float") max_metalsep = pdk.util_max_metal_seperation() mimcaps_ref = opamp_top << mimcap_array(pdk,mim_cap_rows,2,size=mim_cap_size,rmult=6) + + mimcap_netlist = mimcaps_ref.info['netlist'] + displace_fact = max(max_metalsep,pdk.get_grule("capmet")["min_separation"]) mimcaps_ref.movex(pdk.snap_to_2xgrid(opamp_top.xmax + displace_fact + mim_cap_size[0]/2)) mimcaps_ref.movey(pdk.snap_to_2xgrid(ymin + mim_cap_size[1]/2)) @@ -123,7 +126,7 @@ def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap opamp_top.add_ports(mimcaps_ref.get_ports_list(),prefix="mimcap_") # add the cs output as a port opamp_top.add_port(name="commonsource_output_E", port=intermediate_output) - return opamp_top + return opamp_top, mimcap_netlist @@ -185,10 +188,26 @@ def opamp_twostage( } ) + ydim_ncomps = opamp_top.ymax + pmos_comps_ref = opamp_top << pmos_comps + pmos_comps_ref.movey(round(ydim_ncomps + pmos_comps_ref.ymax+10)) + opamp_top.add_ports(pmos_comps_ref.get_ports_list(),prefix="pcomps_") + rename_func = lambda name_, port_ : name_.replace("pcomps_halfpspecialmarker","commonsource_Pamp") if name_.startswith("pcomps_halfpspecialmarker") else name_ + opamp_top = rename_component_ports(opamp_top, rename_function=rename_func) + # create pins and route + clear_cache() + opamp_top, n_to_p_output_route = __create_and_route_pins(pdk, opamp_top, pmos_comps_ref, halfmultn_drain_routeref, halfmultn_gate_routeref) + # place mimcaps and route + clear_cache() + opamp_top, mimcap_netlist = __add_mimcap_arr(pdk, opamp_top, mim_cap_size, mim_cap_rows, pmos_comps_ref.ymin, n_to_p_output_route) + opamp_top.add_ports(n_to_p_output_route.get_ports_list(),"special_con_npr_") + # return + opamp_top.add_ports(_cref.get_ports_list(), prefix="gnd_route_") + diff_cs_netlist = pmos_comps.info['netlist'] pmos_comps.info['netlist'] = Netlist( circuit_name="GAIN_STAGE", - nodes=['VIN', 'VOUT', 'VSS2', 'VSS', 'VBIAS', 'GND'] + nodes=['VIN', 'VOUT', 'VSS', 'VBIAS', 'GND'] ) pmos_comps.info['netlist'].connect_netlist( @@ -201,25 +220,16 @@ def opamp_twostage( [('VREF', 'VBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] ) - ydim_ncomps = opamp_top.ymax - pmos_comps_ref = opamp_top << pmos_comps - pmos_comps_ref.movey(round(ydim_ncomps + pmos_comps_ref.ymax+10)) - opamp_top.add_ports(pmos_comps_ref.get_ports_list(),prefix="pcomps_") - rename_func = lambda name_, port_ : name_.replace("pcomps_halfpspecialmarker","commonsource_Pamp") if name_.startswith("pcomps_halfpspecialmarker") else name_ - opamp_top = rename_component_ports(opamp_top, rename_function=rename_func) - # create pins and route - clear_cache() - opamp_top, n_to_p_output_route = __create_and_route_pins(pdk, opamp_top, pmos_comps_ref, halfmultn_drain_routeref, halfmultn_gate_routeref) - # place mimcaps and route - clear_cache() - opamp_top = __add_mimcap_arr(pdk, opamp_top, mim_cap_size, mim_cap_rows, pmos_comps_ref.ymin, n_to_p_output_route) - opamp_top.add_ports(n_to_p_output_route.get_ports_list(),"special_con_npr_") - # return - opamp_top.add_ports(_cref.get_ports_list(), prefix="gnd_route_") + pmos_comps.info['netlist'].connect_netlist(mimcap_netlist, [('V2', 'VOUT')]) + pmos_comps.info['netlist'].connect_subnets( + mimcap_netlist, + diff_cs_netlist, + [('V1', 'VSS2')] + ) two_stage_netlist = Netlist( circuit_name="OPAMP_TWO_STAGE", - nodes=['VDD', 'GND', 'VBIAS1', 'VP', 'VN', 'VSS2', 'VBIAS2', 'VOUT'] + nodes=['VDD', 'GND', 'VBIAS1', 'VP', 'VN', 'VBIAS2', 'VOUT'] ) input_stage_netlist = opamp_top.info['netlist'] From 88d05430dd04a680dfe972e4fdea85234a03e4c7 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 16 Nov 2023 15:48:35 +0530 Subject: [PATCH 24/57] feat: flattened mimcap_arr netlist --- .../gdsfactory-gen/glayout/primitives/mimcap.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 67030563f..8d34bbcde 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -115,15 +115,17 @@ def mimcap_array(pdk: MappedPDK, rows: int, columns: int, size: tuple[float,floa # add netlist mimcap_arr.info['netlist'] = Netlist( circuit_name="MIMCAP_ARR", - nodes = ['V1', 'V2'] + nodes = ['V1', 'V2'], + source_netlist=""" +.subckt {circuit_name} {nodes} +{mimcap_arr_instances} +.ends {circuit_name} + """, + parameters={ + 'mimcap_arr_instances': '\n'.join([f"C{i+1} {pdk.models['mimcap']} V1 V2 w={size[0]} l={size[1]}" for i in range(rows * columns)]) + } ) - for _ in range(rows * columns): - mimcap_arr.info['netlist'].connect_netlist( - mimcap_single.info['netlist'], - [('V1', 'V1'), ('V2', 'V2')] - ) - return mimcap_arr.flatten() From bc0be6ebf3f693ae4bd84acb7a5712641d5f58ff Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 16 Nov 2023 23:19:12 +0530 Subject: [PATCH 25/57] feat: completed output stage and top level netlists --- .../glayout/components/opamp.py | 68 +++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index eff2e0237..8d276bdda 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -18,7 +18,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized - +from glayout.spice.netlist import Netlist from glayout.components.opamp_twostage import opamp_twostage @@ -30,7 +30,7 @@ def __add_output_stage( amplifierParams: tuple[float, float, int], biasParams: list, rmult: int, -) -> Component: +) -> tuple[Component, Netlist]: '''add output stage to opamp_top, args: pdk = pdk to use opamp_top = component to add output stage to @@ -65,6 +65,7 @@ def __add_output_stage( with_substrate_tap=False, tie_layers=("met2","met2") ) + metal_sep = pdk.util_max_metal_seperation() # Locate output stage relative position # x-coordinate: Center of SW capacitor in array @@ -107,7 +108,46 @@ def __add_output_stage( bias_pin.movex(cmirror_ibias.center[0]).movey(cmirror_ibias.ports["B_gate_S"].center[1]-bias_pin.ymax-5*metal_sep) opamp_top << straight_route(pdk, bias_pin.ports["e2"], cmirror_ibias.ports["B_gate_S"],width=1) opamp_top.add_ports(bias_pin.get_ports_list(),prefix="pin_outputibias_") - return opamp_top + + bias_netlist = Netlist( + circuit_name='CURRENT_MIRROR', + nodes=['VREF', 'VCOPY', 'VSS'], + source_netlist=""" +.subckt {circuit_name} {nodes} +M1 VREF VREF VSS VSS {model} l={length} w={width} m={mult} +M2 VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} +.ends {circuit_name} + """, + parameters={ + 'model': pdk.models['nfet'], + 'width': biasParams[0], + 'length': biasParams[1], + 'mult': biasParams[2] + } + ) + + output_stage_netlist = Netlist( + circuit_name="OUTPUT_STAGE", + nodes=['VDD', 'GND', 'VBIAS', 'VIN', 'VOUT'] + ) + + output_stage_netlist.connect_netlist( + amp_fet_ref.info['netlist'], + [('D', 'VDD'), ('G', 'VIN'), ('B', 'GND')] + ) + + output_stage_netlist.connect_netlist( + bias_netlist, + [('VREF', 'VBIAS'), ('VSS', 'GND')] + ) + + output_stage_netlist.connect_subnets( + amp_fet_ref.info['netlist'], + bias_netlist, + [('S', 'VCOPY')] + ) + + return opamp_top, output_stage_netlist @@ -155,7 +195,27 @@ def opamp( with_antenna_diode_on_diffinputs ) # add output amplfier stage - opamp_top = __add_output_stage(pdk, opamp_top, output_stage_params, output_stage_bias, rmult) + opamp_top, output_stage_netlist = __add_output_stage(pdk, opamp_top, output_stage_params, output_stage_bias, rmult) + + two_stage_netlist = opamp_top.info['netlist'] + + top_level_netlist = Netlist( + circuit_name="OPAMP", + nodes=['VDD', 'GND', 'VP', 'VN', 'VOUT_PRE', 'VOUT', 'VBIAS1', 'VBIAS2', 'VBIAS3'] + ) + + top_level_netlist.connect_netlist( + two_stage_netlist, + [('VOUT', 'VOUT_PRE')] + ) + + top_level_netlist.connect_netlist( + output_stage_netlist, + [('VBIAS', 'VBIAS3'), ('VIN', 'VOUT_PRE')] + ) + + opamp_top.info['netlist'] = top_level_netlist + # return return rename_ports_by_orientation(component_snap_to_grid(opamp_top)) From 69a22d8b8de547d116b196c72a2e8b1929fec13b Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 16 Nov 2023 23:24:14 +0530 Subject: [PATCH 26/57] fix: removed $ typo --- .../components/differential_to_single_ended_converter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 8881f1efe..18b89f352 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -159,10 +159,10 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa nodes=['VIN', 'VOUT', 'VSS', 'VSS2'], source_netlist=""" .subckt {circuit_name} {nodes} -X1 V1 VIN VSS VSS ${model} l={length} w={width} m={mult_top} -X2 VSS2 VIN VSS VSS ${model} l={length} w={width} m={mult_top} -X3 VIN VIN V1 VSS ${model} l={length} w={width} m={mult_bot} -X4 VOUT VIN VSS2 VSS ${model} l={length} w={width} m={mult_bot} +X1 V1 VIN VSS VSS {model} l={length} w={width} m={mult_top} +X2 VSS2 VIN VSS VSS {model} l={length} w={width} m={mult_top} +X3 VIN VIN V1 VSS {model} l={length} w={width} m={mult_bot} +X4 VOUT VIN VSS2 VSS {model} l={length} w={width} m={mult_bot} .ends {circuit_name} """, parameters={ From 47216600e078b3924b138ed679a1a821c286b4c1 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 01:50:07 +0530 Subject: [PATCH 27/57] fix: fixed sky130 fet model names --- .../gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py b/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py index 06e5f995a..b0d21547c 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/pdk/sky130_mapped/sky130_mapped.py @@ -39,8 +39,8 @@ name="sky130", glayers=sky130_glayer_mapping, models={ - 'nfet': 'sky130_fd_pr__nfet_01v8__model', - 'pfet': 'sky130_fd_pr__pfet_01v8__model', + 'nfet': 'sky130_fd_pr__nfet_01v8', + 'pfet': 'sky130_fd_pr__pfet_01v8', 'mimcap': 'sky130_fd_pr__cap_mim_m3_1' }, grules=grulesobj, From 25e06cb4c87c7dade5b87c78771015a143435a2e Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 01:59:39 +0530 Subject: [PATCH 28/57] feat: renamed vbias to ibias --- .../glayout/components/diff_pair_cmirrorbias.py | 4 ++-- .../generators/gdsfactory-gen/glayout/components/opamp.py | 8 ++++---- .../gdsfactory-gen/glayout/components/opamp_twostage.py | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index c48c43021..1d58fc806 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -180,7 +180,7 @@ def diff_pair_ibias( # complete netlist diffpair_i_.info['netlist'] = Netlist( circuit_name="DIFFPAIR_CMIRROR_BIAS", - nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VBIAS', 'VSS', 'B'] + nodes=['VP', 'VN', 'VDD1', 'VDD2', 'IBIAS', 'VSS', 'B'] ) diffpair_i_.info['netlist'].connect_netlist( @@ -190,7 +190,7 @@ def diff_pair_ibias( diffpair_i_.info['netlist'].connect_netlist( cmirror.info['netlist'], - [('VREF', 'VBIAS')] + [('VREF', 'IBIAS')] ) diffpair_i_.info['netlist'].connect_subnets( diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 8d276bdda..3ce80947b 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -128,7 +128,7 @@ def __add_output_stage( output_stage_netlist = Netlist( circuit_name="OUTPUT_STAGE", - nodes=['VDD', 'GND', 'VBIAS', 'VIN', 'VOUT'] + nodes=['VDD', 'GND', 'IBIAS', 'VIN', 'VOUT'] ) output_stage_netlist.connect_netlist( @@ -138,7 +138,7 @@ def __add_output_stage( output_stage_netlist.connect_netlist( bias_netlist, - [('VREF', 'VBIAS'), ('VSS', 'GND')] + [('VREF', 'IBIAS'), ('VSS', 'GND')] ) output_stage_netlist.connect_subnets( @@ -201,7 +201,7 @@ def opamp( top_level_netlist = Netlist( circuit_name="OPAMP", - nodes=['VDD', 'GND', 'VP', 'VN', 'VOUT_PRE', 'VOUT', 'VBIAS1', 'VBIAS2', 'VBIAS3'] + nodes=['VDD', 'GND', 'VP', 'VN', 'VOUT_PRE', 'VOUT', 'IBIAS1', 'IBIAS2', 'IBIAS3'] ) top_level_netlist.connect_netlist( @@ -211,7 +211,7 @@ def opamp( top_level_netlist.connect_netlist( output_stage_netlist, - [('VBIAS', 'VBIAS3'), ('VIN', 'VOUT_PRE')] + [('IBIAS', 'IBIAS3'), ('VIN', 'VOUT_PRE')] ) opamp_top.info['netlist'] = top_level_netlist diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index 271621d95..dc2c2d0e2 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -207,7 +207,7 @@ def opamp_twostage( diff_cs_netlist = pmos_comps.info['netlist'] pmos_comps.info['netlist'] = Netlist( circuit_name="GAIN_STAGE", - nodes=['VIN', 'VOUT', 'VSS', 'VBIAS', 'GND'] + nodes=['VIN', 'VOUT', 'VSS', 'IBIAS', 'GND'] ) pmos_comps.info['netlist'].connect_netlist( @@ -217,7 +217,7 @@ def opamp_twostage( pmos_comps.info['netlist'].connect_netlist( cs_bias_netlist, - [('VREF', 'VBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] + [('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] ) pmos_comps.info['netlist'].connect_netlist(mimcap_netlist, [('V2', 'VOUT')]) @@ -229,7 +229,7 @@ def opamp_twostage( two_stage_netlist = Netlist( circuit_name="OPAMP_TWO_STAGE", - nodes=['VDD', 'GND', 'VBIAS1', 'VP', 'VN', 'VBIAS2', 'VOUT'] + nodes=['VDD', 'GND', 'IBIAS1', 'VP', 'VN', 'IBIAS2', 'VOUT'] ) input_stage_netlist = opamp_top.info['netlist'] @@ -237,7 +237,7 @@ def opamp_twostage( two_stage_netlist.connect_netlist( input_stage_netlist, - [('VBIAS', 'VBIAS1'), ('VSS', 'GND'), ('B', 'GND')] + [('IBIAS', 'IBIAS1'), ('VSS', 'GND'), ('B', 'GND')] ) two_stage_netlist.connect_netlist( From 0b1b0c9667384acaa43f9db65b822d4918235faf Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 15:12:08 +0530 Subject: [PATCH 29/57] fix: fixed mimcap pin order --- .../generators/gdsfactory-gen/glayout/primitives/mimcap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 8d34bbcde..2f8538a73 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -58,7 +58,7 @@ def mimcap( nodes = ['V1', 'V2'], source_netlist=""" .subckt {circuit_name} {nodes} -C1 V1 V2 {model} l={length} w={width} +X1 V1 V2 {model} l={length} w={width} .ends {circuit_name} """, parameters={ @@ -122,7 +122,7 @@ def mimcap_array(pdk: MappedPDK, rows: int, columns: int, size: tuple[float,floa .ends {circuit_name} """, parameters={ - 'mimcap_arr_instances': '\n'.join([f"C{i+1} {pdk.models['mimcap']} V1 V2 w={size[0]} l={size[1]}" for i in range(rows * columns)]) + 'mimcap_arr_instances': '\n'.join([f"X{i+1} V1 V2 {pdk.models['mimcap']} w={size[0]} l={size[1]}" for i in range(rows * columns)]) } ) From f6a04d714bddf4fe2fc76476f4976f41ad547f1b Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 15:12:35 +0530 Subject: [PATCH 30/57] feat: renamed biases, used subcircuit instead of M and C, fixes --- .../components/diff_pair_cmirrorbias.py | 4 ++-- .../gdsfactory-gen/glayout/components/opamp.py | 18 ++++++------------ .../glayout/components/opamp_twostage.py | 10 +++++----- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 1d58fc806..3c7229940 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -151,8 +151,8 @@ def diff_pair_ibias( nodes=['VREF', 'VCOPY', 'VSS'], source_netlist=""" .subckt {circuit_name} {nodes} -M1 VREF VREF VSS VSS {model} l={length} w={width} m={mult} -M2 VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} +XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} +XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} .ends {circuit_name} """, parameters={ diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 3ce80947b..22449335b 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -114,8 +114,8 @@ def __add_output_stage( nodes=['VREF', 'VCOPY', 'VSS'], source_netlist=""" .subckt {circuit_name} {nodes} -M1 VREF VREF VSS VSS {model} l={length} w={width} m={mult} -M2 VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} +XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} +XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} .ends {circuit_name} """, parameters={ @@ -133,18 +133,12 @@ def __add_output_stage( output_stage_netlist.connect_netlist( amp_fet_ref.info['netlist'], - [('D', 'VDD'), ('G', 'VIN'), ('B', 'GND')] + [('D', 'VDD'), ('G', 'VIN'), ('B', 'GND'), ('S', 'VOUT')] ) output_stage_netlist.connect_netlist( bias_netlist, - [('VREF', 'IBIAS'), ('VSS', 'GND')] - ) - - output_stage_netlist.connect_subnets( - amp_fet_ref.info['netlist'], - bias_netlist, - [('S', 'VCOPY')] + [('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] ) return opamp_top, output_stage_netlist @@ -201,7 +195,7 @@ def opamp( top_level_netlist = Netlist( circuit_name="OPAMP", - nodes=['VDD', 'GND', 'VP', 'VN', 'VOUT_PRE', 'VOUT', 'IBIAS1', 'IBIAS2', 'IBIAS3'] + nodes=['VDD', 'GND', 'VP', 'VN', 'VOUT_PRE', 'VOUT', 'DIFFPAIR_BIAS', 'CS_BIAS', 'OUTPUT_STAGE_BIAS'] ) top_level_netlist.connect_netlist( @@ -211,7 +205,7 @@ def opamp( top_level_netlist.connect_netlist( output_stage_netlist, - [('IBIAS', 'IBIAS3'), ('VIN', 'VOUT_PRE')] + [('IBIAS', 'OUTPUT_STAGE_BIAS'), ('VIN', 'VOUT_PRE')] ) opamp_top.info['netlist'] = top_level_netlist diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index dc2c2d0e2..35c7d1383 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -176,8 +176,8 @@ def opamp_twostage( nodes=['VREF', 'VCOPY', 'VSS'], source_netlist=""" .subckt {circuit_name} {nodes} -M1 VREF VREF VSS VSS {model} l={length} w={width} m={mult} -M2 VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} +XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} +XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} .ends {circuit_name} """, parameters={ @@ -229,7 +229,7 @@ def opamp_twostage( two_stage_netlist = Netlist( circuit_name="OPAMP_TWO_STAGE", - nodes=['VDD', 'GND', 'IBIAS1', 'VP', 'VN', 'IBIAS2', 'VOUT'] + nodes=['VDD', 'GND', 'DIFFPAIR_BIAS', 'VP', 'VN', 'CS_BIAS', 'VOUT'] ) input_stage_netlist = opamp_top.info['netlist'] @@ -237,12 +237,12 @@ def opamp_twostage( two_stage_netlist.connect_netlist( input_stage_netlist, - [('IBIAS', 'IBIAS1'), ('VSS', 'GND'), ('B', 'GND')] + [('IBIAS', 'DIFFPAIR_BIAS'), ('VSS', 'GND'), ('B', 'GND')] ) two_stage_netlist.connect_netlist( gain_stage_netlist, - [('VSS', 'GND')] + [('VSS', 'GND'), ('IBIAS', 'CS_BIAS')] ) two_stage_netlist.connect_subnets( From 242bbccb71bb72e9b5080ab8564d2a740ee631c4 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 15:47:32 +0530 Subject: [PATCH 31/57] feat: better subcircuit naming, way to get unique subcircuits --- .../gdsfactory-gen/glayout/spice/netlist.py | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 96d438fb6..74f4bd20e 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -190,7 +190,7 @@ def __generate_self_subcircuit(self, prefix: str = '', suffix: str = '') -> str: main_circuit = f".subckt {generated_circuit_name} {' '.join(self.nodes)}\n" for i, netlist in enumerate(self.sub_netlists): - main_circuit += netlist.generate_instance(i, self.netlist_connections[i]) + "\n" + main_circuit += netlist.generate_instance(str(i), self.netlist_connections[i]) + "\n" main_circuit += f".ends {generated_circuit_name}" @@ -199,15 +199,30 @@ def __generate_self_subcircuit(self, prefix: str = '', suffix: str = '') -> str: else: return "" - def get_subcircuits_list(self, sub_netlists_only = False) -> set[str]: + def get_subcircuits_netlist_map(self, sub_netlists_only = False) -> dict[str, list['Netlist']]: """Generates a list of all the unique SPICE subcircuits directives used in the netlist.""" - subcircuits = set() + subcircuits = dict() + + # Get sub netlists' subcircuits + for netlist in self.sub_netlists: + subnetlist_subcircuits = netlist.get_subcircuits_netlist_map() + + # For each subnetlists' subcircuit + for subckt in subnetlist_subcircuits: + subckt_netlists = subnetlist_subcircuits[subckt] + + if subckt not in subcircuits: + # If it is unique, create an entry in the dict + subcircuits[subckt] = [*subckt_netlists] + else: + # If it is not unique, append the netlists to the dict + subcircuits[subckt] += subckt_netlists - for i, netlist in enumerate(self.sub_netlists): - netlist.circuit_name = f"{self.circuit_name}_{i}_{netlist.circuit_name}" - subcircuits.update(netlist.get_subcircuits_list()) - if not sub_netlists_only: subcircuits.add(self.__generate_self_subcircuit()) + if not sub_netlists_only: + self_subckt = self.__generate_self_subcircuit() + if self_subckt not in subcircuits: + subcircuits[self_subckt] = [self] return subcircuits @@ -230,7 +245,22 @@ def generate_netlist(self, only_subcircuits: bool = False): Parameters: - `only_subcircuits`: Only generates the subcircuit directives if set to `True`. (Default: `False`) """ - subcircuits = '\n'.join(self.get_subcircuits_list(sub_netlists_only=True)) + subcircuits_netlist_map = self.get_subcircuits_netlist_map(sub_netlists_only=True) + subcircuits_list = [] + subcircuit_suffixes = dict() + + for subckt in subcircuits_netlist_map: + for netlist in subcircuits_netlist_map[subckt]: + if netlist.circuit_name in subcircuit_suffixes: + subcircuit_suffixes[netlist.circuit_name] += 1 + + netlist.circuit_name = f"{netlist.circuit_name}_{subcircuit_suffixes[netlist.circuit_name]}" + else: + subcircuit_suffixes[netlist.circuit_name] = 0 + + subcircuits_list.append(subcircuits_netlist_map[subckt][0].__generate_self_subcircuit()) + + subcircuits = '\n'.join(subcircuits_list) main_circuit = self.__generate_self_subcircuit() global_nodes = ' '.join(self.get_global_nodes_list()) From 4a03e86a3cbe7d1e61a76ed00a3d1f14f6dc39a9 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 15:48:16 +0530 Subject: [PATCH 32/57] fix: removed excess spaces --- .../glayout/components/diff_pair_cmirrorbias.py | 6 ++---- .../differential_to_single_ended_converter.py | 6 ++---- .../gdsfactory-gen/glayout/components/opamp.py | 6 ++---- .../glayout/components/opamp_twostage.py | 6 ++---- .../gdsfactory-gen/glayout/primitives/mimcap.py | 12 ++++-------- 5 files changed, 12 insertions(+), 24 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 3c7229940..4efbd2a9e 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -149,12 +149,10 @@ def diff_pair_ibias( cmirror.info['netlist'] = Netlist( circuit_name='CURRENT_MIRROR', nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""" -.subckt {circuit_name} {nodes} + source_netlist=""".subckt {circuit_name} {nodes} XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} -.ends {circuit_name} - """, +.ends {circuit_name}""", parameters={ 'model': pdk.models['nfet'], 'width': diffpair_bias[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 18b89f352..1f7eb1f39 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -157,14 +157,12 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa diff_to_single_netlist = Netlist( circuit_name="DIFF_TO_SINGLE", nodes=['VIN', 'VOUT', 'VSS', 'VSS2'], - source_netlist=""" -.subckt {circuit_name} {nodes} + source_netlist=""".subckt {circuit_name} {nodes} X1 V1 VIN VSS VSS {model} l={length} w={width} m={mult_top} X2 VSS2 VIN VSS VSS {model} l={length} w={width} m={mult_top} X3 VIN VIN V1 VSS {model} l={length} w={width} m={mult_bot} X4 VOUT VIN VSS2 VSS {model} l={length} w={width} m={mult_bot} -.ends {circuit_name} - """, +.ends {circuit_name}""", parameters={ 'model': pdk.models['pfet'], 'width': half_pload[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 22449335b..449c265f3 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -112,12 +112,10 @@ def __add_output_stage( bias_netlist = Netlist( circuit_name='CURRENT_MIRROR', nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""" -.subckt {circuit_name} {nodes} + source_netlist=""".subckt {circuit_name} {nodes} XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} -.ends {circuit_name} - """, +.ends {circuit_name}""", parameters={ 'model': pdk.models['nfet'], 'width': biasParams[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index 35c7d1383..1db75265c 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -174,12 +174,10 @@ def opamp_twostage( cs_bias_netlist = Netlist( circuit_name='CURRENT_MIRROR', nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""" -.subckt {circuit_name} {nodes} + source_netlist=""".subckt {circuit_name} {nodes} XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} -.ends {circuit_name} - """, +.ends {circuit_name}""", parameters={ 'model': pdk.models['nfet'], 'width': diffpair_bias[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 2f8538a73..8dd6c642a 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -56,11 +56,9 @@ def mimcap( component.info['netlist'] = Netlist( circuit_name="MIMCap", nodes = ['V1', 'V2'], - source_netlist=""" -.subckt {circuit_name} {nodes} + source_netlist=""".subckt {circuit_name} {nodes} X1 V1 V2 {model} l={length} w={width} -.ends {circuit_name} - """, +.ends {circuit_name}""", parameters={ 'model': pdk.models['mimcap'], 'length': size[0], @@ -116,11 +114,9 @@ def mimcap_array(pdk: MappedPDK, rows: int, columns: int, size: tuple[float,floa mimcap_arr.info['netlist'] = Netlist( circuit_name="MIMCAP_ARR", nodes = ['V1', 'V2'], - source_netlist=""" -.subckt {circuit_name} {nodes} + source_netlist=""".subckt {circuit_name} {nodes} {mimcap_arr_instances} -.ends {circuit_name} - """, +.ends {circuit_name}""", parameters={ 'mimcap_arr_instances': '\n'.join([f"X{i+1} V1 V2 {pdk.models['mimcap']} w={size[0]} l={size[1]}" for i in range(rows * columns)]) } From e921267baf28b72107e13806db026661e0f67c90 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 15:48:43 +0530 Subject: [PATCH 33/57] feat: added spaces in generate_netlist() --- openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 74f4bd20e..4299fe9ea 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -260,7 +260,7 @@ def generate_netlist(self, only_subcircuits: bool = False): subcircuits_list.append(subcircuits_netlist_map[subckt][0].__generate_self_subcircuit()) - subcircuits = '\n'.join(subcircuits_list) + subcircuits = '\n\n'.join(subcircuits_list) main_circuit = self.__generate_self_subcircuit() global_nodes = ' '.join(self.get_global_nodes_list()) From 58ca69a949684e7e83d67fb28fab6557004204cb Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 15:52:22 +0530 Subject: [PATCH 34/57] feat: better dummy generation, use fet subcircuit --- .../gdsfactory-gen/glayout/primitives/fet.py | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index fdcc1319d..caa13e293 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -427,20 +427,19 @@ def nmos( component = rename_ports_by_orientation(nfet).flatten() # add spice netlist - if with_dummy == False: - dummy_tuple = (False, False) - elif with_dummy == True: - dummy_tuple = (True, True) - else: - dummy_tuple = with_dummy + num_dummies = 0 + if with_dummy == False or with_dummy == (False, False): + num_dummies = 0 + elif with_dummy == (True, False) or with_dummy == (False, True): + num_dummies = 1 + elif with_dummy == True or with_dummy == (True, True): + num_dummies = 2 nmos_netlist=""".subckt {circuit_name} {nodes} -M1 D G S B {model} l={length} w={width} m={mult}""" +XMAIN D G S B {model} l={length} w={width} m={mult}""" - if dummy_tuple[0]: - nmos_netlist += "\nM2 B B B B {model} l={length} w={width} m={dummy_mult}" - if dummy_tuple[1]: - nmos_netlist += "\nM3 B B B B {model} l={length} w={width} m={dummy_mult}" + for i in range(num_dummies): + nmos_netlist += "\nXDUMMY" + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" nmos_netlist += "\n.ends {circuit_name}" @@ -585,20 +584,19 @@ def pmos( component = rename_ports_by_orientation(pfet).flatten() # add spice netlist - if with_dummy == False: - dummy_tuple = (False, False) - elif with_dummy == True: - dummy_tuple = (True, True) - else: - dummy_tuple = with_dummy + num_dummies = 0 + if with_dummy == False or with_dummy == (False, False): + num_dummies = 0 + elif with_dummy == (True, False) or with_dummy == (False, True): + num_dummies = 1 + elif with_dummy == True or with_dummy == (True, True): + num_dummies = 2 pmos_netlist=""".subckt {circuit_name} {nodes} -M1 D G S B {model} l={length} w={width} m={mult}""" +XMAIN D G S B {model} l={length} w={width} m={mult}""" - if dummy_tuple[0]: - pmos_netlist += "\nM2 B B B B {model} l={length} w={width} m={dummy_mult}" - if dummy_tuple[1]: - pmos_netlist += "\nM3 B B B B {model} l={length} w={width} m={dummy_mult}" + for i in range(num_dummies): + pmos_netlist += "\nXDUMMY" + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" pmos_netlist += "\n.ends {circuit_name}" From 2b1398b66ca204cd84512cea6c5aef9bec540e6b Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 16:14:20 +0530 Subject: [PATCH 35/57] feat: new and improved unique circuits generation --- .../gdsfactory-gen/glayout/spice/netlist.py | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 4299fe9ea..d0470f72d 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -245,22 +245,36 @@ def generate_netlist(self, only_subcircuits: bool = False): Parameters: - `only_subcircuits`: Only generates the subcircuit directives if set to `True`. (Default: `False`) """ + + # GENERATE UNIQUE SUBCIRCUIT DiRECTIVES subcircuits_netlist_map = self.get_subcircuits_netlist_map(sub_netlists_only=True) - subcircuits_list = [] - subcircuit_suffixes = dict() + subcircuit_suffixes = dict() + # Get the unique netlists' list and set their suffixes for subckt in subcircuits_netlist_map: - for netlist in subcircuits_netlist_map[subckt]: - if netlist.circuit_name in subcircuit_suffixes: - subcircuit_suffixes[netlist.circuit_name] += 1 - - netlist.circuit_name = f"{netlist.circuit_name}_{subcircuit_suffixes[netlist.circuit_name]}" - else: - subcircuit_suffixes[netlist.circuit_name] = 0 - - subcircuits_list.append(subcircuits_netlist_map[subckt][0].__generate_self_subcircuit()) + netlists = subcircuits_netlist_map[subckt] + # All of these subcircuits will have the same name, so use any one + subckt_name = netlists[0].circuit_name + + if subckt_name in subcircuit_suffixes: + # If a suffix exists, use it and increment it + for netlist in netlists: netlist.circuit_name = f"{netlist.circuit_name}_{subcircuit_suffixes[subckt_name]}" + subcircuit_suffixes[subckt_name] += 1 + else: + # If a suffix doesn't exist, create it. + subcircuit_suffixes[subckt_name] = 1 - subcircuits = '\n\n'.join(subcircuits_list) + unique_subcircuits_list = [] + # Generate all the unique subcircuits (generation is done again since suffixes were updated) + for subckt in subcircuits_netlist_map: + unique_subcircuits_list.append( + # Use any one since all will be equal + subcircuits_netlist_map[subckt][0].__generate_self_subcircuit() + ) + # /GENERATE UNIQUE SUBCIRCUIT DiRECTIVES + + # GENERATE THE FINAL NETLIST + subcircuits = '\n\n'.join(unique_subcircuits_list) main_circuit = self.__generate_self_subcircuit() global_nodes = ' '.join(self.get_global_nodes_list()) @@ -270,5 +284,6 @@ def generate_netlist(self, only_subcircuits: bool = False): self.spice_netlist += subcircuits + "\n" self.spice_netlist += main_circuit + # /GENERATE THE FINAL NETLIST return self.spice_netlist From 4a4ffbda65754d763225374f79e6e9fc9a7ea9c6 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 20:26:44 +0530 Subject: [PATCH 36/57] fix: added space after XDUMMY --- openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index caa13e293..57666b1d7 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -439,7 +439,7 @@ def nmos( XMAIN D G S B {model} l={length} w={width} m={mult}""" for i in range(num_dummies): - nmos_netlist += "\nXDUMMY" + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" + nmos_netlist += "\n " + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" nmos_netlist += "\n.ends {circuit_name}" @@ -596,7 +596,7 @@ def pmos( XMAIN D G S B {model} l={length} w={width} m={mult}""" for i in range(num_dummies): - pmos_netlist += "\nXDUMMY" + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" + pmos_netlist += "\nXDUMMY " + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" pmos_netlist += "\n.ends {circuit_name}" From f76585b4af2053dbaad7e9c225a8c5bc6d42692f Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 20:36:13 +0530 Subject: [PATCH 37/57] feat: added instance format --- .../gdsfactory-gen/glayout/spice/netlist.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index d0470f72d..2889461cf 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -18,6 +18,8 @@ class Netlist: source_netlist: str = "" """The source SPICE subcircuit (template) for the subcircuit. [Mako](https://makotemplates.org) templating syntax is supported.""" + instance_format: str = "X{name} {nodes} {circuit_name}" + """The format for the SPICE instantiation. Uses the Python string formatting syntax. `self.parameters`, `nodes`, `name`, and `circuit_name` are available parameters.""" spice_netlist: str = "" """The generated SPICE netlist.""" @@ -66,17 +68,26 @@ def extract_subckt_name(self, netlist: str) -> str: return 'Netlist' - def generate_instance(self, name: Optional[str] = None, nodes: Optional[list[str]] = None) -> str: + def generate_instance(self, name: Optional[str] = None, nodes: Optional[list[str]] = None, instance_format: Optional[str] = None) -> str: """Generates an instance of the netlist subcircuit. Override to insert parameters in the instance. """ if name == None: name = self.circuit_name + if instance_format == None: + instance_format = self.instance_format + if nodes == None: nodes = self.nodes - return f"X{name} {' '.join(nodes)} {self.circuit_name}" + params = { + **self.generate_source_netlist_params(), + 'nodes': ' '.join(nodes), + 'name': name + } + + return instance_format.format(**params) def read_source_netlist(self, netlist_src: str) -> str: """Reads a source SPICE subcircuit template from a SPICE file. [Mako](https://makotemplates.org) templating syntax is supported in the source SPICE netlist.""" From 17c5794be0962eef61b1b44764f9f5f9cea381ae Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 20:54:13 +0530 Subject: [PATCH 38/57] feat: used instantiation formatting instead of source netlist formatting for parameters --- .../glayout/components/diff_pair_cmirrorbias.py | 7 ++++--- .../differential_to_single_ended_converter.py | 11 ++++++----- .../gdsfactory-gen/glayout/components/opamp.py | 7 ++++--- .../glayout/components/opamp_twostage.py | 7 ++++--- .../gdsfactory-gen/glayout/primitives/fet.py | 14 ++++++++------ .../gdsfactory-gen/glayout/spice/netlist.py | 5 ++++- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 4efbd2a9e..501b627d8 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -149,10 +149,11 @@ def diff_pair_ibias( cmirror.info['netlist'] = Netlist( circuit_name='CURRENT_MIRROR', nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""".subckt {circuit_name} {nodes} -XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} -XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 +XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} +XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} .ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", parameters={ 'model': pdk.models['nfet'], 'width': diffpair_bias[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 1f7eb1f39..8dee43d22 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -157,12 +157,13 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa diff_to_single_netlist = Netlist( circuit_name="DIFF_TO_SINGLE", nodes=['VIN', 'VOUT', 'VSS', 'VSS2'], - source_netlist=""".subckt {circuit_name} {nodes} -X1 V1 VIN VSS VSS {model} l={length} w={width} m={mult_top} -X2 VSS2 VIN VSS VSS {model} l={length} w={width} m={mult_top} -X3 VIN VIN V1 VSS {model} l={length} w={width} m={mult_bot} -X4 VOUT VIN VSS2 VSS {model} l={length} w={width} m={mult_bot} + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 mt=1 mb=1 +X1 V1 VIN VSS VSS {model} l={{l}} w={{w}} m={{w}} +X2 VSS2 VIN VSS VSS {model} l={{l}} w={{w}} m={{mt}} +X3 VIN VIN V1 VSS {model} l={{l}} w={{w}} m={{mb}} +X4 VOUT VIN VSS2 VSS {model} l={{l}} w={{w}} m={{mb}} .ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} mt={mult_top} mb={mult_bot}", parameters={ 'model': pdk.models['pfet'], 'width': half_pload[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 449c265f3..041d51d2e 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -112,10 +112,11 @@ def __add_output_stage( bias_netlist = Netlist( circuit_name='CURRENT_MIRROR', nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""".subckt {circuit_name} {nodes} -XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} -XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 +XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} +XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} .ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", parameters={ 'model': pdk.models['nfet'], 'width': biasParams[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index 1db75265c..cbe6f7e40 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -174,10 +174,11 @@ def opamp_twostage( cs_bias_netlist = Netlist( circuit_name='CURRENT_MIRROR', nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""".subckt {circuit_name} {nodes} -XREF VREF VREF VSS VSS {model} l={length} w={width} m={mult} -XCOPY VCOPY VREF VSS VSS {model} l={length} w={width} m={mult} + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 +XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} +XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} .ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", parameters={ 'model': pdk.models['nfet'], 'width': diffpair_bias[0], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index 57666b1d7..bc82c6f3d 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -435,11 +435,11 @@ def nmos( elif with_dummy == True or with_dummy == (True, True): num_dummies = 2 - nmos_netlist=""".subckt {circuit_name} {nodes} -XMAIN D G S B {model} l={length} w={width} m={mult}""" + nmos_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 dm=1 +XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" for i in range(num_dummies): - nmos_netlist += "\n " + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" + nmos_netlist += "\nXDUMMY" + str(i+1) + " B B B B {model} l={{l}} w={{w}} m={{dm}}" nmos_netlist += "\n.ends {circuit_name}" @@ -447,6 +447,7 @@ def nmos( circuit_name="NMOS", nodes=['D', 'G', 'S', 'B'], source_netlist=nmos_netlist, + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult} dm={dummy_mult}", parameters={ 'model': pdk.models['nfet'], 'length': length, @@ -592,11 +593,11 @@ def pmos( elif with_dummy == True or with_dummy == (True, True): num_dummies = 2 - pmos_netlist=""".subckt {circuit_name} {nodes} -XMAIN D G S B {model} l={length} w={width} m={mult}""" + pmos_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 dm=1 +XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" for i in range(num_dummies): - pmos_netlist += "\nXDUMMY " + str(i+1) + "B B B B {model} l={length} w={width} m={dummy_mult}" + pmos_netlist += "\nXDUMMY" + str(i+1) + " B B B B {model} l={{l}} w={{w}} m={{dm}}" pmos_netlist += "\n.ends {circuit_name}" @@ -604,6 +605,7 @@ def pmos( circuit_name="PMOS", nodes=['D', 'G', 'S', 'B'], source_netlist=pmos_netlist, + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult} dm={dummy_mult}", parameters={ 'model': pdk.models['pfet'], 'length': length, diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 2889461cf..1beb600e2 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -41,7 +41,7 @@ class Netlist: parameters: dict = {} """Dictionary of the high-level parameters.""" - def __init__(self, source_netlist: str = '', nodes: list[str] = [], circuit_name: Union[str, None] = None, parameters: dict = {}, sub_netlists: list['Netlist'] = []): + def __init__(self, source_netlist: str = '', nodes: list[str] = [], circuit_name: Union[str, None] = None, instance_format: Optional[str] = None, parameters: dict = {}, sub_netlists: list['Netlist'] = []): """Initializes a Netlist object. Override to load sub-netlists and parameters on initialization. @@ -58,6 +58,9 @@ def __init__(self, source_netlist: str = '', nodes: list[str] = [], circuit_name else: self.circuit_name = self.extract_subckt_name(self.source_netlist) + if instance_format != None: + self.instance_format = instance_format + self.add_netlists(sub_netlists) def extract_subckt_name(self, netlist: str) -> str: From ee57999daf52f80d521c3488af41466a055f2a68 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 20:56:14 +0530 Subject: [PATCH 39/57] feat: added two newlines everywhere in the netlist --- openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 1beb600e2..85b0bba08 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -294,9 +294,9 @@ def generate_netlist(self, only_subcircuits: bool = False): self.spice_netlist = "" - if len(global_nodes) > 0 and not only_subcircuits: self.spice_netlist += f".global {global_nodes}\n" + if len(global_nodes) > 0 and not only_subcircuits: self.spice_netlist += f".global {global_nodes}\n\n" - self.spice_netlist += subcircuits + "\n" + self.spice_netlist += subcircuits + "\n\n" self.spice_netlist += main_circuit # /GENERATE THE FINAL NETLIST From 666120c0f3605cdfcb7ffc85fb9734e5e19196b7 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Fri, 17 Nov 2023 21:04:05 +0530 Subject: [PATCH 40/57] feat: improved netlist human readability --- .../components/differential_to_single_ended_converter.py | 8 ++++---- .../generators/gdsfactory-gen/glayout/primitives/fet.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 8dee43d22..f728dc2d8 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -158,10 +158,10 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa circuit_name="DIFF_TO_SINGLE", nodes=['VIN', 'VOUT', 'VSS', 'VSS2'], source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 mt=1 mb=1 -X1 V1 VIN VSS VSS {model} l={{l}} w={{w}} m={{w}} -X2 VSS2 VIN VSS VSS {model} l={{l}} w={{w}} m={{mt}} -X3 VIN VIN V1 VSS {model} l={{l}} w={{w}} m={{mb}} -X4 VOUT VIN VSS2 VSS {model} l={{l}} w={{w}} m={{mb}} +XTOP1 V1 VIN VSS VSS {model} l={{l}} w={{w}} m={{mt}} +XTOP2 VSS2 VIN VSS VSS {model} l={{l}} w={{w}} m={{mt}} +XBOT1 VIN VIN V1 VSS {model} l={{l}} w={{w}} m={{mb}} +XBOT2 VOUT VIN VSS2 VSS {model} l={{l}} w={{w}} m={{mb}} .ends {circuit_name}""", instance_format="X{name} {nodes} {circuit_name} l={length} w={width} mt={mult_top} mb={mult_bot}", parameters={ diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index bc82c6f3d..5887a9a20 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -436,7 +436,7 @@ def nmos( num_dummies = 2 nmos_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 dm=1 -XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" +XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" for i in range(num_dummies): nmos_netlist += "\nXDUMMY" + str(i+1) + " B B B B {model} l={{l}} w={{w}} m={{dm}}" @@ -594,7 +594,7 @@ def pmos( num_dummies = 2 pmos_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 dm=1 -XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" +XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" for i in range(num_dummies): pmos_netlist += "\nXDUMMY" + str(i+1) + " B B B B {model} l={{l}} w={{w}} m={{dm}}" From 79b54fc7d95f422c3fc7d88ac3c72b389c3a6a8f Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 03:46:33 +0530 Subject: [PATCH 41/57] fix: multiple netlist fixes --- .../gdsfactory-gen/glayout/components/opamp_twostage.py | 9 +++++---- .../row_csamplifier_diff_to_single_ended_converter.py | 6 +----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index cbe6f7e40..4cc1da3bc 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -204,14 +204,15 @@ def opamp_twostage( opamp_top.add_ports(_cref.get_ports_list(), prefix="gnd_route_") diff_cs_netlist = pmos_comps.info['netlist'] + pmos_comps.info['netlist'] = Netlist( circuit_name="GAIN_STAGE", - nodes=['VIN', 'VOUT', 'VSS', 'IBIAS', 'GND'] + nodes=['VIN1', 'VIN2', 'VOUT', 'VDD', 'IBIAS', 'GND'] ) pmos_comps.info['netlist'].connect_netlist( diff_cs_netlist, - [] + [('VSS', 'VDD')] ) pmos_comps.info['netlist'].connect_netlist( @@ -241,13 +242,13 @@ def opamp_twostage( two_stage_netlist.connect_netlist( gain_stage_netlist, - [('VSS', 'GND'), ('IBIAS', 'CS_BIAS')] + [('IBIAS', 'CS_BIAS')] ) two_stage_netlist.connect_subnets( input_stage_netlist, gain_stage_netlist, - [('VDD1', 'VIN'), ('VDD2', 'VOUT')] + [('VDD1', 'VIN1'), ('VDD2', 'VIN2')] ) opamp_top.info['netlist'] = two_stage_netlist diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py index c3dc7ec43..2d5f51a11 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py @@ -59,11 +59,7 @@ def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_singl pmos_comps.info['netlist'].connect_netlist( halfMultp.info['netlist'], - [('D', 'VOUT'), ('S', 'VSS'), ('B', 'VSS')] - ) - - pmos_comps.info['netlist'].connect_subnets( - 0, halfMultp.info['netlist'], [('VOUT', 'G')] + [('D', 'VOUT'), ('S', 'VSS'), ('B', 'VSS'), ('G', 'VIN2')] ) # add npadding and add ports From cc4b5c7ec1ab75f270043bcd30eeaed005361f60 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 04:43:43 +0530 Subject: [PATCH 42/57] fix: added antenna diodes to diff pair --- .../glayout/components/diff_pair_cmirrorbias.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 501b627d8..d691ed5f9 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -1,3 +1,4 @@ +from copy import deepcopy from gdsfactory.cell import cell, clear_cache from gdsfactory.component import Component, copy from gdsfactory.component_reference import ComponentReference @@ -198,6 +199,15 @@ def diff_pair_ibias( [('VCOPY', 'VTAIL')] ) + diffpair_i_.info['netlist'].connect_netlist( + antenna_diode_comp.info['netlist'], + [('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VP')] + ) + diffpair_i_.info['netlist'].connect_netlist( + deepcopy(antenna_diode_comp.info['netlist']), + [('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VN')] + ) + diffpair_i_ref = prec_ref_center(diffpair_i_) return diffpair_i_ref From c83dc445a20c4913fa5de90a63d2874425b570b3 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 04:55:24 +0530 Subject: [PATCH 43/57] feat: renamed top-level opamp netlist to match --- .../generators/gdsfactory-gen/glayout/components/opamp.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 041d51d2e..6278a6b40 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -193,18 +193,18 @@ def opamp( two_stage_netlist = opamp_top.info['netlist'] top_level_netlist = Netlist( - circuit_name="OPAMP", - nodes=['VDD', 'GND', 'VP', 'VN', 'VOUT_PRE', 'VOUT', 'DIFFPAIR_BIAS', 'CS_BIAS', 'OUTPUT_STAGE_BIAS'] + circuit_name="opamp", + nodes=['gnd', 'CSoutput', 'output', 'vdd', 'plus', 'minus', 'commonsourceibias', 'outputibias', 'diffpairibias'] ) top_level_netlist.connect_netlist( two_stage_netlist, - [('VOUT', 'VOUT_PRE')] + [('VDD', 'vdd'), ('GND', 'gnd'), ('DIFFPAIR_BIAS', 'diffpairibias'), ('VP', 'plus'), ('VN', 'minus'), ('CS_BIAS', 'commonsourceibias'), ('VOUT', 'CSoutput')] ) top_level_netlist.connect_netlist( output_stage_netlist, - [('IBIAS', 'OUTPUT_STAGE_BIAS'), ('VIN', 'VOUT_PRE')] + [('VDD', 'vdd'), ('GND', 'gnd'), ('IBIAS', 'outputibias'), ('VIN', 'CSoutput'), ('VOUT', 'output')] ) opamp_top.info['netlist'] = top_level_netlist From 6a750b482851d8d00dc48379a8deaa7e95bd9612 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 05:05:07 +0530 Subject: [PATCH 44/57] refactor: added __init__, imported Netlist in it --- .../generators/gdsfactory-gen/glayout/components/diff_pair.py | 2 +- .../gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py | 2 +- .../components/differential_to_single_ended_converter.py | 2 +- openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py | 2 +- .../gdsfactory-gen/glayout/components/opamp_twostage.py | 2 +- .../row_csamplifier_diff_to_single_ended_converter.py | 2 +- openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py | 2 +- .../generators/gdsfactory-gen/glayout/primitives/mimcap.py | 2 +- openfasoc/generators/gdsfactory-gen/glayout/spice/__init__.py | 1 + 9 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 openfasoc/generators/gdsfactory-gen/glayout/spice/__init__.py diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py index 93b8cf357..61285d75a 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py @@ -13,7 +13,7 @@ from glayout.primitives.via_gen import via_stack from glayout.primitives.guardring import tapring from glayout.pdk.util.snap_to_grid import component_snap_to_grid -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist @cell def diff_pair( diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index d691ed5f9..5f6e34222 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -36,7 +36,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist @validate_arguments def diff_pair_ibias( diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index f728dc2d8..424a7336f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -18,7 +18,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 6278a6b40..b89c2c46f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -18,7 +18,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist from glayout.components.opamp_twostage import opamp_twostage diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index 4cc1da3bc..fd96d61e9 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -24,7 +24,7 @@ from glayout.components.differential_to_single_ended_converter import differential_to_single_ended_converter from glayout.components.row_csamplifier_diff_to_single_ended_converter import row_csamplifier_diff_to_single_ended_converter from glayout.components.diff_pair_stackedcmirror import diff_pair_stackedcmirror -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist @validate_arguments diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py index 2d5f51a11..d9d7ac465 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py @@ -18,7 +18,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_single_ended_converter: Component, pamp_hparams, rmult) -> Component: diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index 5887a9a20..97a0e42af 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -14,7 +14,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from decimal import Decimal from glayout.routing.straight_route import straight_route -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist @validate_arguments diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 8dd6c642a..0646b8c6f 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -9,7 +9,7 @@ from pydantic import validate_arguments from glayout.routing.straight_route import straight_route from decimal import ROUND_UP, Decimal -from glayout.spice.netlist import Netlist +from glayout.spice import Netlist @validate_arguments def __get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/__init__.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/__init__.py new file mode 100644 index 000000000..e4e4f11bc --- /dev/null +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/__init__.py @@ -0,0 +1 @@ +from .netlist import Netlist \ No newline at end of file From ef8c2663ebe8a8eee2c1297a41e5589e02d8e0e1 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 06:22:28 +0530 Subject: [PATCH 45/57] fix: removed stray comments --- .../gdsfactory-gen/glayout/primitives/fet.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index 97a0e42af..d8e82bbd6 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -213,13 +213,13 @@ def __mult_array_macro( width: Optional[float] = 3, fingers: Optional[int] = 1, multipliers: Optional[int] = 1, - routing: Optional[bool] = True, # + routing: Optional[bool] = True, dummy: Optional[Union[bool, tuple[bool, bool]]] = True, length: Optional[float] = None, - sd_route_topmet: Optional[str] = "met2", # - gate_route_topmet: Optional[str] = "met2", # - sd_route_left: Optional[bool] = True, # - sd_rmult: int = 1, # + sd_route_topmet: Optional[str] = "met2", + gate_route_topmet: Optional[str] = "met2", + sd_route_left: Optional[bool] = True, + sd_rmult: int = 1, gate_rmult: int=1, interfinger_rmult: int=1, dummy_routes: bool=True From 027c77dd0cc26a98ebbffba4981e4e51c1a978dc Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 06:23:17 +0530 Subject: [PATCH 46/57] refactor: converted spicemodels to a simple dict --- .../generators/gdsfactory-gen/glayout/pdk/mappedpdk.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py index 70cbc8813..b09bef1d8 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/pdk/mappedpdk.py @@ -14,11 +14,6 @@ from pydantic import validate_arguments import xml.etree.ElementTree as ET -class SpiceModels(TypedDict): - nfet: str - pfet: str - mimcap: str - class MappedPDK(Pdk): """Inherits everything from the pdk class but also requires mapping to glayers glayers are generic layers which can be returned with get_glayer(name: str) @@ -47,7 +42,7 @@ class MappedPDK(Pdk): "capmet", ) - models: SpiceModels = { + models: dict = { "nfet": "", "pfet": "", "mimcap": "" From 57038d2eb36bcf260e41752b0f3804bb41e9e4b2 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 06:40:25 +0530 Subject: [PATCH 47/57] refactor: created separate function for fet spice generation --- .../gdsfactory-gen/glayout/primitives/fet.py | 109 +++++++++--------- 1 file changed, 53 insertions(+), 56 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index d8e82bbd6..dbfbc11c9 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -62,6 +62,45 @@ def __gen_fingers_macro(pdk: MappedPDK, rmult: int, fingers: int, length: float, multiplier.add_ports(diff.get_ports_list(),prefix="diff_") return component_snap_to_grid(rename_ports_by_orientation(multiplier)) +def __generate_fet_netlist( + circuit_name: str, + model: str, + width: float, + length: float, + fingers: int, + multipliers: int, + with_dummy: Union[bool, tuple[bool, bool]] +) -> Netlist: + # add spice netlist + num_dummies = 0 + if with_dummy == False or with_dummy == (False, False): + num_dummies = 0 + elif with_dummy == (True, False) or with_dummy == (False, True): + num_dummies = 1 + elif with_dummy == True or with_dummy == (True, True): + num_dummies = 2 + + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 dm=1 +XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" + + for i in range(num_dummies): + source_netlist += "\nXDUMMY" + str(i+1) + " B B B B {model} l={{l}} w={{w}} m={{dm}}" + + source_netlist += "\n.ends {circuit_name}" + + return Netlist( + circuit_name=circuit_name, + nodes=['D', 'G', 'S', 'B'], + source_netlist=source_netlist, + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult} dm={dummy_mult}", + parameters={ + 'model': model, + 'length': length, + 'width': width, + 'mult': fingers * multipliers, + 'dummy_mult': multipliers + } + ) @cell def multiplier( @@ -426,35 +465,14 @@ def nmos( component = rename_ports_by_orientation(nfet).flatten() - # add spice netlist - num_dummies = 0 - if with_dummy == False or with_dummy == (False, False): - num_dummies = 0 - elif with_dummy == (True, False) or with_dummy == (False, True): - num_dummies = 1 - elif with_dummy == True or with_dummy == (True, True): - num_dummies = 2 - - nmos_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 dm=1 -XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" - - for i in range(num_dummies): - nmos_netlist += "\nXDUMMY" + str(i+1) + " B B B B {model} l={{l}} w={{w}} m={{dm}}" - - nmos_netlist += "\n.ends {circuit_name}" - - component.info['netlist'] = Netlist( + component.info['netlist'] = __generate_fet_netlist( circuit_name="NMOS", - nodes=['D', 'G', 'S', 'B'], - source_netlist=nmos_netlist, - instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult} dm={dummy_mult}", - parameters={ - 'model': pdk.models['nfet'], - 'length': length, - 'width': width, - 'mult': fingers * multipliers, - 'dummy_mult': multipliers - } + model=pdk.models['nfet'], + width=width, + length=length, + fingers=fingers, + multipliers=multipliers, + with_dummy=with_dummy ) return component @@ -584,35 +602,14 @@ def pmos( ) component = rename_ports_by_orientation(pfet).flatten() - # add spice netlist - num_dummies = 0 - if with_dummy == False or with_dummy == (False, False): - num_dummies = 0 - elif with_dummy == (True, False) or with_dummy == (False, True): - num_dummies = 1 - elif with_dummy == True or with_dummy == (True, True): - num_dummies = 2 - - pmos_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 dm=1 -XMAIN D G S B {model} l={{l}} w={{w}} m={{m}}""" - - for i in range(num_dummies): - pmos_netlist += "\nXDUMMY" + str(i+1) + " B B B B {model} l={{l}} w={{w}} m={{dm}}" - - pmos_netlist += "\n.ends {circuit_name}" - - component.info['netlist'] = Netlist( + component.info['netlist'] = __generate_fet_netlist( circuit_name="PMOS", - nodes=['D', 'G', 'S', 'B'], - source_netlist=pmos_netlist, - instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult} dm={dummy_mult}", - parameters={ - 'model': pdk.models['pfet'], - 'length': length, - 'width': width, - 'mult': fingers * multipliers, - 'dummy_mult': multipliers - } + model=pdk.models['pfet'], + width=width, + length=length, + fingers=fingers, + multipliers=multipliers, + with_dummy=with_dummy ) return component From 14e0f5306044a5daeea5e7ebdb1c5b565b01d9fd Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 06:42:33 +0530 Subject: [PATCH 48/57] refactor: created separate function, better way to create mimcap array --- .../glayout/primitives/mimcap.py | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 0646b8c6f..2fcf92763 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -10,6 +10,7 @@ from glayout.routing.straight_route import straight_route from decimal import ROUND_UP, Decimal from glayout.spice import Netlist +from copy import deepcopy @validate_arguments def __get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: @@ -22,6 +23,35 @@ def __get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: pdk.activate() return capmettop, capmetbottom +def __generate_mimcap_netlist(pdk: MappedPDK, size: tuple[float, float]) -> Netlist: + return Netlist( + circuit_name="MIMCap", + nodes = ['V1', 'V2'], + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 +X1 V1 V2 {model} l={{l}} w={{w}} +.ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} w={width}", + parameters={ + 'model': pdk.models['mimcap'], + 'length': size[0], + 'width': size[1] + } + ) + +def __generate_mimcap_array_netlist(mimcap_netlist: Netlist, num_caps: int) -> Netlist: + arr_netlist = Netlist( + circuit_name="MIMCAP_ARR", + nodes = ['V1', 'V2'] + ) + + for _ in range(num_caps): + arr_netlist.connect_netlist( + deepcopy(mimcap_netlist), + [] + ) + + return arr_netlist + @cell def mimcap( pdk: MappedPDK, size: tuple[float,float]=(5.0, 5.0) @@ -53,18 +83,7 @@ def mimcap( component = rename_ports_by_orientation(mim_cap).flatten() # netlist generation - component.info['netlist'] = Netlist( - circuit_name="MIMCap", - nodes = ['V1', 'V2'], - source_netlist=""".subckt {circuit_name} {nodes} -X1 V1 V2 {model} l={length} w={width} -.ends {circuit_name}""", - parameters={ - 'model': pdk.models['mimcap'], - 'length': size[0], - 'width': size[1] - } - ) + component.info['netlist'] = __generate_mimcap_netlist(pdk, size) return component @@ -111,16 +130,7 @@ def mimcap_array(pdk: MappedPDK, rows: int, columns: int, size: tuple[float,floa mimcap_arr << straight_route(pdk,port_pair[0],port_pair[1],width=rmult*pdk.get_grule(port_pair[2])["min_width"]) # add netlist - mimcap_arr.info['netlist'] = Netlist( - circuit_name="MIMCAP_ARR", - nodes = ['V1', 'V2'], - source_netlist=""".subckt {circuit_name} {nodes} -{mimcap_arr_instances} -.ends {circuit_name}""", - parameters={ - 'mimcap_arr_instances': '\n'.join([f"X{i+1} V1 V2 {pdk.models['mimcap']} w={size[0]} l={size[1]}" for i in range(rows * columns)]) - } - ) + mimcap_arr.info['netlist'] = __generate_mimcap_array_netlist(mimcap_single.info['netlist'], rows * columns) return mimcap_arr.flatten() From 350e418b46882666d3b0ef4bb50455e6a0745b8f Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 06:53:53 +0530 Subject: [PATCH 49/57] refactor: created separate function for diff pair netlist --- .../glayout/components/diff_pair.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py index 61285d75a..31e9a81c8 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py @@ -15,6 +15,19 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from glayout.spice import Netlist +def __create_diff_pair_netlist(fetL: Component, fetR: Component) -> Netlist: + diff_pair_netlist = Netlist(circuit_name='DIFF_PAIR', nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VTAIL', 'B']) + diff_pair_netlist.connect_netlist( + fetL.info['netlist'], + [('D', 'VDD1'), ('G', 'VP'), ('S', 'VTAIL'), ('B', 'B')] + ) + diff_pair_netlist.connect_netlist( + fetR.info['netlist'], + [('D', 'VDD2'), ('G', 'VN'), ('S', 'VTAIL'), ('B', 'B')] + ) + + return diff_pair_netlist + @cell def diff_pair( pdk: MappedPDK, @@ -144,18 +157,7 @@ def diff_pair( component = component_snap_to_grid(rename_ports_by_orientation(diffpair)) - # add spice netlist - diff_pair_netlist = Netlist(circuit_name='DIFF_PAIR', nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VTAIL', 'B']) - diff_pair_netlist.connect_netlist( - fetL.info['netlist'], - [('D', 'VDD1'), ('G', 'VP'), ('S', 'VTAIL'), ('B', 'B')] - ) - diff_pair_netlist.connect_netlist( - fetR.info['netlist'], - [('D', 'VDD2'), ('G', 'VN'), ('S', 'VTAIL'), ('B', 'B')] - ) - - component.info['netlist'] = diff_pair_netlist + component.info['netlist'] = __create_diff_pair_netlist(fetL, fetR) return component From 30fc810c62380e73e7b0fa2ab2b97b24c67ed8c2 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 06:54:13 +0530 Subject: [PATCH 50/57] refactor: created separate functions for opamp and opamp_two_stage netlists --- .../glayout/components/opamp.py | 93 ++++++++++--------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index b89c2c46f..6adabf0a5 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -22,6 +22,39 @@ from glayout.components.opamp_twostage import opamp_twostage +def __create_output_stage_netlist(pdk: MappedPDK, output_amp_fet_ref: ComponentReference, biasParams: list) -> Netlist: + bias_netlist = Netlist( + circuit_name='CURRENT_MIRROR', + nodes=['VREF', 'VCOPY', 'VSS'], + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 +XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} +XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} +.ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", + parameters={ + 'model': pdk.models['nfet'], + 'width': biasParams[0], + 'length': biasParams[1], + 'mult': biasParams[2] + } + ) + + output_stage_netlist = Netlist( + circuit_name="OUTPUT_STAGE", + nodes=['VDD', 'GND', 'IBIAS', 'VIN', 'VOUT'] + ) + + output_stage_netlist.connect_netlist( + output_amp_fet_ref.info['netlist'], + [('D', 'VDD'), ('G', 'VIN'), ('B', 'GND'), ('S', 'VOUT')] + ) + + output_stage_netlist.connect_netlist( + bias_netlist, + [('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] + ) + + return output_stage_netlist @validate_arguments def __add_output_stage( @@ -109,40 +142,26 @@ def __add_output_stage( opamp_top << straight_route(pdk, bias_pin.ports["e2"], cmirror_ibias.ports["B_gate_S"],width=1) opamp_top.add_ports(bias_pin.get_ports_list(),prefix="pin_outputibias_") - bias_netlist = Netlist( - circuit_name='CURRENT_MIRROR', - nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 -XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -.ends {circuit_name}""", - instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", - parameters={ - 'model': pdk.models['nfet'], - 'width': biasParams[0], - 'length': biasParams[1], - 'mult': biasParams[2] - } - ) + output_stage_netlist = __create_output_stage_netlist(pdk, amp_fet_ref, biasParams) + return opamp_top, output_stage_netlist - output_stage_netlist = Netlist( - circuit_name="OUTPUT_STAGE", - nodes=['VDD', 'GND', 'IBIAS', 'VIN', 'VOUT'] +def __create_opamp_netlist(two_stage_netlist: Netlist, output_stage_netlist: Netlist) -> Netlist: + top_level_netlist = Netlist( + circuit_name="opamp", + nodes=['gnd', 'CSoutput', 'output', 'vdd', 'plus', 'minus', 'commonsourceibias', 'outputibias', 'diffpairibias'] ) - output_stage_netlist.connect_netlist( - amp_fet_ref.info['netlist'], - [('D', 'VDD'), ('G', 'VIN'), ('B', 'GND'), ('S', 'VOUT')] + top_level_netlist.connect_netlist( + two_stage_netlist, + [('VDD', 'vdd'), ('GND', 'gnd'), ('DIFFPAIR_BIAS', 'diffpairibias'), ('VP', 'plus'), ('VN', 'minus'), ('CS_BIAS', 'commonsourceibias'), ('VOUT', 'CSoutput')] ) - output_stage_netlist.connect_netlist( - bias_netlist, - [('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] + top_level_netlist.connect_netlist( + output_stage_netlist, + [('VDD', 'vdd'), ('GND', 'gnd'), ('IBIAS', 'outputibias'), ('VIN', 'CSoutput'), ('VOUT', 'output')] ) - return opamp_top, output_stage_netlist - - + return top_level_netlist @cell def opamp( @@ -189,25 +208,7 @@ def opamp( ) # add output amplfier stage opamp_top, output_stage_netlist = __add_output_stage(pdk, opamp_top, output_stage_params, output_stage_bias, rmult) - - two_stage_netlist = opamp_top.info['netlist'] - - top_level_netlist = Netlist( - circuit_name="opamp", - nodes=['gnd', 'CSoutput', 'output', 'vdd', 'plus', 'minus', 'commonsourceibias', 'outputibias', 'diffpairibias'] - ) - - top_level_netlist.connect_netlist( - two_stage_netlist, - [('VDD', 'vdd'), ('GND', 'gnd'), ('DIFFPAIR_BIAS', 'diffpairibias'), ('VP', 'plus'), ('VN', 'minus'), ('CS_BIAS', 'commonsourceibias'), ('VOUT', 'CSoutput')] - ) - - top_level_netlist.connect_netlist( - output_stage_netlist, - [('VDD', 'vdd'), ('GND', 'gnd'), ('IBIAS', 'outputibias'), ('VIN', 'CSoutput'), ('VOUT', 'output')] - ) - - opamp_top.info['netlist'] = top_level_netlist + opamp_top.info['netlist'] = __create_opamp_netlist(opamp_top.info['netlist'], output_stage_netlist) # return return rename_ports_by_orientation(component_snap_to_grid(opamp_top)) From 3485dade4c13ee4c80176d8c36238ba85a4d056f Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 07:02:20 +0530 Subject: [PATCH 51/57] refactor: created separate function for current mirror netlist --- .../components/diff_pair_cmirrorbias.py | 20 ++++++------------ .../glayout/components/opamp.py | 17 ++------------- .../glayout/components/opamp_twostage.py | 21 ++++++------------- .../components/stacked_current_mirror.py | 18 +++++++++++++++- 4 files changed, 31 insertions(+), 45 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 5f6e34222..4d62ac767 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -37,6 +37,7 @@ from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized from glayout.spice import Netlist +from glayout.components.stacked_current_mirror import create_current_mirror_netlist @validate_arguments def diff_pair_ibias( @@ -147,20 +148,11 @@ def diff_pair_ibias( ) cmirror.add_ports(srcshort.get_ports_list(), prefix="purposegndports") # current mirror netlist - cmirror.info['netlist'] = Netlist( - circuit_name='CURRENT_MIRROR', - nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 -XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -.ends {circuit_name}""", - instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", - parameters={ - 'model': pdk.models['nfet'], - 'width': diffpair_bias[0], - 'length': diffpair_bias[1], - 'mult': diffpair_bias[2] - } + cmirror.info['netlist'] = create_current_mirror_netlist( + pdk, + width=diffpair_bias[0], + length=diffpair_bias[1], + multipliers=diffpair_bias[2] ) # add cmirror diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 6adabf0a5..4ffca2fba 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -21,23 +21,10 @@ from glayout.spice import Netlist from glayout.components.opamp_twostage import opamp_twostage +from glayout.components.stacked_current_mirror import create_current_mirror_netlist def __create_output_stage_netlist(pdk: MappedPDK, output_amp_fet_ref: ComponentReference, biasParams: list) -> Netlist: - bias_netlist = Netlist( - circuit_name='CURRENT_MIRROR', - nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 -XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -.ends {circuit_name}""", - instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", - parameters={ - 'model': pdk.models['nfet'], - 'width': biasParams[0], - 'length': biasParams[1], - 'mult': biasParams[2] - } - ) + bias_netlist = create_current_mirror_netlist(pdk, biasParams[0], biasParams[1], biasParams[2]) output_stage_netlist = Netlist( circuit_name="OUTPUT_STAGE", diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index fd96d61e9..567ee7cdb 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -25,7 +25,7 @@ from glayout.components.row_csamplifier_diff_to_single_ended_converter import row_csamplifier_diff_to_single_ended_converter from glayout.components.diff_pair_stackedcmirror import diff_pair_stackedcmirror from glayout.spice import Netlist - +from glayout.components.stacked_current_mirror import create_current_mirror_netlist @validate_arguments def __create_and_route_pins( @@ -171,20 +171,11 @@ def opamp_twostage( pmos_comps = row_csamplifier_diff_to_single_ended_converter(pdk, pmos_comps, half_common_source_params, rmult) - cs_bias_netlist = Netlist( - circuit_name='CURRENT_MIRROR', - nodes=['VREF', 'VCOPY', 'VSS'], - source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 -XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} -.ends {circuit_name}""", - instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", - parameters={ - 'model': pdk.models['nfet'], - 'width': diffpair_bias[0], - 'length': diffpair_bias[1], - 'mult': diffpair_bias[2] - } + cs_bias_netlist = create_current_mirror_netlist( + pdk, + width=diffpair_bias[0], + length=diffpair_bias[1], + multipliers=diffpair_bias[2] ) ydim_ncomps = opamp_top.ymax diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py b/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py index 9d8a7fdd6..f097b3bd9 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py @@ -18,8 +18,24 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized +from glayout.spice import Netlist - +def create_current_mirror_netlist(pdk: MappedPDK, width: float, length: float, multipliers: int) -> Netlist: + return Netlist( + circuit_name='CURRENT_MIRROR', + nodes=['VREF', 'VCOPY', 'VSS'], + source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 m=1 +XREF VREF VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} +XCOPY VCOPY VREF VSS VSS {model} l={{l}} w={{w}} m={{m}} +.ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} w={width} m={mult}", + parameters={ + 'model': pdk.models['nfet'], + 'width': width, + 'length': length, + 'mult': multipliers + } + ) @validate_arguments def stacked_nfet_current_mirror(pdk: MappedPDK, half_common_source_nbias: tuple[float, float, int, int], rmult: int, sd_route_left: bool) -> Component: From 21cb8314fc44e46c12312ab605977c2421a711c0 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 07:06:22 +0530 Subject: [PATCH 52/57] refactor: created separate function for diff2single netlist --- .../differential_to_single_ended_converter.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 424a7336f..926cadcb7 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -146,15 +146,8 @@ def __route_sharedgatecomps(pdk: MappedPDK, shared_gate_comps, via_location, pto shared_gate_comps.add_ports(mimcap_connection_ref.get_ports_list(),prefix="mimcap_connection_") return shared_gate_comps - -def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_pload: tuple[float,float,int], via_xlocation) -> tuple: - clear_cache() - pmos_comps, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports = __create_sharedgatecomps(pdk, rmult,half_pload) - clear_cache() - pmos_comps = __route_sharedgatecomps(pdk, pmos_comps, via_xlocation, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports) - - # add spice netlist - diff_to_single_netlist = Netlist( +def __create_diff_to_single_netlist(pdk: MappedPDK, half_pload: tuple[float, float, int]) -> Netlist: + return Netlist( circuit_name="DIFF_TO_SINGLE", nodes=['VIN', 'VOUT', 'VSS', 'VSS2'], source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 mt=1 mb=1 @@ -173,6 +166,12 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa } ) - pmos_comps.info['netlist'] = diff_to_single_netlist +def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_pload: tuple[float,float,int], via_xlocation) -> tuple: + clear_cache() + pmos_comps, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports = __create_sharedgatecomps(pdk, rmult,half_pload) + clear_cache() + pmos_comps = __route_sharedgatecomps(pdk, pmos_comps, via_xlocation, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports) + + pmos_comps.info['netlist'] = __create_diff_to_single_netlist(pdk, half_pload) return pmos_comps From ea636f510a2ae4f497c547cc86725568aa868abb Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 07:06:37 +0530 Subject: [PATCH 53/57] refactor: created separate netlist for row_csamp_diff2single --- ...mplifier_diff_to_single_ended_converter.py | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py index d9d7ac465..ad624cfb4 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py @@ -20,21 +20,29 @@ from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized from glayout.spice import Netlist - -def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_single_ended_converter: Component, pamp_hparams, rmult) -> Component: - pmos_comps = diff_to_single_ended_converter - +def __create_csamp_diff_to_single_netlist(diff_to_single: Component) -> Netlist: overall_netlist = Netlist( circuit_name="DIFF_TO_SINGLE_CS", nodes=['VIN1', 'VIN2', 'VOUT', 'VSS', 'VSS2'] ) overall_netlist.connect_netlist( - pmos_comps.info['netlist'], + diff_to_single.info['netlist'], [('VIN', 'VIN1'), ('VOUT', 'VIN2')] ) - pmos_comps.info['netlist'] = overall_netlist + return overall_netlist + +def __connect_cs_netlist(pmos_comps: Component, half_cs_pmos: Component): + pmos_comps.info['netlist'].connect_netlist( + half_cs_pmos.info['netlist'], + [('D', 'VOUT'), ('S', 'VSS'), ('B', 'VSS'), ('G', 'VIN2')] + ) + +def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_single_ended_converter: Component, pamp_hparams, rmult) -> Component: + pmos_comps = diff_to_single_ended_converter + + pmos_comps.info['netlist'] = __create_csamp_diff_to_single_netlist(diff_to_single_ended_converter) x_dim_center = max(abs(pmos_comps.xmax),abs(pmos_comps.xmin)) for direction in [-1, 1]: @@ -57,10 +65,7 @@ def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_singl # this special marker is used to rename these ports in the opamp to commonsource_Pamp_ pmos_comps.add_ports(halfMultp_ref.get_ports_list(),prefix="halfpspecialmarker_"+label) - pmos_comps.info['netlist'].connect_netlist( - halfMultp.info['netlist'], - [('D', 'VOUT'), ('S', 'VSS'), ('B', 'VSS'), ('G', 'VIN2')] - ) + __connect_cs_netlist(pmos_comps, halfMultp) # add npadding and add ports nwellbbox = pmos_comps.extract(layers=[pdk.get_glayer("poly"),pdk.get_glayer("active_diff"),pdk.get_glayer("active_tap"), pdk.get_glayer("nwell"),pdk.get_glayer("dnwell")]).bbox From fda33fe56e8c7ac28dd8d32e792a3abf193f2159 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 07:10:24 +0530 Subject: [PATCH 54/57] refactor: created separate function for diff_pair_cmirrorbias --- .../components/diff_pair_cmirrorbias.py | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 4d62ac767..7595a66f9 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -39,6 +39,40 @@ from glayout.spice import Netlist from glayout.components.stacked_current_mirror import create_current_mirror_netlist +def __create_diff_pair_ibias_netlist(center_diffpair: Component, current_mirror: Component, antenna_diode: Component) -> Netlist: + netlist = Netlist( + circuit_name="DIFFPAIR_CMIRROR_BIAS", + nodes=['VP', 'VN', 'VDD1', 'VDD2', 'IBIAS', 'VSS', 'B'] + ) + + netlist.connect_netlist( + center_diffpair.info['netlist'], + [] + ) + + netlist.connect_netlist( + current_mirror.info['netlist'], + [('VREF', 'IBIAS')] + ) + + netlist.connect_subnets( + current_mirror.info['netlist'], + center_diffpair.info['netlist'], + [('VCOPY', 'VTAIL')] + ) + + netlist.connect_netlist( + antenna_diode.info['netlist'], + [('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VP')] + ) + + netlist.connect_netlist( + deepcopy(antenna_diode.info['netlist']), + [('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VN')] + ) + + return netlist + @validate_arguments def diff_pair_ibias( pdk: MappedPDK, @@ -169,37 +203,8 @@ def diff_pair_ibias( diffpair_i_.add_ports([purposegndPort]) diffpair_i_.add_ports(tailcurrent_ref.get_ports_list(), prefix="ibias_") - # complete netlist - diffpair_i_.info['netlist'] = Netlist( - circuit_name="DIFFPAIR_CMIRROR_BIAS", - nodes=['VP', 'VN', 'VDD1', 'VDD2', 'IBIAS', 'VSS', 'B'] - ) - - diffpair_i_.info['netlist'].connect_netlist( - center_diffpair_comp.info['netlist'], - [] - ) - - diffpair_i_.info['netlist'].connect_netlist( - cmirror.info['netlist'], - [('VREF', 'IBIAS')] - ) - - diffpair_i_.info['netlist'].connect_subnets( - cmirror.info['netlist'], - center_diffpair_comp.info['netlist'], - [('VCOPY', 'VTAIL')] - ) - - diffpair_i_.info['netlist'].connect_netlist( - antenna_diode_comp.info['netlist'], - [('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VP')] - ) - diffpair_i_.info['netlist'].connect_netlist( - deepcopy(antenna_diode_comp.info['netlist']), - [('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VN')] - ) - diffpair_i_ref = prec_ref_center(diffpair_i_) + + diffpair_i_ref.info['netlist'] = __create_diff_pair_ibias_netlist(center_diffpair_comp, cmirror, antenna_diode_comp) return diffpair_i_ref From f9621ba9f11b46e88f50af9b27626ebf42f20f4c Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 07:15:47 +0530 Subject: [PATCH 55/57] refactor: created separate netlist for opamp_twostage --- .../glayout/components/opamp_twostage.py | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index 567ee7cdb..492bb3f37 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -128,7 +128,54 @@ def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap opamp_top.add_port(name="commonsource_output_E", port=intermediate_output) return opamp_top, mimcap_netlist +def __create_gain_stage_netlist(mimcap_netlist: Netlist, diff_cs_netlist: Netlist, cs_bias_netlist: Netlist) -> Netlist: + netlist = Netlist( + circuit_name="GAIN_STAGE", + nodes=['VIN1', 'VIN2', 'VOUT', 'VDD', 'IBIAS', 'GND'] + ) + + netlist.connect_netlist( + diff_cs_netlist, + [('VSS', 'VDD')] + ) + + netlist.connect_netlist( + cs_bias_netlist, + [('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] + ) + + netlist.connect_netlist(mimcap_netlist, [('V2', 'VOUT')]) + netlist.connect_subnets( + mimcap_netlist, + diff_cs_netlist, + [('V1', 'VSS2')] + ) + return netlist + +def __create_two_stage_netlist(input_stage_netlist: Netlist, gain_stage_netlist: Netlist) -> Netlist: + two_stage_netlist = Netlist( + circuit_name="OPAMP_TWO_STAGE", + nodes=['VDD', 'GND', 'DIFFPAIR_BIAS', 'VP', 'VN', 'CS_BIAS', 'VOUT'] + ) + + two_stage_netlist.connect_netlist( + input_stage_netlist, + [('IBIAS', 'DIFFPAIR_BIAS'), ('VSS', 'GND'), ('B', 'GND')] + ) + + two_stage_netlist.connect_netlist( + gain_stage_netlist, + [('IBIAS', 'CS_BIAS')] + ) + + two_stage_netlist.connect_subnets( + input_stage_netlist, + gain_stage_netlist, + [('VDD1', 'VIN1'), ('VDD2', 'VIN2')] + ) + + return two_stage_netlist def opamp_twostage( pdk: MappedPDK, @@ -194,55 +241,8 @@ def opamp_twostage( # return opamp_top.add_ports(_cref.get_ports_list(), prefix="gnd_route_") - diff_cs_netlist = pmos_comps.info['netlist'] - - pmos_comps.info['netlist'] = Netlist( - circuit_name="GAIN_STAGE", - nodes=['VIN1', 'VIN2', 'VOUT', 'VDD', 'IBIAS', 'GND'] - ) - - pmos_comps.info['netlist'].connect_netlist( - diff_cs_netlist, - [('VSS', 'VDD')] - ) - - pmos_comps.info['netlist'].connect_netlist( - cs_bias_netlist, - [('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] - ) - - pmos_comps.info['netlist'].connect_netlist(mimcap_netlist, [('V2', 'VOUT')]) - pmos_comps.info['netlist'].connect_subnets( - mimcap_netlist, - diff_cs_netlist, - [('V1', 'VSS2')] - ) - - two_stage_netlist = Netlist( - circuit_name="OPAMP_TWO_STAGE", - nodes=['VDD', 'GND', 'DIFFPAIR_BIAS', 'VP', 'VN', 'CS_BIAS', 'VOUT'] - ) - - input_stage_netlist = opamp_top.info['netlist'] - gain_stage_netlist = pmos_comps.info['netlist'] - - two_stage_netlist.connect_netlist( - input_stage_netlist, - [('IBIAS', 'DIFFPAIR_BIAS'), ('VSS', 'GND'), ('B', 'GND')] - ) - - two_stage_netlist.connect_netlist( - gain_stage_netlist, - [('IBIAS', 'CS_BIAS')] - ) - - two_stage_netlist.connect_subnets( - input_stage_netlist, - gain_stage_netlist, - [('VDD1', 'VIN1'), ('VDD2', 'VIN2')] - ) - - opamp_top.info['netlist'] = two_stage_netlist + pmos_comps.info['netlist'] = __create_gain_stage_netlist(mimcap_netlist, pmos_comps.info['netlist'], cs_bias_netlist) + opamp_top.info['netlist'] = __create_two_stage_netlist(opamp_top.info['netlist'], pmos_comps.info['netlist']) return opamp_top From ce0d1bf2d7139984221268979630e609f1173166 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sat, 18 Nov 2023 18:28:44 +0530 Subject: [PATCH 56/57] refactor: better naming for netlist functions --- .../gdsfactory-gen/glayout/components/diff_pair.py | 4 ++-- .../glayout/components/diff_pair_cmirrorbias.py | 8 ++++---- .../differential_to_single_ended_converter.py | 4 ++-- .../gdsfactory-gen/glayout/components/opamp.py | 12 ++++++------ .../glayout/components/opamp_twostage.py | 12 ++++++------ ...row_csamplifier_diff_to_single_ended_converter.py | 4 ++-- .../glayout/components/stacked_current_mirror.py | 2 +- .../gdsfactory-gen/glayout/primitives/fet.py | 6 +++--- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py index 31e9a81c8..d7c402092 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair.py @@ -15,7 +15,7 @@ from glayout.pdk.util.snap_to_grid import component_snap_to_grid from glayout.spice import Netlist -def __create_diff_pair_netlist(fetL: Component, fetR: Component) -> Netlist: +def diff_pair_netlist(fetL: Component, fetR: Component) -> Netlist: diff_pair_netlist = Netlist(circuit_name='DIFF_PAIR', nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VTAIL', 'B']) diff_pair_netlist.connect_netlist( fetL.info['netlist'], @@ -157,7 +157,7 @@ def diff_pair( component = component_snap_to_grid(rename_ports_by_orientation(diffpair)) - component.info['netlist'] = __create_diff_pair_netlist(fetL, fetR) + component.info['netlist'] = diff_pair_netlist(fetL, fetR) return component diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 7595a66f9..83f4b9806 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -37,9 +37,9 @@ from pydantic import validate_arguments from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized from glayout.spice import Netlist -from glayout.components.stacked_current_mirror import create_current_mirror_netlist +from glayout.components.stacked_current_mirror import current_mirror_netlist -def __create_diff_pair_ibias_netlist(center_diffpair: Component, current_mirror: Component, antenna_diode: Component) -> Netlist: +def diff_pair_ibias_netlist(center_diffpair: Component, current_mirror: Component, antenna_diode: Component) -> Netlist: netlist = Netlist( circuit_name="DIFFPAIR_CMIRROR_BIAS", nodes=['VP', 'VN', 'VDD1', 'VDD2', 'IBIAS', 'VSS', 'B'] @@ -182,7 +182,7 @@ def diff_pair_ibias( ) cmirror.add_ports(srcshort.get_ports_list(), prefix="purposegndports") # current mirror netlist - cmirror.info['netlist'] = create_current_mirror_netlist( + cmirror.info['netlist'] = current_mirror_netlist( pdk, width=diffpair_bias[0], length=diffpair_bias[1], @@ -205,6 +205,6 @@ def diff_pair_ibias( diffpair_i_ref = prec_ref_center(diffpair_i_) - diffpair_i_ref.info['netlist'] = __create_diff_pair_ibias_netlist(center_diffpair_comp, cmirror, antenna_diode_comp) + diffpair_i_ref.info['netlist'] = diff_pair_ibias_netlist(center_diffpair_comp, cmirror, antenna_diode_comp) return diffpair_i_ref diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py index 926cadcb7..6c7c46f9c 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/differential_to_single_ended_converter.py @@ -146,7 +146,7 @@ def __route_sharedgatecomps(pdk: MappedPDK, shared_gate_comps, via_location, pto shared_gate_comps.add_ports(mimcap_connection_ref.get_ports_list(),prefix="mimcap_connection_") return shared_gate_comps -def __create_diff_to_single_netlist(pdk: MappedPDK, half_pload: tuple[float, float, int]) -> Netlist: +def differential_to_single_ended_converter_netlist(pdk: MappedPDK, half_pload: tuple[float, float, int]) -> Netlist: return Netlist( circuit_name="DIFF_TO_SINGLE", nodes=['VIN', 'VOUT', 'VSS', 'VSS2'], @@ -172,6 +172,6 @@ def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_ploa clear_cache() pmos_comps = __route_sharedgatecomps(pdk, pmos_comps, via_xlocation, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports) - pmos_comps.info['netlist'] = __create_diff_to_single_netlist(pdk, half_pload) + pmos_comps.info['netlist'] = differential_to_single_ended_converter_netlist(pdk, half_pload) return pmos_comps diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py index 4ffca2fba..619e6ab46 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py @@ -21,10 +21,10 @@ from glayout.spice import Netlist from glayout.components.opamp_twostage import opamp_twostage -from glayout.components.stacked_current_mirror import create_current_mirror_netlist +from glayout.components.stacked_current_mirror import current_mirror_netlist -def __create_output_stage_netlist(pdk: MappedPDK, output_amp_fet_ref: ComponentReference, biasParams: list) -> Netlist: - bias_netlist = create_current_mirror_netlist(pdk, biasParams[0], biasParams[1], biasParams[2]) +def opamp_output_stage_netlist(pdk: MappedPDK, output_amp_fet_ref: ComponentReference, biasParams: list) -> Netlist: + bias_netlist = current_mirror_netlist(pdk, biasParams[0], biasParams[1], biasParams[2]) output_stage_netlist = Netlist( circuit_name="OUTPUT_STAGE", @@ -129,10 +129,10 @@ def __add_output_stage( opamp_top << straight_route(pdk, bias_pin.ports["e2"], cmirror_ibias.ports["B_gate_S"],width=1) opamp_top.add_ports(bias_pin.get_ports_list(),prefix="pin_outputibias_") - output_stage_netlist = __create_output_stage_netlist(pdk, amp_fet_ref, biasParams) + output_stage_netlist = opamp_output_stage_netlist(pdk, amp_fet_ref, biasParams) return opamp_top, output_stage_netlist -def __create_opamp_netlist(two_stage_netlist: Netlist, output_stage_netlist: Netlist) -> Netlist: +def opamp_netlist(two_stage_netlist: Netlist, output_stage_netlist: Netlist) -> Netlist: top_level_netlist = Netlist( circuit_name="opamp", nodes=['gnd', 'CSoutput', 'output', 'vdd', 'plus', 'minus', 'commonsourceibias', 'outputibias', 'diffpairibias'] @@ -195,7 +195,7 @@ def opamp( ) # add output amplfier stage opamp_top, output_stage_netlist = __add_output_stage(pdk, opamp_top, output_stage_params, output_stage_bias, rmult) - opamp_top.info['netlist'] = __create_opamp_netlist(opamp_top.info['netlist'], output_stage_netlist) + opamp_top.info['netlist'] = opamp_netlist(opamp_top.info['netlist'], output_stage_netlist) # return return rename_ports_by_orientation(component_snap_to_grid(opamp_top)) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index 492bb3f37..b4e9111ea 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -25,7 +25,7 @@ from glayout.components.row_csamplifier_diff_to_single_ended_converter import row_csamplifier_diff_to_single_ended_converter from glayout.components.diff_pair_stackedcmirror import diff_pair_stackedcmirror from glayout.spice import Netlist -from glayout.components.stacked_current_mirror import create_current_mirror_netlist +from glayout.components.stacked_current_mirror import current_mirror_netlist @validate_arguments def __create_and_route_pins( @@ -128,7 +128,7 @@ def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap opamp_top.add_port(name="commonsource_output_E", port=intermediate_output) return opamp_top, mimcap_netlist -def __create_gain_stage_netlist(mimcap_netlist: Netlist, diff_cs_netlist: Netlist, cs_bias_netlist: Netlist) -> Netlist: +def opamp_gain_stage_netlist(mimcap_netlist: Netlist, diff_cs_netlist: Netlist, cs_bias_netlist: Netlist) -> Netlist: netlist = Netlist( circuit_name="GAIN_STAGE", nodes=['VIN1', 'VIN2', 'VOUT', 'VDD', 'IBIAS', 'GND'] @@ -153,7 +153,7 @@ def __create_gain_stage_netlist(mimcap_netlist: Netlist, diff_cs_netlist: Netlis return netlist -def __create_two_stage_netlist(input_stage_netlist: Netlist, gain_stage_netlist: Netlist) -> Netlist: +def opamp_twostage_netlist(input_stage_netlist: Netlist, gain_stage_netlist: Netlist) -> Netlist: two_stage_netlist = Netlist( circuit_name="OPAMP_TWO_STAGE", nodes=['VDD', 'GND', 'DIFFPAIR_BIAS', 'VP', 'VN', 'CS_BIAS', 'VOUT'] @@ -218,7 +218,7 @@ def opamp_twostage( pmos_comps = row_csamplifier_diff_to_single_ended_converter(pdk, pmos_comps, half_common_source_params, rmult) - cs_bias_netlist = create_current_mirror_netlist( + cs_bias_netlist = current_mirror_netlist( pdk, width=diffpair_bias[0], length=diffpair_bias[1], @@ -241,8 +241,8 @@ def opamp_twostage( # return opamp_top.add_ports(_cref.get_ports_list(), prefix="gnd_route_") - pmos_comps.info['netlist'] = __create_gain_stage_netlist(mimcap_netlist, pmos_comps.info['netlist'], cs_bias_netlist) - opamp_top.info['netlist'] = __create_two_stage_netlist(opamp_top.info['netlist'], pmos_comps.info['netlist']) + pmos_comps.info['netlist'] = opamp_gain_stage_netlist(mimcap_netlist, pmos_comps.info['netlist'], cs_bias_netlist) + opamp_top.info['netlist'] = opamp_twostage_netlist(opamp_top.info['netlist'], pmos_comps.info['netlist']) return opamp_top diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py index ad624cfb4..0299c6baf 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/row_csamplifier_diff_to_single_ended_converter.py @@ -20,7 +20,7 @@ from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized from glayout.spice import Netlist -def __create_csamp_diff_to_single_netlist(diff_to_single: Component) -> Netlist: +def row_csamplifier_diff_to_single_ended_converter_netlist(diff_to_single: Component) -> Netlist: overall_netlist = Netlist( circuit_name="DIFF_TO_SINGLE_CS", nodes=['VIN1', 'VIN2', 'VOUT', 'VSS', 'VSS2'] @@ -42,7 +42,7 @@ def __connect_cs_netlist(pmos_comps: Component, half_cs_pmos: Component): def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_single_ended_converter: Component, pamp_hparams, rmult) -> Component: pmos_comps = diff_to_single_ended_converter - pmos_comps.info['netlist'] = __create_csamp_diff_to_single_netlist(diff_to_single_ended_converter) + pmos_comps.info['netlist'] = row_csamplifier_diff_to_single_ended_converter_netlist(diff_to_single_ended_converter) x_dim_center = max(abs(pmos_comps.xmax),abs(pmos_comps.xmin)) for direction in [-1, 1]: diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py b/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py index f097b3bd9..1470c1c35 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/stacked_current_mirror.py @@ -20,7 +20,7 @@ from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized from glayout.spice import Netlist -def create_current_mirror_netlist(pdk: MappedPDK, width: float, length: float, multipliers: int) -> Netlist: +def current_mirror_netlist(pdk: MappedPDK, width: float, length: float, multipliers: int) -> Netlist: return Netlist( circuit_name='CURRENT_MIRROR', nodes=['VREF', 'VCOPY', 'VSS'], diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py index dbfbc11c9..3e9365df2 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/fet.py @@ -62,7 +62,7 @@ def __gen_fingers_macro(pdk: MappedPDK, rmult: int, fingers: int, length: float, multiplier.add_ports(diff.get_ports_list(),prefix="diff_") return component_snap_to_grid(rename_ports_by_orientation(multiplier)) -def __generate_fet_netlist( +def fet_netlist( circuit_name: str, model: str, width: float, @@ -465,7 +465,7 @@ def nmos( component = rename_ports_by_orientation(nfet).flatten() - component.info['netlist'] = __generate_fet_netlist( + component.info['netlist'] = fet_netlist( circuit_name="NMOS", model=pdk.models['nfet'], width=width, @@ -602,7 +602,7 @@ def pmos( ) component = rename_ports_by_orientation(pfet).flatten() - component.info['netlist'] = __generate_fet_netlist( + component.info['netlist'] = fet_netlist( circuit_name="PMOS", model=pdk.models['pfet'], width=width, From 366ea3d4fb6199d71a61d079f8833edf22cbe276 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sun, 19 Nov 2023 05:15:46 +0530 Subject: [PATCH 57/57] feat: used ref and deepcopy inside connect_netlist --- .../glayout/components/diff_pair_cmirrorbias.py | 11 +++++------ .../glayout/components/opamp_twostage.py | 17 +++++++++-------- .../gdsfactory-gen/glayout/primitives/mimcap.py | 3 +-- .../gdsfactory-gen/glayout/spice/netlist.py | 5 +++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py index 83f4b9806..6a975d4da 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/diff_pair_cmirrorbias.py @@ -1,4 +1,3 @@ -from copy import deepcopy from gdsfactory.cell import cell, clear_cache from gdsfactory.component import Component, copy from gdsfactory.component_reference import ComponentReference @@ -45,19 +44,19 @@ def diff_pair_ibias_netlist(center_diffpair: Component, current_mirror: Componen nodes=['VP', 'VN', 'VDD1', 'VDD2', 'IBIAS', 'VSS', 'B'] ) - netlist.connect_netlist( + diffpair_ref = netlist.connect_netlist( center_diffpair.info['netlist'], [] ) - netlist.connect_netlist( + cmirror_ref = netlist.connect_netlist( current_mirror.info['netlist'], [('VREF', 'IBIAS')] ) netlist.connect_subnets( - current_mirror.info['netlist'], - center_diffpair.info['netlist'], + cmirror_ref, + diffpair_ref, [('VCOPY', 'VTAIL')] ) @@ -67,7 +66,7 @@ def diff_pair_ibias_netlist(center_diffpair: Component, current_mirror: Componen ) netlist.connect_netlist( - deepcopy(antenna_diode.info['netlist']), + antenna_diode.info['netlist'], [('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VN')] ) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py index b4e9111ea..30fc215dd 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/components/opamp_twostage.py @@ -134,7 +134,7 @@ def opamp_gain_stage_netlist(mimcap_netlist: Netlist, diff_cs_netlist: Netlist, nodes=['VIN1', 'VIN2', 'VOUT', 'VDD', 'IBIAS', 'GND'] ) - netlist.connect_netlist( + diff_cs_ref = netlist.connect_netlist( diff_cs_netlist, [('VSS', 'VDD')] ) @@ -144,10 +144,11 @@ def opamp_gain_stage_netlist(mimcap_netlist: Netlist, diff_cs_netlist: Netlist, [('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')] ) - netlist.connect_netlist(mimcap_netlist, [('V2', 'VOUT')]) + mimcap_ref = netlist.connect_netlist(mimcap_netlist, [('V2', 'VOUT')]) + netlist.connect_subnets( - mimcap_netlist, - diff_cs_netlist, + mimcap_ref, + diff_cs_ref, [('V1', 'VSS2')] ) @@ -159,19 +160,19 @@ def opamp_twostage_netlist(input_stage_netlist: Netlist, gain_stage_netlist: Net nodes=['VDD', 'GND', 'DIFFPAIR_BIAS', 'VP', 'VN', 'CS_BIAS', 'VOUT'] ) - two_stage_netlist.connect_netlist( + input_stage_ref = two_stage_netlist.connect_netlist( input_stage_netlist, [('IBIAS', 'DIFFPAIR_BIAS'), ('VSS', 'GND'), ('B', 'GND')] ) - two_stage_netlist.connect_netlist( + gain_stage_ref = two_stage_netlist.connect_netlist( gain_stage_netlist, [('IBIAS', 'CS_BIAS')] ) two_stage_netlist.connect_subnets( - input_stage_netlist, - gain_stage_netlist, + input_stage_ref, + gain_stage_ref, [('VDD1', 'VIN1'), ('VDD2', 'VIN2')] ) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py index 2fcf92763..17ddb571a 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/primitives/mimcap.py @@ -10,7 +10,6 @@ from glayout.routing.straight_route import straight_route from decimal import ROUND_UP, Decimal from glayout.spice import Netlist -from copy import deepcopy @validate_arguments def __get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: @@ -46,7 +45,7 @@ def __generate_mimcap_array_netlist(mimcap_netlist: Netlist, num_caps: int) -> N for _ in range(num_caps): arr_netlist.connect_netlist( - deepcopy(mimcap_netlist), + mimcap_netlist, [] ) diff --git a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py index 85b0bba08..5ed9576a1 100644 --- a/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py +++ b/openfasoc/generators/gdsfactory-gen/glayout/spice/netlist.py @@ -1,5 +1,6 @@ from os.path import join, dirname from typing import Union, Optional +from copy import deepcopy import re @@ -169,14 +170,14 @@ def add_netlists(self, netlists: list['Netlist']): self.sub_netlists.append(netlist) self.netlist_connections.append(netlist.nodes.copy()) - def connect_netlist(self, netlist: 'Netlist', node_mapping: list[tuple[str, str]]): + def connect_netlist(self, netlist: 'Netlist', node_mapping: list[tuple[str, str]]) -> int: """Adds a sub-netlist and connects it to top-level nodes. Parameters: - `netlist`: The netlist object to add. - `node_mapping`: A list of 2-element tuples representing the connections between the netlist nodes and the top-level nodes. The first element in the tuple is the name of the node of `netlist` and the second value is the name of the top-level to connect to. """ - self.add_netlists([netlist]) + self.add_netlists([deepcopy(netlist)]) netlist_index = len(self.sub_netlists) - 1 self.connect_node(net=netlist_index, node_mapping=node_mapping)