piel.integration.gdsfactory_hdl21.core#

Most of the hdl21-gdsfactory integration functions will be contributed directly to gdsfactory. However, some translation language inherent to the piel implementation of these tools is included here.

Note that to be able to construct a full circuit model of the netlist tools provided, it is necessary to create individual circuit models of the devices that we will interconnect, and then map them to a larger netlist. This means that it is necessary to create specific SPICE models for each particular component, say in an electrical netlist.

This functions convert a GDSFactory netlist, with a set of component models, into hdl21 that accounts for the instance properties, which can then be connected into a VLSIR compatible Netlist implementation.

Eventually we will implement RCX where we can extract the netlist with parasitics directly from the layout, but for now this will be the implementation. The output structure of our SPICE should be compatible with the Netlist package BaseModel.

We follow the principle in: https://eee.guc.edu.eg/Courses/Electronics/ELCT503%20Semiconductors/Lab/spicehowto.pdf

Spice Simulation 1-1
*** MODEL Descriptions ***
.model nm NMOS level=2 VT0=0.7
KP=80e-6 LAMBDA=0.01

*** NETLIST Description ***
M1 vdd ng 0 0 nm W=3u L=3u
R1 in ng 50
Vdd vdd 0 5
Vin in 0 2.5

*** SIMULATION Commands ***
.op
.end

Note that the netlist device connectivity structure of most passive components is in the form:

<DEVICE ID> <CONNECTION_0> <CONNECTION_1> <DEVICE_VALUE> <MORE_PARAMETERS>

Our example GDSFactory netlist format is in the simplified form:

{
    "connections": {
        "straight_1": {
            "e1": "taper_1,e2",
            "e2": "taper_2,e2"
        },
        "taper_1": {
            "e1": "via_stack_1,e3"
        },
        "taper_2": {
            "e1": "via_stack_2,e1"
        }
    },
    "instances": {
        "straight_1": {
            "component": "straight",
            "info": {
                "length": 15.0,
                "width": 0.5,
                "cross_section": "strip_heater_metal",
                "settings": {
                    "width": 0.5,
                    "layer": "WG",
                    "heater_width": 2.5,
                    "layer_heater": "HEATER"
                }
            }
        },
        "taper_1": {
            "component": "taper",
            "info": {
                "length": 5.0,
                "width1": 11.0,
                "width2": 2.5
            },
            "settings": {
                "cross_section": {
                    "layer": "HEATER",
                    "width": 2.5,
                    "offset": 0.0,
                    "taper_length": 10.0,
                    "gap": 5.0,
                    "min_length": 5.0,
                    "port_names": ["e1", "e2"]
                }
            }
        },
        "taper_2": {
            "component": "taper",
            "info": {
                "length": 5.0,
                "width1": 11.0,
                "width2": 2.5
            },
            "settings": {
                "cross_section": {
                    "layer": "HEATER",
                    "width": 2.5,
                    "offset": 0.0,
                    "taper_length": 10.0,
                    "gap": 5.0,
                    "min_length": 5.0,
                    "port_names": ["e1", "e2"]
                }
            }
        },
        "via_stack_1": {
            "component": "via_stack",
            "info": {
                "size": [11.0, 11.0],
                "layer": "M3"
            },
            "settings": {
                "layers": ["HEATER", "M2", "M3"]
            }
        },
        "via_stack_2": {
            "component": "via_stack",
            "info": {
                "size": [11.0, 11.0],
                "layer": "M3"
            },
            "settings": {
                "layers": ["HEATER", "M2", "M3"]
            }
        }
    },
    "placements": {
        "straight_1": {"x": 0.0, "y": 0.0, "rotation": 0, "mirror": 0},
        "taper_1": {"x": -5.0, "y": 0.0, "rotation": 0, "mirror": 0},
        "taper_2": {"x": 20.0, "y": 0.0, "rotation": 180, "mirror": 0},
        "via_stack_1": {"x": -10.5, "y": 0.0, "rotation": 0, "mirror": 0},
        "via_stack_2": {"x": 25.5, "y": 0.0, "rotation": 0, "mirror": 0}
    },
    "ports": {
        "e1": "taper_1,e2",
        "e2": "taper_2,e2"
    },
    "name": "straight_heater_metal_simple",
}

This is particularly useful when creating our components and connectivity, because what we can do is instantiate our devices with their corresponding values, and then create our connectivity accordingly. To do this properly from our GDSFactory netlist to hdl21, we can then extract the total SPICE circuit, and convert it to a VLSIR format using the Netlist module. The reason why we can’t use the Netlist package from Dan Fritchman directly is that we need to apply a set of models that translate a particular component instantiation into an electrical model. Because we are not yet doing layout extraction as that requires EM solvers, we need to create some sort of SPICE level assignment based on the provided dictionary.

Note that hdl21 already can implement the port connectivity directly from internal instances, and translate this to our connectivity netlist. This means we only need to iterate to create our instances based on our models into a hdl21 module, then we can easily assign the corresponding values. It is also possible to create the assigned parameters as part of the hdl21 component which would form part of our module. Because the gdsfactory names are compatible with hdl21, then it is fine to create the integration accordingly.

The algorithm can be to:

1. Parse the gdsfactory netlist, assign the electrical ports for the model. Extract all instances and required models from the netlist. 2. Verify that the models have been provided. Each model describes the type of component this is, how many ports it requires and so on. Create a hdl21 top level module for every gdsfactory netlist, this is reasonable as it is composed, and not a generator class. This generates a large amount of instantiated hdl21 modules that are generated from generators. 3. Map the connections to each instance port as part of the instance dictionary. This parses the connectivity in the gdsfactory netlist and connects the ports accordingly.

The connections are a bit more complex. So each of our connections dictionary is in the form:

"connections": {
           "straight_1": {
               "e1": "taper_1,e2",
               "e2": "taper_2,e2"
           },
           "taper_1": {
               "e1": "via_stack_1,e3"
           },
           "taper_2": {
               "e1": "via_stack_2,e1"
           }
       },

We know what our top model ports are. We know our internal instance ports as well, and this will be provided by the model too. For the sake of easiness, we can describe these as hdl21 equivalent InOut or ``Port` `ports and not have to deal with directionality. After instance declaration, and models for each of these components with the corresponding port topology, it is then straightforward to parse the connectivity and implement the network, and extract the SPICE.

Module Contents#

Functions#

gdsfactory_netlist_to_spice_netlist(→ hdl21.Module)

This function converts a GDSFactory electrical netlist into a standard SPICE netlist. It follows the same

construct_hdl21_module(→ hdl21.Module)

This function converts a gdsfactory-spice converted netlist using the component models into a SPICE circuit.

gdsfactory_netlist_to_spice_netlist(gdsfactory_netlist: dict, generators: dict, **kwargs) hdl21.Module[source]#

This function converts a GDSFactory electrical netlist into a standard SPICE netlist. It follows the same principle as the sax circuit composition.

Each GDSFactory netlist has a set of instances, each with a corresponding model, and each instance with a given set of geometrical settings that can be applied to each particular model. We know the type of SPICE model from the instance model we provides.

We know that the gdsfactory has a set of instances, and we can map unique models via sax through our own composition circuit. Write the SPICE component based on the model into a total circuit representation in string from the reshaped gdsfactory dictionary into our own structure.

Parameters:
  • gdsfactory_netlist – GDSFactory netlist

  • generators – Dictionary of Generators

Returns:

hdl21 module or raw SPICE string

construct_hdl21_module(spice_netlist: dict, **kwargs) hdl21.Module[source]#

This function converts a gdsfactory-spice converted netlist using the component models into a SPICE circuit.

Part of the complexity of this function is the multiport nature of some components and models, and assigning the parameters accordingly into the SPICE function. This is because not every SPICE component will be bi-port, and many will have multi-ports and parameters accordingly. Each model can implement the composition into a SPICE circuit, but they depend on a set of parameters that must be set from the instance. Another aspect is that we may want to assign the component ID according to the type of component. However, we can also assign the ID based on the individual instance in the circuit, which is also a reasonable approximation. However, it could be said, that the ideal implementation would be for each component model provided to return the SPICE instance including connectivity except for the ID.

# TODO implement validators