From c96a6d0b9d9d7d5d5461b11592fac0ad2a2feaee Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 11 May 2020 16:22:08 -0700 Subject: [PATCH] Add no well option. Add stack gates vertical option. --- compiler/pgates/pand2.py | 80 +++++++++++++++++++++++++------- compiler/pgates/pand3.py | 76 ++++++++++++++++++++++++------ compiler/pgates/pbuf.py | 3 +- compiler/pgates/pdriver.py | 5 +- compiler/pgates/pgate.py | 18 +++++-- compiler/pgates/pinv.py | 7 +-- compiler/pgates/pnand2.py | 9 ++-- compiler/pgates/pnand3.py | 7 +-- compiler/pgates/pnor2.py | 11 +++-- compiler/tests/04_pand2_test.py | 4 ++ compiler/tests/04_pand3_test.py | 4 ++ compiler/tests/04_pnand2_test.py | 5 ++ compiler/tests/04_pnand3_test.py | 5 ++ compiler/tests/04_pnor2_test.py | 4 ++ 14 files changed, 187 insertions(+), 51 deletions(-) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 69af1e62..6df877fd 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -15,14 +15,14 @@ class pand2(pgate.pgate): """ This is a simple buffer used for driving loads. """ - def __init__(self, name, size=1, height=None): - debug.info(1, "Creating pnand2 {}".format(name)) + def __init__(self, name, size=1, height=None, vertical=False): + debug.info(1, "Creating pand2 {}".format(name)) self.add_comment("size: {}".format(size)) - + + self.vertical = vertical self.size = size - - # Creates the netlist and layout - pgate.pgate.__init__(self, name, height) + + pgate.pgate.__init__(self, name) def create_netlist(self): self.add_pins() @@ -30,17 +30,22 @@ class pand2(pgate.pgate): self.create_insts() def create_modules(self): - self.nand = factory.create(module_type="pnand2", height=self.height) + self.nand = factory.create(module_type="pnand2", + height=self.height) self.add_mod(self.nand) self.inv = factory.create(module_type="pdriver", - neg_polarity=True, - fanout=self.size, + size_list=[self.size], height=self.height) self.add_mod(self.inv) def create_layout(self): - self.width = self.nand.width + self.inv.width + if self.vertical: + self.height = 2 * self.nand.height + self.width = max(self.nand.width, self.inv.width) + else: + self.width = self.nand.width + self.inv.width + self.place_insts() self.add_wires() self.add_layout_pins() @@ -68,17 +73,60 @@ class pand2(pgate.pgate): # Add NAND to the right self.nand_inst.place(offset=vector(0, 0)) - # Add INV to the right - self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0)) + if self.vertical: + # Add INV above + self.inv_inst.place(offset=vector(self.inv.width, + 2 * self.nand.height), + mirror="XY") + else: + # Add INV to the right + self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0)) + + def route_supply_rails(self): + """ Add vdd/gnd rails to the top, (middle), and bottom. """ + self.add_layout_pin_rect_center(text="gnd", + layer=self.route_layer, + offset=vector(0.5 * self.width, 0), + width=self.width) + + # Second gnd of the inverter gate + if self.vertical: + self.add_layout_pin_rect_center(text="gnd", + layer=self.route_layer, + offset=vector(0.5 * self.width, self.height), + width=self.width) + if self.vertical: + # Shared between two gates + y_offset = 0.5 * self.height + else: + y_offset = self.height + self.add_layout_pin_rect_center(text="vdd", + layer=self.route_layer, + offset=vector(0.5 * self.width, y_offset), + width=self.width) + def add_wires(self): # nand Z to inv A z1_pin = self.nand_inst.get_pin("Z") a2_pin = self.inv_inst.get_pin("A") - mid1_point = vector(0.5 * (z1_pin.cx() + a2_pin.cx()), z1_pin.cy()) - mid2_point = vector(mid1_point, a2_pin.cy()) - self.add_path(self.route_layer, - [z1_pin.center(), mid1_point, mid2_point, a2_pin.center()]) + if self.vertical: + route_layer = "m2" + self.add_via_stack_center(offset=z1_pin.center(), + from_layer=z1_pin.layer, + to_layer=route_layer) + self.add_zjog(route_layer, + z1_pin.uc(), + a2_pin.bc(), + "V") + self.add_via_stack_center(offset=a2_pin.center(), + from_layer=a2_pin.layer, + to_layer=route_layer) + else: + route_layer = self.route_layer + mid1_point = vector(z1_pin.cx(), a2_pin.cy()) + self.add_path(route_layer, + [z1_pin.center(), mid1_point, a2_pin.center()]) def add_layout_pins(self): pin = self.inv_inst.get_pin("Z") diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py index 841ac69d..5e2e83f8 100644 --- a/compiler/pgates/pand3.py +++ b/compiler/pgates/pand3.py @@ -15,10 +15,11 @@ class pand3(pgate.pgate): """ This is a simple buffer used for driving loads. """ - def __init__(self, name, size=1, height=None): + def __init__(self, name, size=1, height=None, vertical=False): debug.info(1, "Creating pand3 {}".format(name)) self.add_comment("size: {}".format(size)) - + + self.vertical = vertical self.size = size # Creates the netlist and layout @@ -31,16 +32,22 @@ class pand3(pgate.pgate): def create_modules(self): # Shield the cap, but have at least a stage effort of 4 - self.nand = factory.create(module_type="pnand3", height=self.height) + self.nand = factory.create(module_type="pnand3", + height=self.height) self.add_mod(self.nand) - self.inv = factory.create(module_type="pinv", - size=self.size, + self.inv = factory.create(module_type="pdriver", + size_list=[self.size], height=self.height) self.add_mod(self.inv) def create_layout(self): - self.width = self.nand.width + self.inv.width + if self.vertical: + self.height = 2 * self.nand.height + self.width = max(self.nand.width, self.inv.width) + else: + self.width = self.nand.width + self.inv.width + self.place_insts() self.add_wires() self.add_layout_pins() @@ -69,18 +76,61 @@ class pand3(pgate.pgate): # Add NAND to the right self.nand_inst.place(offset=vector(0, 0)) - # Add INV to the right - self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0)) + if self.vertical: + # Add INV above + self.inv_inst.place(offset=vector(self.inv.width, + 2 * self.nand.height), + mirror="XY") + else: + # Add INV to the right + self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0)) + + def route_supply_rails(self): + """ Add vdd/gnd rails to the top, (middle), and bottom. """ + self.add_layout_pin_rect_center(text="gnd", + layer=self.route_layer, + offset=vector(0.5 * self.width, 0), + width=self.width) + + # Second gnd of the inverter gate + if self.vertical: + self.add_layout_pin_rect_center(text="gnd", + layer=self.route_layer, + offset=vector(0.5 * self.width, self.height), + width=self.width) + if self.vertical: + # Shared between two gates + y_offset = 0.5 * self.height + else: + y_offset = self.height + self.add_layout_pin_rect_center(text="vdd", + layer=self.route_layer, + offset=vector(0.5 * self.width, y_offset), + width=self.width) + def add_wires(self): # nand Z to inv A z1_pin = self.nand_inst.get_pin("Z") a2_pin = self.inv_inst.get_pin("A") - mid1_point = vector(0.5 * (z1_pin.cx()+a2_pin.cx()), z1_pin.cy()) - mid2_point = vector(mid1_point, a2_pin.cy()) - self.add_path(z1_pin.layer, - [z1_pin.center(), mid1_point, mid2_point, a2_pin.center()]) - + if self.vertical: + route_layer = "m2" + self.add_via_stack_center(offset=z1_pin.center(), + from_layer=z1_pin.layer, + to_layer=route_layer) + self.add_zjog(route_layer, + z1_pin.uc(), + a2_pin.bc(), + "V") + self.add_via_stack_center(offset=a2_pin.center(), + from_layer=a2_pin.layer, + to_layer=route_layer) + else: + route_layer = self.route_layer + mid1_point = vector(z1_pin.cx(), a2_pin.cy()) + self.add_path(route_layer, + [z1_pin.center(), mid1_point, a2_pin.center()]) + def add_layout_pins(self): pin = self.inv_inst.get_pin("Z") self.add_layout_pin_rect_center(text="Z", diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 4d90286d..8b9c4eab 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -56,7 +56,8 @@ class pbuf(pgate.pgate): self.inv2 = factory.create(module_type="pinv", size=self.size, - height=self.height) + height=self.height, + add_wells=False) self.add_mod(self.inv2) def create_insts(self): diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 9bba7aee..b36d3e95 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -87,10 +87,13 @@ class pdriver(pgate.pgate): def add_modules(self): self.inv_list = [] + add_well = True for size in self.size_list: temp_inv = factory.create(module_type="pinv", size=size, - height=self.height) + height=self.height, + add_wells=add_well) + add_well=False self.inv_list.append(temp_inv) self.add_mod(temp_inv) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 5351be07..be317f48 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -24,7 +24,7 @@ class pgate(design.design): functions for parameterized gates. """ - def __init__(self, name, height=None): + def __init__(self, name, height=None, add_wells=True): """ Creates a generic cell """ design.design.__init__(self, name) @@ -33,7 +33,8 @@ class pgate(design.design): elif not height: # By default, something simple self.height = 14 * self.m1_pitch - + self.add_wells = add_wells + if "li" in layer: self.route_layer = "li" else: @@ -150,7 +151,7 @@ class pgate(design.design): # This should match the cells in the cell library self.nwell_y_offset = 0.48 * self.height - full_height = self.height + 0.5* self.m1_width + full_height = self.height + 0.5 * self.m1_width # FIXME: float rounding problem if "nwell" in layer: @@ -302,10 +303,17 @@ class pgate(design.design): def determine_width(self): """ Determine the width based on the well contacts (assumed to be on the right side) """ + # Width is determined by well contact and spacing and allowing a supply via between each cell - self.width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * contact.m1_via.width + if self.add_wells: + self.width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * contact.m1_via.width + # Height is an input parameter, so it is not recomputed. + else: + max_active_xoffset = self.find_highest_layer_coords("active").x + max_route_xoffset = self.find_highest_layer_coords(self.route_layer).x + 0.5 * self.m1_space + self.width = max(max_active_xoffset, max_route_xoffset) + self.well_width = self.width + 2 * self.nwell_enclose_active - # Height is an input parameter, so it is not recomputed. @staticmethod def bin_width(tx_type, target_width): diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index e0e1ce81..214e66dc 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -32,7 +32,7 @@ class pinv(pgate.pgate): from center of rail to rail. """ - def __init__(self, name, size=1, beta=parameter["beta"], height=None): + def __init__(self, name, size=1, beta=parameter["beta"], height=None, add_wells=True): debug.info(2, "creating pinv structure {0} with size of {1}".format(name, @@ -44,7 +44,7 @@ class pinv(pgate.pgate): self.pmos_size = beta * size self.beta = beta - pgate.pgate.__init__(self, name, height) + pgate.pgate.__init__(self, name, height, add_wells) def create_netlist(self): """ Calls all functions related to the generation of the netlist """ @@ -56,7 +56,8 @@ class pinv(pgate.pgate): def create_layout(self): """ Calls all functions related to the generation of the layout """ self.place_ptx() - self.add_well_contacts() + if self.add_wells: + self.add_well_contacts() self.determine_width() self.extend_wells() self.route_supply_rails() diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 5d20201e..59995133 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -20,7 +20,7 @@ class pnand2(pgate.pgate): This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. """ - def __init__(self, name, size=1, height=None): + def __init__(self, name, size=1, height=None, add_wells=True): """ Creates a cell for a simple 2 input nand """ debug.info(2, @@ -43,7 +43,7 @@ class pnand2(pgate.pgate): (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) # Creates the netlist and layout - pgate.pgate.__init__(self, name, height) + pgate.pgate.__init__(self, name, height, add_wells) def create_netlist(self): self.add_pins() @@ -55,13 +55,14 @@ class pnand2(pgate.pgate): self.setup_layout_constants() self.place_ptx() - self.add_well_contacts() + if self.add_wells: + self.add_well_contacts() + self.route_output() self.determine_width() self.route_supply_rails() self.connect_rails() self.extend_wells() self.route_inputs() - self.route_output() self.add_boundary() def add_pins(self): diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 454b75dd..446b8212 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -19,7 +19,7 @@ class pnand3(pgate.pgate): This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. """ - def __init__(self, name, size=1, height=None): + def __init__(self, name, size=1, height=None, add_wells=True): """ Creates a cell for a simple 3 input nand """ debug.info(2, @@ -45,7 +45,7 @@ class pnand3(pgate.pgate): (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) # Creates the netlist and layout - pgate.pgate.__init__(self, name, height) + pgate.pgate.__init__(self, name, height, add_wells) def add_pins(self): """ Adds pins for spice netlist """ @@ -63,7 +63,8 @@ class pnand3(pgate.pgate): self.setup_layout_constants() self.place_ptx() - self.add_well_contacts() + if self.add_wells: + self.add_well_contacts() self.determine_width() self.route_supply_rails() self.connect_rails() diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index f522578e..2126e86c 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -19,7 +19,7 @@ class pnor2(pgate.pgate): This module generates gds of a parametrically sized 2-input nor. This model use ptx to generate a 2-input nor within a cetrain height. """ - def __init__(self, name, size=1, height=None): + def __init__(self, name, size=1, height=None, add_wells=True): """ Creates a cell for a simple 2 input nor """ debug.info(2, @@ -42,7 +42,7 @@ class pnor2(pgate.pgate): (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) # Creates the netlist and layout - pgate.pgate.__init__(self, name, height) + pgate.pgate.__init__(self, name, height, add_wells) def create_netlist(self): self.add_pins() @@ -54,13 +54,14 @@ class pnor2(pgate.pgate): self.setup_layout_constants() self.place_ptx() - self.add_well_contacts() + if self.add_wells: + self.add_well_contacts() + self.route_inputs() + self.route_output() self.determine_width() self.route_supply_rails() self.connect_rails() self.extend_wells() - self.route_inputs() - self.route_output() self.add_boundary() def add_pins(self): diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py index f7e5f304..21a0a38e 100755 --- a/compiler/tests/04_pand2_test.py +++ b/compiler/tests/04_pand2_test.py @@ -29,6 +29,10 @@ class pand2_test(openram_test): a = pand2.pand2(name="pand2x4", size=4) self.local_check(a) + debug.info(2, "Testing vertical pand2 gate 4x") + a = pand2.pand2(name="pand2x4", size=4, vertical=True) + self.local_check(a) + globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/04_pand3_test.py b/compiler/tests/04_pand3_test.py index e58f1ee9..f851077b 100755 --- a/compiler/tests/04_pand3_test.py +++ b/compiler/tests/04_pand3_test.py @@ -29,6 +29,10 @@ class pand3_test(openram_test): a = pand3.pand3(name="pand3x4", size=4) self.local_check(a) + debug.info(2, "Testing vertical pand3 gate 4x") + a = pand3.pand3(name="pand3x4", size=4, vertical=True) + self.local_check(a) + globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index f939738a..77a6932c 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -25,6 +25,11 @@ class pnand2_test(openram_test): tx = factory.create(module_type="pnand2", size=1) self.local_check(tx) + debug.info(2, "Checking 2-input nand gate") + tx = factory.create(module_type="pnand2", size=1, add_wells=False) + # Only DRC because well contacts will fail LVS + self.local_drc_check(tx) + globals.end_openram() diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index f1af19ac..82bf1846 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -25,6 +25,11 @@ class pnand3_test(openram_test): tx = factory.create(module_type="pnand3", size=1) self.local_check(tx) + debug.info(2, "Checking 3-input nand gate") + tx = factory.create(module_type="pnand3", size=1, add_wells=False) + # Only DRC because well contacts will fail LVS + self.local_drc_check(tx) + globals.end_openram() diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index ea0d6dbc..1e8abaa4 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -25,6 +25,10 @@ class pnor2_test(openram_test): tx = factory.create(module_type="pnor2", size=1) self.local_check(tx) + debug.info(2, "Checking 2-input nor gate") + tx = factory.create(module_type="pnor2", size=1, add_wells=False) + self.local_drc_check(tx) + globals.end_openram() # run the test from the command line