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.
"""
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")

View File

@ -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",

View File

@ -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):

View File

@ -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)

View File

@ -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):

View File

@ -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()

View File

@ -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):

View File

@ -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()

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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