blob: 5f88586302caa15279a26a929968bf26ecd74169 [file] [log] [blame]
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Module 5: Hierarchical Generators\n",
"This module covers writing layout/schematic generators that instantiate other generators. We will write a two-stage amplifier generator, which instatiates the common-source amplifier followed by the source-follower amplifier."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## AmpChain Layout Example\n",
"First, we will write a layout generator for the two-stage amplifier. The layout floorplan is drawn for you below:\n",
"<img src=\"bootcamp_pics/5_hierarchical_generator/hierachical_generator_1.PNG\" alt=\"Drawing\" style=\"width: 400px;\"/>\n",
"This floorplan abuts the `AmpCS` instance next to `AmpSF` instance, the `VSS` ports are simply shorted together, and the top `VSS` port of `AmpSF` is ignored (they are connected together internally by dummy connections). The intermediate node of the two-stage amplifier is connected using a vertical routing track in the middle of the two amplifier blocks. `VDD` ports are connected to the top-most M6 horizontal track, and other ports are simply exported in-place.\n",
"\n",
"The layout generator is reproduced below, with some parts missing (which you will fill out later). We will walk through the important sections of the code.\n",
"```python\n",
"class AmpChain(TemplateBase):\n",
" def __init__(self, temp_db, lib_name, params, used_names, **kwargs):\n",
" TemplateBase.__init__(self, temp_db, lib_name, params, used_names, **kwargs)\n",
" self._sch_params = None\n",
"\n",
" @property\n",
" def sch_params(self):\n",
" return self._sch_params\n",
"\n",
" @classmethod\n",
" def get_params_info(cls):\n",
" return dict(\n",
" cs_params='common source amplifier parameters.',\n",
" sf_params='source follower parameters.',\n",
" show_pins='True to draw pin geometries.',\n",
" )\n",
"\n",
" def draw_layout(self):\n",
" \"\"\"Draw the layout of a transistor for characterization.\n",
" \"\"\"\n",
"\n",
" # make copies of given dictionaries to avoid modifying external data.\n",
" cs_params = self.params['cs_params'].copy()\n",
" sf_params = self.params['sf_params'].copy()\n",
" show_pins = self.params['show_pins']\n",
"\n",
" # disable pins in subcells\n",
" cs_params['show_pins'] = False\n",
" sf_params['show_pins'] = False\n",
"\n",
" # create layout masters for subcells we will add later\n",
" cs_master = self.new_template(params=cs_params, temp_cls=AmpCS)\n",
" # TODO: create sf_master. Use AmpSFSoln class\n",
" sf_master = None\n",
"\n",
" if sf_master is None:\n",
" return\n",
"\n",
" # add subcell instances\n",
" cs_inst = self.add_instance(cs_master, 'XCS')\n",
" # add source follower to the right of common source\n",
" x0 = cs_inst.bound_box.right_unit\n",
" sf_inst = self.add_instance(sf_master, 'XSF', loc=(x0, 0), unit_mode=True)\n",
"\n",
" # get VSS wires from AmpCS/AmpSF\n",
" cs_vss_warr = cs_inst.get_all_port_pins('VSS')[0]\n",
" sf_vss_warrs = sf_inst.get_all_port_pins('VSS')\n",
" # only connect bottom VSS wire of source follower\n",
" if sf_vss_warrs[0].track_id.base_index < sf_vss_warrs[1].track_id.base_index:\n",
" sf_vss_warr = sf_vss_warrs[0]\n",
" else:\n",
" sf_vss_warr = sf_vss_warrs[1]\n",
"\n",
" # connect VSS of the two blocks together\n",
" vss = self.connect_wires([cs_vss_warr, sf_vss_warr])[0]\n",
"\n",
" # get layer IDs from VSS wire\n",
" hm_layer = vss.layer_id\n",
" vm_layer = hm_layer + 1\n",
" top_layer = vm_layer + 1\n",
"\n",
" # calculate template size\n",
" tot_box = cs_inst.bound_box.merge(sf_inst.bound_box)\n",
" self.set_size_from_bound_box(top_layer, tot_box, round_up=True)\n",
"\n",
" # get subcell ports as WireArrays so we can connect them\n",
" vmid0 = cs_inst.get_all_port_pins('vout')[0]\n",
" vmid1 = sf_inst.get_all_port_pins('vin')[0]\n",
" vdd0 = cs_inst.get_all_port_pins('VDD')[0]\n",
" vdd1 = sf_inst.get_all_port_pins('VDD')[0]\n",
"\n",
" # get vertical VDD TrackIDs\n",
" vdd0_tid = TrackID(vm_layer, self.grid.coord_to_nearest_track(vm_layer, vdd0.middle))\n",
" vdd1_tid = TrackID(vm_layer, self.grid.coord_to_nearest_track(vm_layer, vdd1.middle))\n",
"\n",
" # connect VDD of each block to vertical M5\n",
" vdd0 = self.connect_to_tracks(vdd0, vdd0_tid)\n",
" vdd1 = self.connect_to_tracks(vdd1, vdd1_tid)\n",
" # connect M5 VDD to top M6 horizontal track\n",
" vdd_tidx = self.grid.get_num_tracks(self.size, top_layer) - 1\n",
" vdd_tid = TrackID(top_layer, vdd_tidx)\n",
" vdd = self.connect_to_tracks([vdd0, vdd1], vdd_tid)\n",
"\n",
" # TODO: connect vmid0 and vmid1 to vertical track in the middle of two templates\n",
" # hint: use x0\n",
" vmid = None\n",
"\n",
" if vmid is None:\n",
" return\n",
"\n",
" # add pins on wires\n",
" self.add_pin('vmid', vmid, show=show_pins)\n",
" self.add_pin('VDD', vdd, show=show_pins)\n",
" self.add_pin('VSS', vss, show=show_pins)\n",
" # re-export pins on subcells.\n",
" self.reexport(cs_inst.get_port('vin'), show=show_pins)\n",
" self.reexport(cs_inst.get_port('vbias'), net_name='vb1', show=show_pins)\n",
" # TODO: reexport vout and vbias of source follower\n",
" # TODO: vbias should be renamed to vb2\n",
"\n",
" # compute schematic parameters.\n",
" self._sch_params = dict(\n",
" cs_params=cs_master.sch_params,\n",
" sf_params=sf_master.sch_params,\n",
" )\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## AmpChain Constructor\n",
"```python\n",
"class AmpChain(TemplateBase):\n",
" def __init__(self, temp_db, lib_name, params, used_names, **kwargs):\n",
" TemplateBase.__init__(self, temp_db, lib_name, params, used_names, **kwargs)\n",
" self._sch_params = None\n",
"\n",
" @property\n",
" def sch_params(self):\n",
" return self._sch_params\n",
"\n",
" @classmethod\n",
" def get_params_info(cls):\n",
" return dict(\n",
" cs_params='common source amplifier parameters.',\n",
" sf_params='source follower parameters.',\n",
" show_pins='True to draw pin geometries.',\n",
" )\n",
"```\n",
"First, notice that instead of subclassing `AnalogBase`, the `AmpChain` class subclasses `TemplateBase`. This is because we are not trying to draw transistor rows inside this layout generator; we just want to place and route multiple layout instances together. `TemplateBase` is the base class for all layout generators and it provides most placement and routing methods you need.\n",
"\n",
"Next, notice that the parameters for `AmpChain` are simply parameter dictionaries for the two sub-generators. The ability to use complex data structures as generator parameters solves the parameter explosion problem when writing generators with many levels of hierarchy."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Creating Layout Master\n",
"```python\n",
"# create layout masters for subcells we will add later\n",
"cs_master = self.new_template(params=cs_params, temp_cls=AmpCS)\n",
"# TODO: create sf_master. Use AmpSFSoln class\n",
"sf_master = None\n",
"```\n",
"Here, the `new_template()` function creates a new layout master, `cs_master`, which represents a generated layout cellview from the `AmpCS` layout generator. We can later instances of this master in the current layout, which are references to the generated `AmpCS` layout cellview, perhaps shifted and rotated. The main take away is that the `new_template()` function does not add any layout geometries to the current layout, but rather create a separate layout cellview which we may use later."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Creating Layout Instance\n",
"```python\n",
"# add subcell instances\n",
"cs_inst = self.add_instance(cs_master, 'XCS')\n",
"# add source follower to the right of common source\n",
"x0 = cs_inst.bound_box.right_unit\n",
"sf_inst = self.add_instance(sf_master, 'XSF', loc=(x0, 0), unit_mode=True)\n",
"```\n",
"\n",
"The `add_instance()` method adds an instance of the given layout master to the current cellview. By default, if no location or orientation is given, it puts the instance at the origin with no rotation. the `bound_box` attribute can then be used on the instance to get the bounding box of the instance. Here, the bounding box is used to determine the X coordinate of the source-follower."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Get Instance Ports\n",
"```python\n",
"# get subcell ports as WireArrays so we can connect them\n",
"vmid0 = cs_inst.get_all_port_pins('vout')[0]\n",
"vmid1 = sf_inst.get_all_port_pins('vin')[0]\n",
"vdd0 = cs_inst.get_all_port_pins('VDD')[0]\n",
"vdd1 = sf_inst.get_all_port_pins('VDD')[0]\n",
"```\n",
"after adding an instance, the `get_all_port_pins()` function can be used to obtain a list of all pins as `WireArray` objects with the given name. In this case, we know that there's exactly one pin, so we use Python list indexing to obtain first element of the list."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Routing Grid Object\n",
"```python\n",
"# get vertical VDD TrackIDs\n",
"vdd0_tid = TrackID(vm_layer, self.grid.coord_to_nearest_track(vm_layer, vdd0.middle))\n",
"vdd1_tid = TrackID(vm_layer, self.grid.coord_to_nearest_track(vm_layer, vdd1.middle))\n",
"```\n",
"\n",
"the `self.grid` attribute of `TemplateBase` is a `RoutingGrid` objects, which provides many useful functions related to the routing grid. In this particular scenario, `coord_to_nearest_track()` is used to determine the vertical track index closest to the center of the `VDD` ports. These vertical tracks will be used later to connect the `VDD` ports together."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Re-export Pins on Instances\n",
"```python\n",
" # re-export pins on subcells.\n",
"self.reexport(cs_inst.get_port('vin'), show=show_pins)\n",
"self.reexport(cs_inst.get_port('vbias'), net_name='vb1', show=show_pins)\n",
"# TODO: reexport vout and vbias of source follower\n",
"# TODO: vbias should be renamed to vb2\n",
"```\n",
"`TemplateBase` also provides a `reexport()` function, which is a convenience function to re-export an instance port in-place. The `net_name` optional parameter can be used to change the port name. In this example, the `vbias` port of common-source amplifier is renamed to `vb1`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Layout Exercises\n",
"Now you should know everything you need to finish the two-stage amplifier layout generator. Fill in the missing pieces to do the following:\n",
"\n",
"1. Create layout master for `AmpSF` using the `AmpSFSoln` class.\n",
"2. Using `RoutingGrid`, determine the vertical track index in the middle of the two amplifier blocks, and connect `vmid` wires together using this track.\n",
" * Hint: variable `x0` is the X coordinate of the boundary between the two blocks.\n",
"3. Re-export `vout` and `vbias` of the source-follower. Rename `vbias` to `vb2`.\n",
"\n",
"Once you're done, evaluate the cell below, which will generate the layout and run LVS. If everything is done correctly, a layout should be generated inthe `DEMO_AMP_CHAIN` library, and LVS should pass."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"creating BagProject\n",
"computing layout\n",
"ext_w0 = 1, ext_wend=6, tot_ntr=19\n",
"ext_w0 = 2, ext_wend=2, tot_ntr=18\n",
"final: ext_w0 = 2, ext_wend=2, tot_ntr=18\n",
"{'s': WireArray(TrackID(layer=3, track=7, num=9, pitch=2), 0.981, 1.136), 'd': WireArray(TrackID(layer=3, track=8, num=8, pitch=2), 1.168, 1.323), 'g': WireArray(TrackID(layer=3, track=8, num=8, pitch=2), 0.791, 0.946)}\n",
"WireArray(TrackID(layer=3, track=8, num=8, pitch=2), 0.791, 0.946)\n",
"5.5\n",
"creating layout\n",
"layout done\n",
"computing AMP_CHAIN schematics\n"
]
},
{
"ename": "TypeError",
"evalue": "design() argument after ** must be a mapping, not NoneType",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-1-f7e0f1af5c7e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 134\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 135\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 136\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_chain_soln'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mAmpChain\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[0mlvs_only\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 99\u001b[0m \u001b[0mdsn\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mprj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcreate_design_module\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msch_lib\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msch_cell\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 100\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'computing %s schematics'\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[1;32m--> 101\u001b[1;33m \u001b[0mdsn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdesign\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0msch_params\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 102\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 103\u001b[0m \u001b[0mdsn\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mprj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnew_schematic_instance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlib_name\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0msch_lib\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcell_name\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0msch_cell\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0msch_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[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mTypeError\u001b[0m: design() argument after ** must be a mapping, not NoneType"
]
}
],
"source": [
"from bag.layout.routing import TrackID\n",
"from bag.layout.template import TemplateBase\n",
"\n",
"from xbase_demo.demo_layout.core import AmpCS, AmpSFSoln\n",
"\n",
"\n",
"class AmpChain(TemplateBase):\n",
" def __init__(self, temp_db, lib_name, params, used_names, **kwargs):\n",
" TemplateBase.__init__(self, temp_db, lib_name, params, used_names, **kwargs)\n",
" self._sch_params = None\n",
"\n",
" @property\n",
" def sch_params(self):\n",
" return self._sch_params\n",
"\n",
" @classmethod\n",
" def get_params_info(cls):\n",
" return dict(\n",
" cs_params='common source amplifier parameters.',\n",
" sf_params='source follower parameters.',\n",
" show_pins='True to draw pin geometries.',\n",
" )\n",
"\n",
" def draw_layout(self):\n",
" \"\"\"Draw the layout of a transistor for characterization.\n",
" \"\"\"\n",
"\n",
" # make copies of given dictionaries to avoid modifying external data.\n",
" cs_params = self.params['cs_params'].copy()\n",
" sf_params = self.params['sf_params'].copy()\n",
" show_pins = self.params['show_pins']\n",
"\n",
" # disable pins in subcells\n",
" cs_params['show_pins'] = False\n",
" sf_params['show_pins'] = False\n",
"\n",
" # create layout masters for subcells we will add later\n",
" cs_master = self.new_template(params=cs_params, temp_cls=AmpCS)\n",
" # TODO: create sf_master. Use AmpSFSoln class\n",
" sf_master = None\n",
"\n",
" if sf_master is None:\n",
" return\n",
"\n",
" # add subcell instances\n",
" cs_inst = self.add_instance(cs_master, 'XCS')\n",
" # add source follower to the right of common source\n",
" x0 = cs_inst.bound_box.right_unit\n",
" sf_inst = self.add_instance(sf_master, 'XSF', loc=(x0, 0), unit_mode=True)\n",
"\n",
" # get VSS wires from AmpCS/AmpSF\n",
" cs_vss_warr = cs_inst.get_all_port_pins('VSS')[0]\n",
" sf_vss_warrs = sf_inst.get_all_port_pins('VSS')\n",
" # only connect bottom VSS wire of source follower\n",
" if len(sf_vss_warrs) < 2 or sf_vss_warrs[0].track_id.base_index < sf_vss_warrs[1].track_id.base_index:\n",
" sf_vss_warr = sf_vss_warrs[0]\n",
" else:\n",
" sf_vss_warr = sf_vss_warrs[1]\n",
"\n",
" # connect VSS of the two blocks together\n",
" vss = self.connect_wires([cs_vss_warr, sf_vss_warr])[0]\n",
"\n",
" # get layer IDs from VSS wire\n",
" hm_layer = vss.layer_id\n",
" vm_layer = hm_layer + 1\n",
" top_layer = vm_layer + 1\n",
"\n",
" # calculate template size\n",
" tot_box = cs_inst.bound_box.merge(sf_inst.bound_box)\n",
" self.set_size_from_bound_box(top_layer, tot_box, round_up=True)\n",
"\n",
" # get subcell ports as WireArrays so we can connect them\n",
" vmid0 = cs_inst.get_all_port_pins('vout')[0]\n",
" vmid1 = sf_inst.get_all_port_pins('vin')[0]\n",
" vdd0 = cs_inst.get_all_port_pins('VDD')[0]\n",
" vdd1 = sf_inst.get_all_port_pins('VDD')[0]\n",
"\n",
" # get vertical VDD TrackIDs\n",
" vdd0_tid = TrackID(vm_layer, self.grid.coord_to_nearest_track(vm_layer, vdd0.middle))\n",
" vdd1_tid = TrackID(vm_layer, self.grid.coord_to_nearest_track(vm_layer, vdd1.middle))\n",
"\n",
" # connect VDD of each block to vertical M5\n",
" vdd0 = self.connect_to_tracks(vdd0, vdd0_tid)\n",
" vdd1 = self.connect_to_tracks(vdd1, vdd1_tid)\n",
" # connect M5 VDD to top M6 horizontal track\n",
" vdd_tidx = self.grid.get_num_tracks(self.size, top_layer) - 1\n",
" vdd_tid = TrackID(top_layer, vdd_tidx)\n",
" vdd = self.connect_to_tracks([vdd0, vdd1], vdd_tid)\n",
"\n",
" # TODO: connect vmid0 and vmid1 to vertical track in the middle of two templates\n",
" # hint: use x0\n",
" vmid = None\n",
"\n",
" if vmid is None:\n",
" return\n",
"\n",
" # add pins on wires\n",
" self.add_pin('vmid', vmid, show=show_pins)\n",
" self.add_pin('VDD', vdd, show=show_pins)\n",
" self.add_pin('VSS', vss, show=show_pins)\n",
" # re-export pins on subcells.\n",
" self.reexport(cs_inst.get_port('vin'), show=show_pins)\n",
" self.reexport(cs_inst.get_port('vbias'), net_name='vb1', show=show_pins)\n",
" # TODO: reexport vout and vbias of source follower\n",
" # TODO: vbias should be renamed to vb2\n",
"\n",
" # compute schematic parameters.\n",
" self._sch_params = dict(\n",
" cs_params=cs_master.sch_params,\n",
" sf_params=sf_master.sch_params,\n",
" )\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",
"\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_chain_soln', AmpChain, run_lvs=True, lvs_only=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## AmpChain Schematic Template\n",
"Now let's move on to schematic generator. As before, we need to create the schematic template first. A half-complete schematic template is provided for you in library `demo_templates`, cell `amp_chain`, shown below:\n",
"<img src=\"bootcamp_pics/5_hierarchical_generator/hierachical_generator_2.PNG\" alt=\"Drawing\" style=\"width: 400px;\"/>\n",
"\n",
"The schematic template for a hierarchical generator is very simple; you simply need to instantiate the schematic templates of the sub-blocks (***Not the generated schematic!***). For the exercise, instantiate the `amp_sf` schematic template from the `demo_templates` library, named it `XSF`, connect it, then evaluate the following cell to import the `amp_chain` netlist to Python.\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"using existing 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": {},
"source": [
"## AmpChain Schematic Generator\n",
"With schematic template done, you are ready to write the schematic generator. It is also very simple, you just need to call the `design()` method, which you implemented previously, on each instance in the schematic. Complete the following schematic generator, then evaluate the cell to push it through the design flow."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"using existing BagProject\n",
"computing layout\n",
"ext_w0 = 1, ext_wend=6, tot_ntr=19\n",
"ext_w0 = 2, ext_wend=2, tot_ntr=18\n",
"final: ext_w0 = 2, ext_wend=2, tot_ntr=18\n",
"{'s': WireArray(TrackID(layer=3, track=7, num=9, pitch=2), 0.981, 1.136), 'd': WireArray(TrackID(layer=3, track=8, num=8, pitch=2), 1.168, 1.323), 'g': WireArray(TrackID(layer=3, track=8, num=8, pitch=2), 0.791, 0.946)}\n",
"WireArray(TrackID(layer=3, track=8, num=8, pitch=2), 0.791, 0.946)\n",
"5.5\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_CHAIN 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_CHAIN/AMP_CHAIN/lvsLog_20171128_0009272slvfabd",
"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-84e11b8fc0cb>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 61\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 62\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 63\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_chain'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mAmpChainSoln\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msch_cls\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdemo_templates__amp_chain\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_CHAIN/AMP_CHAIN/lvsLog_20171128_0009272slvfabd"
]
}
],
"source": [
"%matplotlib inline\n",
"\n",
"import os\n",
"\n",
"from bag.design import Module\n",
"\n",
"\n",
"# noinspection PyPep8Naming\n",
"class demo_templates__amp_chain(Module):\n",
" \"\"\"Module for library demo_templates cell amp_chain.\n",
"\n",
" Fill in high level description here.\n",
" \"\"\"\n",
"\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_chain.yaml') \n",
"\n",
" def __init__(self, bag_config, parent=None, prj=None, **kwargs):\n",
" Module.__init__(self, bag_config, self.yaml_file, parent=parent, prj=prj, **kwargs)\n",
"\n",
" @classmethod\n",
" def get_params_info(cls):\n",
" # type: () -> Dict[str, str]\n",
" \"\"\"Returns a dictionary from parameter names to descriptions.\n",
"\n",
" Returns\n",
" -------\n",
" param_info : Optional[Dict[str, str]]\n",
" dictionary from parameter names to descriptions.\n",
" \"\"\"\n",
" return dict(\n",
" cs_params='common-source amplifier parameters dictionary.',\n",
" sf_params='source-follwer amplifier parameters dictionary.',\n",
" )\n",
" \n",
" def design(self, cs_params=None, sf_params=None):\n",
" self.instances['XCS'].design(**cs_params)\n",
" # TODO: design XSF\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 AmpChainSoln\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_chain', AmpChainSoln, sch_cls=demo_templates__amp_chain, 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
}