From 7905e9b116ed9d9b0030e4953f4dac3704a3477e Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Sun, 26 Nov 2023 23:57:24 +0530 Subject: [PATCH] feat: added glayout notebook --- .../GLayout_OpAmp/GLayout_OpAmp.ipynb | 671 ++++++++++++++++++ 1 file changed, 671 insertions(+) create mode 100644 ISSCC24/submitted_notebooks/GLayout_OpAmp/GLayout_OpAmp.ipynb diff --git a/ISSCC24/submitted_notebooks/GLayout_OpAmp/GLayout_OpAmp.ipynb b/ISSCC24/submitted_notebooks/GLayout_OpAmp/GLayout_OpAmp.ipynb new file mode 100644 index 00000000..09ca9aec --- /dev/null +++ b/ISSCC24/submitted_notebooks/GLayout_OpAmp/GLayout_OpAmp.ipynb @@ -0,0 +1,671 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "aK2t7aSWNojQ" + }, + "source": [ + "# GLayout: Creating PDK-Agnostic P-Cell Based Chip Layouts in Python\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xjDewsT5Y4lP" + }, + "source": [ + "```\n", + "OpenFASOC Team, November 2023\n", + "SPDX-License-Identifier: Apache-2.0\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L6Ck4z5ujN_k" + }, + "source": [ + "\n", + "|Name|Affiliation| IEEE Member | SSCS Member |\n", + "|:-----------------:|:----------:|:----------:|:----------:|\n", + "| Harsh Khandeparkar| University of Michigan + Indian Institute of Technology Kharagpur | No | No |\n", + "| Anhang Li | University of Michigan | Yes | No |\n", + "| Ali Hammoud | University of Michigan | Yes | No |\n", + "| Ayushman Tripathi | University of Michigan | No | No |\n", + "| Mehdi Saligane (Advisor) | University of Michigan | Yes | Yes |\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-Xp4cEjkeHIx" + }, + "source": [ + "# Introduction\n", + "Welcome!\n", + "This notebook serves as an introduction to the GDSFactory-based layout automation tool **GLayout** and an example two-stage Operational Amplifier (Op-Amp) generator, as a part of [OpenFASoC](https://github.com/idea-fasoc/OpenFASOC).\n", + "\n", + "## GDSFactory\n", + "[GDSFactory](https://gdsfactory.github.io/gdsfactory/index.html) is a Python library for designing integrated circuit layouts in Python and save it directly in the [GDSII](https://en.wikipedia.org/wiki/GDSII) format, and run DRC (Design Rule Checking) and LVS (Layout v/s Schematic) verification, or simulation.\n", + "\n", + "## GLayout\n", + "[GLayout](https://github.com/idea-fasoc/OpenFASOC/blob/main/openfasoc/generators/gdsfactory-gen/glayout/) is a layout automation python package which generates _DRC clean_ circuit layouts and SPICE netlists for any PDK (Process Design Kit). It is composed of two main parts: the _generic PDK framework_, and the _circuit generators_.\n", + "\n", + "The generic PDK framework allows for describing any PDK in a standardized format, defined by the `MappedPDK` class. The generators are Python functions that take as arguments a `MappedPDK` object, and a set of optional layout parameters to produce a DRC (Design Rule Checking) clean layout of a particular circuit design and the pre-PEX (Parasitic Extraction) SPICE netlist, for LVS (Layout v/s Extraction).\n", + "\n", + "The post-PEX netlist can be used for simulating a circuit. The simulation and performance evaluation of multiple design variations can be parallelized on a cloud platform for fast design space exploration. Fig. 1 describes the GLayout workflow.\n", + "\n", + "![workflow](https://i.imgur.com/BA7gY81.png)\n", + "\n", + "(Fig. 1: GLayout Workflow)\n", + "\n", + "### Generators\n", + "Generators in GLayout are Python functions that generate the layout and SPICE netlist for a circuit component. This allows for describing hierarchical and parameterized circuits, or PCells (Parameterized Cells), in Python.\n", + "\n", + "A generator can be a utility generator such as a Via, a primitive PCell such as a MOSFET, or a complex circuit as an Op-Amp.\n", + "\n", + "Generators are PDK-agnostic and hierarchical, and may call other generators. This allows complex components to be composed of simpler components hierarchically. Fig. 2 shows the hierarchical usage of generators in an example Op-Amp design, and Fig. 3 shows the creation of a high-level PCell from a primitive PCell.\n", + "\n", + "The SPICE netlist for a component is also generated hierarchically along with the layout.\n", + "\n", + "![hierarchy](https://i.imgur.com/YC4CXrp.png)\n", + "\n", + "(Fig. 2: Hierarchy of PCells in the Example Op-Amp Design)\n", + "\n", + "![high level pcell construction](https://i.imgur.com/KSgSHla.png)\n", + "\n", + "(Fig. 3: Creation of High-Level PCells from Primitive PCells)\n", + "\n", + "#### List of Generators\n", + "##### Utility Generators\n", + "- Via\n", + "- Guardring\n", + "- Routing (Straight, L, and C)\n", + "\n", + "##### PCell Generators\n", + "- Primitive Cells\n", + " - FET (NMOS, PMOS)\n", + " - MIM Capacitor\n", + "- Intermediate PCells\n", + " - Differential Pair\n", + " - Current Mirror\n", + " - Differential to Single Ended Converter\n", + "\n", + "##### Example Designs\n", + "- Two Stage Operational Amplifier" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Using GLayout\n", + "### 1. Clone the repository and install dependencies\n", + "#### Python Dependencies\n", + "* [`gdsfactory`](https://github.com/gdsfactory/gdsfactory): Provides the backend for GDS manipulation.\n", + "* [`sky130`](https://github.com/gdsfactory/skywater130): The Skywater 130nm PDK Python package for GDSFactory to use in this demo.\n", + "* [`gf180`](https://github.com/gdsfactory/gf180): The GF 180nm PDK Python package for GDSFactory to use in this demo.\n", + "* [`gdstk`](https://heitzmann.github.io/gdstk/): (installed as a part of gdsfactory) Used for converting GDS files into SVG images for viewing.\n", + "* [`svgutils`](https://svgutils.readthedocs.io/en/latest/): To scale the SVG image.\n", + "\n", + "#### System Dependencies\n", + "* [`klayout`](https://klayout.de/): For DRC (Design Rule Checking).\n" + ], + "metadata": { + "id": "j4dNshkgMM4I" + } + }, + { + "cell_type": "code", + "source": [ + "# Clone OpenFASoC\n", + "!git clone https://github.com/idea-fasoc/OpenFASOC\n", + "# Install python dependencies\n", + "!pip install sky130\n", + "!pip install gf180 prettyprinttree svgutils\n", + "!pip install gdsfactory==7.7.0\n", + "\n", + "import pathlib\n", + "import os\n", + "# Install KLayout (via conda)\n", + "!curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\n", + "conda_prefix_path = pathlib.Path('conda-env')\n", + "CONDA_PREFIX = str(conda_prefix_path.resolve())\n", + "%env CONDA_PREFIX={CONDA_PREFIX}\n", + "\n", + "!bin/micromamba create --yes --prefix $CONDA_PREFIX\n", + "# Install from the litex-hub channel\n", + "!bin/micromamba install --yes --prefix $CONDA_PREFIX \\\n", + " --channel litex-hub \\\n", + " --channel main \\\n", + " klayout\n", + "\n", + "# Add conda packages to the PATH\n", + "PATH = os.environ['PATH']\n", + "%env PATH={PATH}:{CONDA_PREFIX}/bin\n", + "\n", + "%cd OpenFASOC/openfasoc/generators/gdsfactory-gen" + ], + "metadata": { + "id": "JzDjayJIMSHe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 2. Basic Usage of the GLayout Framework\n", + "Each generator is a Python function that takes a `MappedPDK` object as a parameter and generates a DRC clean layout for the given PDK. The generator may also accept a set of optional layout parameters such as the width or length of a MOSFET. All parameters are normal Python function arguments.\n", + "\n", + "The generator returns a `GDSFactory.Component` object that can be written to a `.gds` file and viewed using a tool such as Klayout. In this example, the `gdstk` library is used to convert the `.gds` file to an SVG image for viewing.\n", + "\n", + "The pre-PEX SPICE netlist for the component can be viewed using `component.info['netlist'].generate_netlist()`.\n", + "\n", + "In the following example the FET generator `glayout.primitives.fet` is imported and run with both the [Skywater 130](https://skywater-pdk.readthedocs.io/en/main/) and [GF180](https://gf180mcu-pdk.readthedocs.io/en/latest/) PDKs." + ], + "metadata": { + "id": "ozTFXBekORtd" + } + }, + { + "cell_type": "markdown", + "source": [ + "#### Demonstration of Basic Layout / Netlist Generation in SKY130 & GF180" + ], + "metadata": { + "id": "MRjvYFZl6o8z" + } + }, + { + "cell_type": "code", + "source": [ + "from glayout.primitives.fet import nmos\n", + "from glayout.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", + "from glayout.pdk.gf180_mapped import gf180_mapped_pdk as gf180\n", + "import gdstk\n", + "import svgutils.transform as sg\n", + "import IPython.display\n", + "from IPython.display import clear_output\n", + "import ipywidgets as widgets\n", + "\n", + "# Used to display the results in a grid (notebook only)\n", + "left = widgets.Output()\n", + "leftSPICE = widgets.Output()\n", + "right = widgets.Output()\n", + "rightSPICE = widgets.Output()\n", + "hide = widgets.Output()\n", + "\n", + "grid = widgets.GridspecLayout(1, 4)\n", + "grid[0, 0] = left\n", + "grid[0, 1] = leftSPICE\n", + "grid[0, 2] = right\n", + "grid[0, 3] = rightSPICE\n", + "display(grid)\n", + "\n", + "def display_gds(gds_file, scale = 3):\n", + " # Generate an SVG image\n", + " top_level_cell = gdstk.read_gds(gds_file).top_level()[0]\n", + " top_level_cell.write_svg('out.svg')\n", + "\n", + " # Scale the image for displaying\n", + " fig = sg.fromfile('out.svg')\n", + " fig.set_size((str(float(fig.width) * scale), str(float(fig.height) * scale)))\n", + " fig.save('out.svg')\n", + "\n", + " # Display the image\n", + " IPython.display.display(IPython.display.SVG('out.svg'))\n", + "\n", + "def display_component(component, scale = 3):\n", + " # Save to a GDS file\n", + " with hide:\n", + " component.write_gds(\"out.gds\")\n", + "\n", + " display_gds('out.gds', scale)\n", + "\n", + "with hide:\n", + " # Generate the sky130 component\n", + " component_sky130 = nmos(pdk = sky130, fingers=5)\n", + " # Generate the gf180 component\n", + " component_gf180 = nmos(pdk = gf180, fingers=5)\n", + "\n", + "# Display the components' GDS and SPICE netlists\n", + "with left:\n", + " print('Skywater 130nm N-MOSFET (fingers = 5)')\n", + " display_component(component_sky130, scale=2.5)\n", + "with leftSPICE:\n", + " print('Skywater 130nm SPICE Netlist')\n", + " print(component_sky130.info['netlist'].generate_netlist())\n", + "\n", + "with right:\n", + " print('GF 180nm N-MOSFET (fingers = 5)')\n", + " display_component(component_gf180, scale=2)\n", + "with rightSPICE:\n", + " print('GF 180nm SPICE Netlist')\n", + " print(component_gf180.info['netlist'].generate_netlist())" + ], + "metadata": { + "id": "H0xylxwHOeKy" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "#### Interactive Primitive Generation in SKY130\n", + "The following cell demonstrates the different PCell and Utility generators on the Sky130 PDK." + ], + "metadata": { + "id": "YEaPdbyc-rh2" + } + }, + { + "cell_type": "code", + "source": [ + "from glayout.primitives import fet, mimcap, guardring\n", + "from glayout.components import diff_pair\n", + "import ipywidgets as widgets\n", + "\n", + "selection_button = widgets.RadioButtons(\n", + " options=['NMOS', 'PMOS', 'MIM Capacitor', 'Differential Pair', 'Guardring'],\n", + " orientation='horizontal',\n", + " description='Generator:',\n", + " layout=widgets.Layout(position='right')\n", + ")\n", + "generate_button = widgets.Button(description='Generate', disabled=False)\n", + "output = widgets.Output(layout = widgets.Layout(position='left', overflow='visible'))\n", + "hide = widgets.Output()\n", + "\n", + "grid = widgets.GridspecLayout(1, 2)\n", + "grid[0, 0] = widgets.VBox([selection_button, generate_button])\n", + "grid[0, 1] = output\n", + "\n", + "display(grid)\n", + "\n", + "with hide:\n", + " component = fet.nmos(pdk = sky130)\n", + "with output:\n", + " print('NMOS')\n", + " display_component(component)\n", + "\n", + "def generate_component(_):\n", + " selected_comp = selection_button.value\n", + "\n", + " with output:\n", + " clear_output()\n", + " print(f\"Generating {selected_comp}...\")\n", + " with hide:\n", + " match selected_comp:\n", + " case 'NMOS':\n", + " component = fet.nmos(pdk = sky130)\n", + " case 'PMOS':\n", + " component = fet.pmos(pdk = sky130)\n", + " case 'MIM Capacitor':\n", + " component = mimcap.mimcap(pdk = sky130)\n", + " case 'Differential Pair':\n", + " component = diff_pair.diff_pair(pdk = sky130)\n", + " case 'Guardring':\n", + " component = guardring.tapring(pdk = sky130)\n", + " with output:\n", + " clear_output()\n", + " print(selected_comp)\n", + " display_component(component, 3)\n", + "\n", + "generate_button.on_click(generate_component)" + ], + "metadata": { + "id": "DO_cMVFz-mHo" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 3. Tweak the Parameters\n", + "These are some of the parameters the NMOS FET generator accepts:\n", + "* `width`: The gate width of the FET.\n", + "* `length`: The gate length of the FET.\n", + "* `fingers`: The number of fingers. Each finger shares the same source/drain.\n", + "* `multipliers`: Number of multipliers (a multiplier is a row of fingers).\n", + "\n", + "Run the below cell and use the sliders to adjust the parameters." + ], + "metadata": { + "id": "gI9JNwN_fdL1" + } + }, + { + "cell_type": "code", + "source": [ + "# Default Values\n", + "width=3\n", + "length=0.2\n", + "fingers=4\n", + "multipliers=1\n", + "\n", + "# Create sliders\n", + "width_slider = widgets.FloatSlider(description = 'Width:', min = 1, max = 5, step = 0.5, value = width)\n", + "length_slider = widgets.FloatSlider(description = 'Length:', min = 0.2, max = 1, step = 0.1, value = length)\n", + "fingers_slider = widgets.IntSlider(description = 'Fingers:', min = 1, max = 10, value = fingers)\n", + "multipliers_slider = widgets.IntSlider(description = 'Multipliers:', min = 1, max = 5, value = multipliers)\n", + "generate_button = widgets.Button(description='Generate', disabled=False)\n", + "\n", + "inputs_box = widgets.VBox([width_slider, length_slider, fingers_slider, multipliers_slider, generate_button])\n", + "\n", + "output = widgets.Output(layout = widgets.Layout(position='left', overflow='visible'))\n", + "hide = widgets.Output()\n", + "\n", + "grid = widgets.GridspecLayout(1, 2)\n", + "grid[0, 0] = inputs_box\n", + "grid[0, 1] = output\n", + "\n", + "display(grid)\n", + "\n", + "def generate_component(_):\n", + " width = width_slider.value\n", + " length = length_slider.value\n", + " fingers = fingers_slider.value\n", + " multipliers = multipliers_slider.value\n", + "\n", + " with output:\n", + " clear_output()\n", + " print(f\"Generating with width={width}, length={length}, fingers={fingers}, multipliers={multipliers}...\")\n", + " with hide:\n", + " component = component = fet.nmos(pdk = sky130, width = width, length=length, fingers = fingers, multipliers = multipliers)\n", + " with output:\n", + " clear_output()\n", + " print(f\"N-MOSFET with width={width}, length={length}, fingers={fingers}, multipliers={multipliers}:\")\n", + " display_component(component)\n", + "\n", + "generate_component(None)\n", + "\n", + "# Regenerate upon change in value\n", + "generate_button.on_click(generate_component)" + ], + "metadata": { + "id": "-HIs4q1fC-vY" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 4. DRC Checking Using External Tools (KLayout)\n", + "Design Rule Check (DRC) is the process of ensuring that a particular layout does not violate the constraints or _design rules_ imposed by the PDK.\n", + "\n", + "[Klayout](https://klayout.de/) is a GDSII viewer and editor that also has a DRC feature. The design rules for the PDK, in this case the Skywater 130 PDK, are described in a `.lydrc` file.\n", + "\n", + "The following cell runs DRC on the component generated in the previous cell. The number of DRC errors reported will be displayed at the end of the output." + ], + "metadata": { + "id": "g45S96g7BOhr" + } + }, + { + "cell_type": "code", + "source": [ + "!klayout out.gds -zz -r glayout/pdk/sky130_mapped/sky130.lydrc\n", + "!echo -e \"\\n$(grep -c \"\" sky130_drc.txt) DRC Errors Found\"" + ], + "metadata": { + "id": "FSi37vB3GyvR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Complex Circuit Example: Op-Amp\n", + "Using the above generators, complex circuit designs can be created by connecting the components. The function for creating such a design would itself be a generator. For example, differential pair generator uses the FET, Via, and routing generators.\n", + "\n", + "### Design\n", + "One such example circuit is the [Operational Amplifier](https://en.wikipedia.org/wiki/Operational_amplifier) (Op-Amp) defined in the `opamp.py` file. This design consists of a differential pair (input stage), a differential to single-ended converter (load), a common source (CS) gain stage, and an output buffer (for testing, it's not a part of the feedback loop), with an improved split-stage feedback created using a capacitor. The differential pair and the gain and output stages are biased using current mirrors.\n", + "\n", + "Each of the stages, the feedback capacitor, and the biasing circuitry were generated using the exported generators. See the schematic in Fig. 4 for an overview of the circuit. The PCells used (Differential Pair, Current Mirror, etc.) are highlighted with the dotted border.\n", + "\n", + "In Fig. 5(a), a Skywater 130nm layout for the Op-Amp is shown with the different components annotated. The annotated components are marked in the circuit schematic in Fig. 5(b) for the first two stages of the Op-Amp.\n", + "\n", + "![schematic](https://i.imgur.com/PUEPdXE.png)\n", + "\n", + "(Fig. 4: Example Op-Amp Circuit Schematic)\n", + "\n", + "![schemlayout](https://i.imgur.com/W2askiz.png)\n", + "\n", + "(Fig. 5: (a) Sky130 Op-Amp Layout and (b) the Corresponding Circuit Schematic for the First Two Stages of the Op-Amp)\n", + "\n", + "### Parameters\n", + "The Op-Amp generator accepts the following optional parameters:\n", + "- `half_diffpair_params`: A tuple of (width, length, fingers) for the differential pair.\n", + "- `diffpair_bias`: A tuple of (width, length, fingers) for the differential pair bias transistors.\n", + "- `half_common_source_params`: A tuple of (width, length, fingers, multipliers) for the common source PMOS transistor.\n", + "- `half_common_source_bias`: A tuple of (width, length, fingers, multipliers) for the common source bias transistors. The `multipliers` only apply to the mirror transistor, reference transistor has a multiplier of 1.\n", + "- `output_stage_params`: A tuple of (width, length, fingers) for the output stage NMOS transistor.\n", + "- `output_stage_bias`: A tuple of (width, length, fingers) for the output stage bias transistors.\n", + "- `half_pload`: A tuple of (width, length, fingers) for the load (differential to single-ended converter). The `fingers` only apply to the bottom two transistors.\n", + "- `mim_cap_size`: A tuple of (width, length) for individual MIM capacitors.\n", + "- `mim_cap_rows`: The number of rows in the MIM capacitor array.\n", + "- `rmult`: The multiplier for the width of the routes.\n", + "\n", + "These parameters can be changed to generate a very wide range of Op-Amp designs." + ], + "metadata": { + "id": "Qw7Hsyft_NHm" + } + }, + { + "cell_type": "markdown", + "source": [ + "### 1. Generating the Op-Amp\n", + "The cell below generates the Op-Amp with a particular set of parameters and a PDK (Sky130 by default). Change any of the parameters or the PDK set at the beginning of the cell to generate different variations of the Op-Amp." + ], + "metadata": { + "id": "e896CP65iqEY" + } + }, + { + "cell_type": "code", + "source": [ + "from glayout.components.opamp import opamp\n", + "\n", + "# Select which PDK to use\n", + "pdk = sky130\n", + "# pdk = gf180\n", + "\n", + "# Op-Amp Parameters\n", + "half_diffpair_params = (6, 1, 4)\n", + "diffpair_bias = (6, 2, 4)\n", + "half_common_source_params = (7, 1, 10, 3)\n", + "half_common_source_bias = (6, 2, 8, 2)\n", + "output_stage_params = (5, 1, 16)\n", + "output_stage_bias = (6, 2, 4)\n", + "half_pload = (6,1,6)\n", + "mim_cap_size = (12, 12)\n", + "mim_cap_rows = 3\n", + "rmult = 2\n", + "\n", + "hide = widgets.Output()\n", + "\n", + "# Generate the Op-Amp\n", + "print('Generating Op-Amp...')\n", + "with hide:\n", + " component = opamp(pdk, half_diffpair_params, diffpair_bias, half_common_source_params, half_common_source_bias, output_stage_params, output_stage_bias, half_pload, mim_cap_size, mim_cap_rows, rmult)\n", + "\n", + "# Display the Op-Amp\n", + "clear_output()\n", + "display_component(component, 0.5)" + ], + "metadata": { + "id": "qcbCRjQh_c9g" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 2. Sweeping Variations\n", + "The [`sky130_nist_tapeout.py`](https://github.com/idea-fasoc/OpenFASOC/blob/main/openfasoc/generators/gdsfactory-gen/tapeout_and_RL/sky130_nist_tapeout.py) file contains utilities for generating a matrix of Op-Amps with different parameters in the Sky130 PDK, running simulations, and generating statistics. This Python file is documented [here](https://github.com/idea-fasoc/OpenFASOC/blob/main/openfasoc/generators/gdsfactory-gen/tapeout_and_RL/README.md).\n", + "\n", + "In the cell below, an array of different Op-Amp parameters will be generated and a matrix of all the different variations will be created and displayed. Probe pads and \"Nanofab\" micropads are added for layout (See Fig. 6).\n", + "\n", + "The `get_small_parameter_list()` function is used to generate a small list of parameters. In test mode (default), only 2 Op-Amp varations will be generated. Set the `TEST_MODE` variable to `False` to generate 1700+ variations. NOTE: This may take a very long time to run.\n", + "\n", + "The `create_opamp_matrix()` function generates Op-Amps from a given list of parameter values and appends them to a single GDS file for display. The function also adds \"pads\" to the Op-Amp that are used for probing on the physical layout. (See Fig. 6)\n", + "\n", + "![pads](https://i.imgur.com/5YIsYSY.png)\n", + "\n", + "(Fig 6. Pads Added to the Op-Amps in the Matrix)" + ], + "metadata": { + "id": "ayxczg2_lZdH" + } + }, + { + "cell_type": "code", + "source": [ + "%cd tapeout_and_RL\n", + "from sky130_nist_tapeout import *\n", + "\n", + "# Test mode. Set to False to generate 1700+ variations.\n", + "TEST_MODE = True\n", + "TEST_NUM_VARIANTS = 2 # These many variants will be generated if TEST_MODE = True\n", + "\n", + "# Generate parameter list\n", + "parameter_list = get_small_parameter_list()\n", + "\n", + "# Generate the Op-Amp matrix\n", + "create_opamp_matrix(save_dir_name = '.', params = parameter_list, indices = [i for i in range(TEST_NUM_VARIANTS)] if TEST_MODE else None)\n", + "\n", + "# Display the Op-Amp matrix\n", + "display_gds('opamp_matrix.gds', 0.35)" + ], + "metadata": { + "id": "1RlGEAkmyRkL" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 3. PEX and Spice Simulation\n", + "The `brute_force_full_layout_and_PEXsim()` function generates the full layouts for a given list of parameters, runs the post-PEX simulations, and returns the results. [This](https://github.com/idea-fasoc/OpenFASOC/blob/main/openfasoc/generators/gdsfactory-gen/tapeout_and_RL/opamp_perf_eval.sp) SPICE testbench is used for the simulations.\n", + "\n", + "In test mode, only 8 variants of the Op-Amp are simulated. Set `TEST_MODE` to `False` to run simulations for all of the 1700+ variations. NOTE: This may take a very long time to run." + ], + "metadata": { + "id": "AMuWdisV86Qc" + } + }, + { + "cell_type": "code", + "source": [ + "# Test mode. Set to False to simulate the whole 1700+ variations.\n", + "TEST_MODE = True\n", + "\n", + "# Define a set of parameters to test\n", + "params_array = parameter_list[:8] if TEST_MODE else parameter_list\n", + "\n", + "# Run the simulations and get the results\n", + "!rm -r save_gds_by_index # cleans up any previous simulations\n", + "results_array = brute_force_full_layout_and_PEXsim(sky130, params_array)" + ], + "metadata": { + "id": "wKPMRJ4i9qoY" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 4. Generate Statistics and Plot\n", + "The below cell generates a Gain v/s Unity Gain Bandwidth (UGB) plot from the results generated above.\n", + "\n", + "Based on these results, the best variation of the Op-Amp can be chosen for a given user specification. Specifications such as the highest gain or the least power consumption can be targeted.\n", + "\n", + "These results can also be used along with various optimization algorithms to efficiently converge towards the best possible parameters for the given specifications, in a fully automated loop." + ], + "metadata": { + "id": "LxmqcEdFr7_M" + } + }, + { + "cell_type": "code", + "source": [ + "import matplotlib.pyplot as plt\n", + "import matplotlib as mpl\n", + "from matplotlib import colormaps as cm\n", + "cmap = cm.get_cmap('jet')\n", + "\n", + "try:\n", + " params_list_of_dict = [{**opamp_parameters_de_serializer(opparam),**{\"index\":i}} for i,opparam in enumerate(params_array)]\n", + " results_list_of_dict = [{**opamp_results_de_serializer(opresult),**{\"index\":i}} for i,opresult in enumerate(results_array)]\n", + "except:\n", + " params_list_of_dict = [{**opamp_parameters_de_serializer_old(opparam),**{\"index\":i}} for i,opparam in enumerate(params_array)]\n", + " results_list_of_dict = [{**opamp_results_de_serializer_old(opresult),**{\"index\":i}} for i,opresult in enumerate(results_array)]\n", + "\n", + "# ilist is the list of output stage current bias (all of them are the same=93.5uA)\n", + "ugblist = np.array([opresult[\"ugb\"] for opresult in results_list_of_dict])\n", + "gainlist = np.array([opresult[\"dcGain\"] for opresult in results_list_of_dict])\n", + "powerlist = np.array([opresult[\"power\"] for opresult in results_list_of_dict])\n", + "freqlist = ugblist/10**(gainlist/20)\n", + "\n", + "fig, ax = plt.subplots(figsize = (10, 8))\n", + "colorlist = []\n", + "cnorm = mpl.colors.LogNorm(vmin=10e-5,vmax=1e-3)\n", + "sm = mpl.cm.ScalarMappable(cmap=cmap, norm=cnorm)\n", + "\n", + "for i in powerlist:\n", + " colorlist.append(cmap(cnorm(i)))\n", + "ax.scatter(freqlist,gainlist,s=1,alpha=1,c=colorlist)\n", + "plt.xlabel('Frequency ugb / Hz')\n", + "plt.ylabel('DC Gain / dB20')\n", + "ticks=[0.1e-6,1e-6,10e-6,100e-6]\n", + "aspect=60\n", + "cbar = fig.colorbar(sm, orientation='vertical', ax=ax, label='Power')\n", + "ax.set_xscale('log')" + ], + "metadata": { + "id": "Pgv94uUgsGI4" + }, + "execution_count": null, + "outputs": [] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3.9.13 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "397704579725e15f5c7cb49fe5f0341eb7531c82d19f2c29d197e8b64ab5776b" + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file