Add no well option. Add stack gates vertical option.

This commit is contained in:
mrg 2020-05-11 16:22:08 -07:00
parent b7c66d7e07
commit c96a6d0b9d
14 changed files with 187 additions and 51 deletions

View File

@ -15,14 +15,14 @@ class pand2(pgate.pgate):
""" """
This is a simple buffer used for driving loads. 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 pnand2 {}".format(name)) debug.info(1, "Creating pand2 {}".format(name))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.vertical = vertical
self.size = size self.size = size
# Creates the netlist and layout pgate.pgate.__init__(self, name)
pgate.pgate.__init__(self, name, height)
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -30,17 +30,22 @@ class pand2(pgate.pgate):
self.create_insts() self.create_insts()
def create_modules(self): 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.add_mod(self.nand)
self.inv = factory.create(module_type="pdriver", self.inv = factory.create(module_type="pdriver",
neg_polarity=True, size_list=[self.size],
fanout=self.size,
height=self.height) height=self.height)
self.add_mod(self.inv) self.add_mod(self.inv)
def create_layout(self): 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.place_insts()
self.add_wires() self.add_wires()
self.add_layout_pins() self.add_layout_pins()
@ -68,17 +73,60 @@ class pand2(pgate.pgate):
# Add NAND to the right # Add NAND to the right
self.nand_inst.place(offset=vector(0, 0)) self.nand_inst.place(offset=vector(0, 0))
# Add INV to the right if self.vertical:
self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0)) # 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): def add_wires(self):
# nand Z to inv A # nand Z to inv A
z1_pin = self.nand_inst.get_pin("Z") z1_pin = self.nand_inst.get_pin("Z")
a2_pin = self.inv_inst.get_pin("A") a2_pin = self.inv_inst.get_pin("A")
mid1_point = vector(0.5 * (z1_pin.cx() + a2_pin.cx()), z1_pin.cy()) if self.vertical:
mid2_point = vector(mid1_point, a2_pin.cy()) route_layer = "m2"
self.add_path(self.route_layer, self.add_via_stack_center(offset=z1_pin.center(),
[z1_pin.center(), mid1_point, mid2_point, a2_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): def add_layout_pins(self):
pin = self.inv_inst.get_pin("Z") pin = self.inv_inst.get_pin("Z")

View File

@ -15,10 +15,11 @@ class pand3(pgate.pgate):
""" """
This is a simple buffer used for driving loads. 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)) debug.info(1, "Creating pand3 {}".format(name))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.vertical = vertical
self.size = size self.size = size
# Creates the netlist and layout # Creates the netlist and layout
@ -31,16 +32,22 @@ class pand3(pgate.pgate):
def create_modules(self): def create_modules(self):
# Shield the cap, but have at least a stage effort of 4 # 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.add_mod(self.nand)
self.inv = factory.create(module_type="pinv", self.inv = factory.create(module_type="pdriver",
size=self.size, size_list=[self.size],
height=self.height) height=self.height)
self.add_mod(self.inv) self.add_mod(self.inv)
def create_layout(self): 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.place_insts()
self.add_wires() self.add_wires()
self.add_layout_pins() self.add_layout_pins()
@ -69,18 +76,61 @@ class pand3(pgate.pgate):
# Add NAND to the right # Add NAND to the right
self.nand_inst.place(offset=vector(0, 0)) self.nand_inst.place(offset=vector(0, 0))
# Add INV to the right if self.vertical:
self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0)) # 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): def add_wires(self):
# nand Z to inv A # nand Z to inv A
z1_pin = self.nand_inst.get_pin("Z") z1_pin = self.nand_inst.get_pin("Z")
a2_pin = self.inv_inst.get_pin("A") a2_pin = self.inv_inst.get_pin("A")
mid1_point = vector(0.5 * (z1_pin.cx()+a2_pin.cx()), z1_pin.cy()) if self.vertical:
mid2_point = vector(mid1_point, a2_pin.cy()) route_layer = "m2"
self.add_path(z1_pin.layer, self.add_via_stack_center(offset=z1_pin.center(),
[z1_pin.center(), mid1_point, mid2_point, a2_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): def add_layout_pins(self):
pin = self.inv_inst.get_pin("Z") pin = self.inv_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Z", self.add_layout_pin_rect_center(text="Z",

View File

@ -56,7 +56,8 @@ class pbuf(pgate.pgate):
self.inv2 = factory.create(module_type="pinv", self.inv2 = factory.create(module_type="pinv",
size=self.size, size=self.size,
height=self.height) height=self.height,
add_wells=False)
self.add_mod(self.inv2) self.add_mod(self.inv2)
def create_insts(self): def create_insts(self):

View File

@ -87,10 +87,13 @@ class pdriver(pgate.pgate):
def add_modules(self): def add_modules(self):
self.inv_list = [] self.inv_list = []
add_well = True
for size in self.size_list: for size in self.size_list:
temp_inv = factory.create(module_type="pinv", temp_inv = factory.create(module_type="pinv",
size=size, size=size,
height=self.height) height=self.height,
add_wells=add_well)
add_well=False
self.inv_list.append(temp_inv) self.inv_list.append(temp_inv)
self.add_mod(temp_inv) self.add_mod(temp_inv)

View File

@ -24,7 +24,7 @@ class pgate(design.design):
functions for parameterized gates. functions for parameterized gates.
""" """
def __init__(self, name, height=None): def __init__(self, name, height=None, add_wells=True):
""" Creates a generic cell """ """ Creates a generic cell """
design.design.__init__(self, name) design.design.__init__(self, name)
@ -33,7 +33,8 @@ class pgate(design.design):
elif not height: elif not height:
# By default, something simple # By default, something simple
self.height = 14 * self.m1_pitch self.height = 14 * self.m1_pitch
self.add_wells = add_wells
if "li" in layer: if "li" in layer:
self.route_layer = "li" self.route_layer = "li"
else: else:
@ -150,7 +151,7 @@ class pgate(design.design):
# This should match the cells in the cell library # This should match the cells in the cell library
self.nwell_y_offset = 0.48 * self.height 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 # FIXME: float rounding problem
if "nwell" in layer: if "nwell" in layer:
@ -302,10 +303,17 @@ class pgate(design.design):
def determine_width(self): def determine_width(self):
""" Determine the width based on the well contacts (assumed to be on the right side) """ """ 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 # 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 self.well_width = self.width + 2 * self.nwell_enclose_active
# Height is an input parameter, so it is not recomputed.
@staticmethod @staticmethod
def bin_width(tx_type, target_width): def bin_width(tx_type, target_width):

View File

@ -32,7 +32,7 @@ class pinv(pgate.pgate):
from center of rail to rail. 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, debug.info(2,
"creating pinv structure {0} with size of {1}".format(name, "creating pinv structure {0} with size of {1}".format(name,
@ -44,7 +44,7 @@ class pinv(pgate.pgate):
self.pmos_size = beta * size self.pmos_size = beta * size
self.beta = beta self.beta = beta
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height, add_wells)
def create_netlist(self): def create_netlist(self):
""" Calls all functions related to the generation of the netlist """ """ Calls all functions related to the generation of the netlist """
@ -56,7 +56,8 @@ class pinv(pgate.pgate):
def create_layout(self): def create_layout(self):
""" Calls all functions related to the generation of the layout """ """ Calls all functions related to the generation of the layout """
self.place_ptx() self.place_ptx()
self.add_well_contacts() if self.add_wells:
self.add_well_contacts()
self.determine_width() self.determine_width()
self.extend_wells() self.extend_wells()
self.route_supply_rails() self.route_supply_rails()

View File

@ -20,7 +20,7 @@ class pnand2(pgate.pgate):
This module generates gds of a parametrically sized 2-input nand. 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. 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 """ """ Creates a cell for a simple 2 input nand """
debug.info(2, debug.info(2,
@ -43,7 +43,7 @@ class pnand2(pgate.pgate):
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height, add_wells)
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -55,13 +55,14 @@ class pnand2(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.place_ptx() self.place_ptx()
self.add_well_contacts() if self.add_wells:
self.add_well_contacts()
self.route_output()
self.determine_width() self.determine_width()
self.route_supply_rails() self.route_supply_rails()
self.connect_rails() self.connect_rails()
self.extend_wells() self.extend_wells()
self.route_inputs() self.route_inputs()
self.route_output()
self.add_boundary() self.add_boundary()
def add_pins(self): def add_pins(self):

View File

@ -19,7 +19,7 @@ class pnand3(pgate.pgate):
This module generates gds of a parametrically sized 2-input nand. 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. 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 """ """ Creates a cell for a simple 3 input nand """
debug.info(2, debug.info(2,
@ -45,7 +45,7 @@ class pnand3(pgate.pgate):
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height, add_wells)
def add_pins(self): def add_pins(self):
""" Adds pins for spice netlist """ """ Adds pins for spice netlist """
@ -63,7 +63,8 @@ class pnand3(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.place_ptx() self.place_ptx()
self.add_well_contacts() if self.add_wells:
self.add_well_contacts()
self.determine_width() self.determine_width()
self.route_supply_rails() self.route_supply_rails()
self.connect_rails() self.connect_rails()

View File

@ -19,7 +19,7 @@ class pnor2(pgate.pgate):
This module generates gds of a parametrically sized 2-input nor. 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. 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 """ """ Creates a cell for a simple 2 input nor """
debug.info(2, debug.info(2,
@ -42,7 +42,7 @@ class pnor2(pgate.pgate):
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height, add_wells)
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -54,13 +54,14 @@ class pnor2(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.place_ptx() 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.determine_width()
self.route_supply_rails() self.route_supply_rails()
self.connect_rails() self.connect_rails()
self.extend_wells() self.extend_wells()
self.route_inputs()
self.route_output()
self.add_boundary() self.add_boundary()
def add_pins(self): def add_pins(self):

View File

@ -29,6 +29,10 @@ class pand2_test(openram_test):
a = pand2.pand2(name="pand2x4", size=4) a = pand2.pand2(name="pand2x4", size=4)
self.local_check(a) 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() globals.end_openram()
# instantiate a copdsay of the class to actually run the test # instantiate a copdsay of the class to actually run the test

View File

@ -29,6 +29,10 @@ class pand3_test(openram_test):
a = pand3.pand3(name="pand3x4", size=4) a = pand3.pand3(name="pand3x4", size=4)
self.local_check(a) 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() globals.end_openram()
# instantiate a copdsay of the class to actually run the test # instantiate a copdsay of the class to actually run the test

View File

@ -25,6 +25,11 @@ class pnand2_test(openram_test):
tx = factory.create(module_type="pnand2", size=1) tx = factory.create(module_type="pnand2", size=1)
self.local_check(tx) 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() globals.end_openram()

View File

@ -25,6 +25,11 @@ class pnand3_test(openram_test):
tx = factory.create(module_type="pnand3", size=1) tx = factory.create(module_type="pnand3", size=1)
self.local_check(tx) 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() globals.end_openram()

View File

@ -25,6 +25,10 @@ class pnor2_test(openram_test):
tx = factory.create(module_type="pnor2", size=1) tx = factory.create(module_type="pnor2", size=1)
self.local_check(tx) 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() globals.end_openram()
# run the test from the command line # run the test from the command line