blob: 5246a6e3ba93cebebc39e4e61553a9e6528123f7 [file] [log] [blame]
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Schematic Generators\n",
"This module covers the basics of writing a schematic generator."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Schematic Generation Flow\n",
"The schematic generator design flow is slightly different than the layout generator design flow. As described in Module 1, BAG copies an existing schematic template in Virtuoso and perform modifications on it in order to generate human-readable schematic instances. The schematic generation flow follows the steps below:\n",
"\n",
"1. Create schematic in Virtuoso.\n",
"2. Import schematic information from Virtuoso to Python.\n",
"3. Implement schematic generator in Python.\n",
"4. Use BAG to create new instances of the schematic."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## CS Amplifier Schematic Generator Example\n",
"Lets walk through the common-source amplifier schematic generator example, reproduced below:\n",
"\n",
"```python\n",
"yaml_file = pkg_resources.resource_filename(__name__, os.path.join('netlist_info', 'amp_cs.yaml'))\n",
"\n",
"class demo_templates__amp_cs(Module):\n",
"\n",
" def __init__(self, bag_config, parent=None, prj=None, **kwargs):\n",
" Module.__init__(self, bag_config, yaml_file, parent=parent, prj=prj, **kwargs)\n",
"\n",
" @classmethod\n",
" def get_params_info(cls):\n",
" return dict(\n",
" lch='channel length in meters.',\n",
" w_dict='Dictionary of transistor widths.',\n",
" intent_dict='Dictionary of transistor threshold flavors.',\n",
" fg_dict='Dictionary of transistor number of fingers.',\n",
" dum_info='Dummy information data structure',\n",
" )\n",
" \n",
" def design(self, lch, w_dict, intent_dict, fg_dict, dum_info):\n",
" # populate self.parameters dictionary\n",
" wp = w_dict['load']\n",
" wn = w_dict['amp']\n",
" intentp = intent_dict['load']\n",
" intentn = intent_dict['amp']\n",
"\n",
" fg_amp = fg_dict['amp']\n",
" fg_load = fg_dict['load']\n",
"\n",
" # set transistor parameters\n",
" self.instances['XP'].design(w=wp, l=lch, intent=intentp, nf=fg_load)\n",
" self.instances['XN'].design(w=wn, l=lch, intent=intentn, nf=fg_amp)\n",
"\n",
" # handle dummy transistors\n",
" self.design_dummy_transistors(dum_info, 'XDUM', 'VDD', 'VSS')\n",
"\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Constructor\n",
"Consider the section below:\n",
"```python\n",
"yaml_file = pkg_resources.resource_filename(__name__, os.path.join('netlist_info', 'amp_cs.yaml'))\n",
"\n",
"class demo_templates__amp_cs(Module):\n",
"\n",
" def __init__(self, bag_config, parent=None, prj=None, **kwargs):\n",
" Module.__init__(self, bag_config, yaml_file, parent=parent, prj=prj, **kwargs)\n",
"```\n",
"First of all, notice the `yaml_file` variable. This variable stores the path to a netlist file that describes instances and connections in the schematic template. This netlist file is generated by BAG when schematic templates are imported from Virtuoso to BAG. This implies that everytime you modify the schematic template, you should re-import the design to BAG in order to update this file.\n",
"\n",
"Then, notice that this class is a subclass of `Module`. Similar to `AnalogBase`, `Module` is the base class of all schematic generators, and it provides many useful functions to modify the schematic template."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parameters information\n",
"Next we have the following class method declaration:\n",
"\n",
"```python\n",
"@classmethod\n",
"def get_params_info(cls):\n",
" return dict(\n",
" lch='channel length in meters.',\n",
" w_dict='Dictionary of transistor widths.',\n",
" intent_dict='Dictionary of transistor threshold flavors.',\n",
" fg_dict='Dictionary of transistor number of fingers.',\n",
" dum_info='Dummy information data structure',\n",
" )\n",
"```\n",
"\n",
"This method serves the same purpose as the method with the same name in layout generators."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The Design Method\n",
"```python\n",
"def design(self, lch, w_dict, intent_dict, fg_dict, dum_info):\n",
"```\n",
"Next we have the `design()` method. Similar to `draw_layout()`, this is where all schematic modification happens. Note that all schematic parameters should be listed as arguments of the `design()` method."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setting Transistor Parameters\n",
"The first several lines of `design()` are quite self-explanatory. Then we have the following:\n",
"\n",
"```python\n",
"# set transistor parameters\n",
"self.instances['XP'].design(w=wp, l=lch, intent=intentp, nf=fg_load)\n",
"self.instances['XN'].design(w=wn, l=lch, intent=intentn, nf=fg_amp)\n",
"```\n",
"All instances in the schematic template will be present in the `self.instances` dictionary, which maps instance names to the corresponding `SchInstance` objects (This is why you should always choose meaningful names for instances in your schematic template). You can modify these instances by called their `design()` method. For `BAG_prim` transistors, their `design()` method takes parameters `w`, `l`, `intent`, and `nf`, which stands for width, length, transistor threshold, and number of fingers, respectively.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dummy transistors\n",
"In the next line we have:\n",
"\n",
"```python\n",
"# handle dummy transistors\n",
"self.design_dummy_transistors(dum_info, 'XDUM', 'VDD', 'VSS')\n",
"```\n",
"Recall that `dum_info` is the dummy transistor data struct computed by AnalogBase. The `design_dummy_transistors()` method will automatically help you create the corresponding dummy transistors in the schematic, by copying and modifying a transistor instance in the schematic template. For example, here it'll copy and modfy the \"XDUM\" transistor instance, and use \"VDD\" as the power supply name, \"VSS\" as the ground supply name."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## SF Schematic Exercise\n",
"Now let's try to create a source-follower schematic generator. Before we start writing generator code, we need to create a schematic template for the source-follower:\n",
"\n",
"1. Open the cellview `demo_templates`/`amp_sf` in Virtuoso.\n",
"\n",
"2. Instantiate non-dummy transistors from the `BAG_prim` library, and create proper connections. Use `nmos4_standard` and `pmos4_standard` as the transistors. Leave the dummy transistor alone.\n",
" * Name the amplifying transistor `XAMP` and the bias transistor `XBIAS`.\n",
"\n",
"3. If you're stuck or you want to check your answer, see the schematic for `demo_templates`/`amp_sf_soln`.\n",
"\n",
"4. After completing the schematic, evaluate the following cell, which will update the netlist associated with `amp_sf`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"creating BagProject\n",
"importing netlist from virtuoso\n",
"netlist import done\n"
]
}
],
"source": [
"import bag\n",
"\n",
"# obtain BagProject instance\n",
"local_dict = locals()\n",
"if 'bprj' in local_dict:\n",
" print('using existing BagProject')\n",
" bprj = local_dict['bprj']\n",
"else:\n",
" print('creating BagProject')\n",
" bprj = bag.BagProject()\n",
" \n",
"print('importing netlist from virtuoso')\n",
"bprj.import_design_library('demo_templates')\n",
"print('netlist import done')"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Implement Schematic Generator\n",
"Now that you finished the schematic template and imported netlist information into BAG, fill in the missing parts of the following schematic generator. After you finished, evaluate the cell below to run the source-follower amplifer through the flow. If everything works properly, LVS should pass, and you should see DC/AC/Transient simulation plots of the source-follower. If you need to change the schematic template in Virtuoso, remember to re-evaluate the cell above to regenerate the netlist file."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"creating BagProject\n",
"computing layout\n",
"ext_w0 = 1, ext_wend=9, tot_ntr=20\n",
"ext_w0 = 2, ext_wend=8, tot_ntr=20\n",
"ext_w0 = 4, ext_wend=9, tot_ntr=21\n",
"final: ext_w0 = 2, ext_wend=8, tot_ntr=20\n",
"creating layout\n",
"layout done\n",
"creating AMP_SF schematics\n",
"running lvs\n",
"Running tasks, Press Ctrl-C to cancel.\n"
]
},
{
"ename": "ValueError",
"evalue": "LVS failed. check log file: /tools/projects/erichang/bag_gen/BAG2_cds_ff_mpt/pvs_run/lvs_run_dir/DEMO_AMP_SF/AMP_SF/lvsLog_20171127_232149rtf5tphj",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-2-f2776ed95ca3>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 89\u001b[0m \u001b[0mbprj\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mbag\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mBagProject\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 90\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 91\u001b[1;33m \u001b[0mdemo_core\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_flow\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbprj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtop_specs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'amp_sf'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mAmpSFSoln\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msch_cls\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdemo_templates__amp_sf\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrun_lvs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m/tools/projects/erichang/bag_gen/BAG2_cds_ff_mpt/BAG_XBase_demo/xbase_demo/core.py\u001b[0m in \u001b[0;36mrun_flow\u001b[1;34m(prj, specs, dsn_name, lay_cls, sch_cls, run_lvs, lvs_only)\u001b[0m\n\u001b[0;32m 375\u001b[0m \u001b[0mdsn_sch_params\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgen_layout\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mprj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mspecs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdsn_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlay_cls\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 376\u001b[0m \u001b[1;31m# generate design/testbench schematics\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 377\u001b[1;33m \u001b[0mgen_schematics\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mprj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mspecs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdsn_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdsn_sch_params\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msch_cls\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0msch_cls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcheck_lvs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mrun_lvs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlvs_only\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mlvs_only\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 378\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 379\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mlvs_only\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;32m/tools/projects/erichang/bag_gen/BAG2_cds_ff_mpt/BAG_XBase_demo/xbase_demo/core.py\u001b[0m in \u001b[0;36mgen_schematics\u001b[1;34m(prj, specs, dsn_name, sch_params, sch_cls, check_lvs, lvs_only)\u001b[0m\n\u001b[0;32m 112\u001b[0m \u001b[0mlvs_passed\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlvs_log\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mprj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_lvs\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimpl_lib\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgen_cell\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 113\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mlvs_passed\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 114\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'LVS failed. check log file: %s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mlvs_log\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 115\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 116\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'lvs passed'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: LVS failed. check log file: /tools/projects/erichang/bag_gen/BAG2_cds_ff_mpt/pvs_run/lvs_run_dir/DEMO_AMP_SF/AMP_SF/lvsLog_20171127_232149rtf5tphj"
]
}
],
"source": [
"%matplotlib inline\n",
"\n",
"import os\n",
"\n",
"from bag.design import Module\n",
"\n",
"\n",
"# noinspection PyPep8Naming\n",
"class demo_templates__amp_sf(Module):\n",
" \"\"\"Module for library demo_templates cell amp_sf.\n",
"\n",
" Fill in high level description here.\n",
" \"\"\"\n",
"\n",
" def __init__(self, bag_config, parent=None, prj=None, **kwargs):\n",
" # hard coded netlist flie path to get jupyter notebook working.\n",
" yaml_file = os.path.join(os.environ['BAG_WORK_DIR'], 'BAG_XBase_demo', \n",
" 'BagModules', 'demo_templates', 'netlist_info', 'amp_sf.yaml') \n",
"\n",
" Module.__init__(self, bag_config, yaml_file, parent=parent, prj=prj, **kwargs)\n",
"\n",
" @classmethod\n",
" def get_params_info(cls):\n",
" return dict(\n",
" lch='channel length in meters.',\n",
" w_dict='Dictionary of transistor widths.',\n",
" intent_dict='Dictionary of transistor threshold flavors.',\n",
" fg_dict='Dictionary of transistor number of fingers.',\n",
" dum_info='Dummy information data structure',\n",
" )\n",
"\n",
" def design(self, lch, w_dict, intent_dict, fg_dict, dum_info):\n",
" w_amp = w_dict['amp']\n",
" w_bias = w_dict['bias']\n",
" intent_amp = intent_dict['amp']\n",
" intent_bias = intent_dict['bias']\n",
" fg_amp = fg_dict['amp']\n",
" fg_bias = fg_dict['bias']\n",
"\n",
" # TODO: design XAMP and XBIAS transistors\n",
" # related code from amp_cs schematic generator are copied below\n",
" # for reference\n",
" # self.instances['XP'].design(w=wp, l=lch, intent=intentp, nf=fg_load)\n",
" # self.instances['XN'].design(w=wn, l=lch, intent=intentn, nf=fg_amp)\n",
"\n",
" # handle dummy transistors\n",
" self.design_dummy_transistors(dum_info, 'XDUM', 'VDD', 'VSS')\n",
"\n",
" \n",
"import os\n",
"\n",
"# import bag package\n",
"import bag\n",
"from bag.io import read_yaml\n",
"\n",
"# import BAG demo Python modules\n",
"import xbase_demo.core as demo_core\n",
"from xbase_demo.demo_layout.core import AmpSFSoln\n",
"\n",
"# load circuit specifications from file\n",
"spec_fname = os.path.join(os.environ['BAG_WORK_DIR'], 'specs_demo/demo.yaml')\n",
"top_specs = read_yaml(spec_fname)\n",
"\n",
"# obtain BagProject instance\n",
"local_dict = locals()\n",
"if 'bprj' in local_dict:\n",
" print('using existing BagProject')\n",
" bprj = local_dict['bprj']\n",
"else:\n",
" print('creating BagProject')\n",
" bprj = bag.BagProject()\n",
"\n",
"demo_core.run_flow(bprj, top_specs, 'amp_sf', AmpSFSoln, sch_cls=demo_templates__amp_sf, run_lvs=True)"
]
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
}
},
"nbformat": 4,
"nbformat_minor": 1
}