Cleanup pgate code.

Moved create_netlist and create_layout to the pgate class
from which everything is derived. Modified all pgates
to have consistent debug output and order of init function.
This commit is contained in:
Matt Guthaus 2019-04-26 11:57:29 -07:00 committed by Matt Guthaus
parent e507fbd5e9
commit 05ad4285af
15 changed files with 301 additions and 90 deletions

View File

@ -21,8 +21,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
self.name = name self.name = name
hierarchy_layout.layout.__init__(self, name)
hierarchy_spice.spice.__init__(self, name) hierarchy_spice.spice.__init__(self, name)
hierarchy_layout.layout.__init__(self, name)
def get_layout_pins(self,inst): def get_layout_pins(self,inst):

View File

@ -28,7 +28,10 @@ class spice():
# Spice format) # Spice format)
self.conns = [] self.conns = []
# Keep track of any comments to add the the spice # Keep track of any comments to add the the spice
self.comments = [] try:
self.commments
except:
self.comments = []
self.sp_read() self.sp_read()
@ -38,7 +41,12 @@ class spice():
def add_comment(self, comment): def add_comment(self, comment):
""" Add a comment to the spice file """ """ Add a comment to the spice file """
self.comments.append(comment) try:
self.commments
except:
self.comments = []
else:
self.comments.append(comment)
def add_pin(self, name, pin_type="INOUT"): def add_pin(self, name, pin_type="INOUT"):
""" Adds a pin to the pins list. Default type is INOUT signal. """ """ Adds a pin to the pins list. Default type is INOUT signal. """

View File

@ -11,16 +11,13 @@ 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):
self.size = size debug.info(1, "reating pnand2 {}".format(name))
pgate.pgate.__init__(self, name, height)
debug.info(1, "Creating {}".format(self.name))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.create_netlist() self.size = size
if not OPTS.netlist_only:
self.create_layout() # Creates the netlist and layout
pgate.pgate.__init__(self, name, height)
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -40,6 +37,7 @@ class pand2(pgate.pgate):
self.place_insts() self.place_insts()
self.add_wires() self.add_wires()
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS()
def add_pins(self): def add_pins(self):
self.add_pin("A") self.add_pin("A")
@ -129,4 +127,4 @@ class pand2(pgate.pgate):
def get_cin(self): def get_cin(self):
"""Return the relative input capacitance of a single input""" """Return the relative input capacitance of a single input"""
return self.nand.get_cin() return self.nand.get_cin()

View File

@ -12,17 +12,15 @@ class pbuf(pgate.pgate):
""" """
def __init__(self, name, size=4, height=None): def __init__(self, name, size=4, height=None):
debug.info(1, "creating {0} with size of {1}".format(name,size))
self.add_comment("size: {}".format(size))
self.stage_effort = 4 self.stage_effort = 4
self.size = size self.size = size
self.height = height self.height = height
# Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(1, "creating {0} with size of {1}".format(self.name,self.size))
self.add_comment("size: {}".format(size))
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self): def create_netlist(self):

View File

@ -13,6 +13,8 @@ class pdriver(pgate.pgate):
""" """
def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None): def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None):
debug.info(1, "creating pdriver {}".format(name))
self.stage_effort = 3 self.stage_effort = 3
self.height = height self.height = height
self.neg_polarity = neg_polarity self.neg_polarity = neg_polarity
@ -26,16 +28,9 @@ class pdriver(pgate.pgate):
if self.size_list and self.neg_polarity: if self.size_list and self.neg_polarity:
debug.error("Cannot specify both size_list and neg_polarity.", -1) debug.error("Cannot specify both size_list and neg_polarity.", -1)
# Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(1, "Creating {}".format(self.name))
self.compute_sizes()
self.add_comment("sizes: {}".format(str(self.size_list)))
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def compute_sizes(self): def compute_sizes(self):
# size_list specified # size_list specified
@ -63,6 +58,8 @@ class pdriver(pgate.pgate):
def create_netlist(self): def create_netlist(self):
self.compute_sizes()
self.add_comment("sizes: {}".format(str(self.size_list)))
self.add_pins() self.add_pins()
self.add_modules() self.add_modules()
self.create_insts() self.create_insts()
@ -75,7 +72,6 @@ class pdriver(pgate.pgate):
self.width = self.inv_inst_list[-1].rx() self.width = self.inv_inst_list[-1].rx()
self.height = self.inv_inst_list[0].height self.height = self.inv_inst_list[0].height
self.DRC_LVS()
def add_pins(self): def add_pins(self):
self.add_pin("A") self.add_pin("A")

View File

@ -21,7 +21,20 @@ class pgate(design.design):
b = factory.create(module_type="bitcell") b = factory.create(module_type="bitcell")
self.height = b.height self.height = b.height
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
self.DRC_LVS()
def create_netlist():
""" Pure virtual function """
debug.error("Must over-ride create_netlist.",-1)
def create_layout():
""" Pure virtual function """
debug.error("Must over-ride create_layout.",-1)
def connect_pin_to_rail(self,inst,pin,supply): def connect_pin_to_rail(self,inst,pin,supply):
""" Connects a ptx pin to a supply rail. """ """ Connects a ptx pin to a supply rail. """
source_pin = inst.get_pin(pin) source_pin = inst.get_pin(pin)

View File

@ -20,28 +20,18 @@ class pinv(pgate.pgate):
""" """
def __init__(self, name, size=1, beta=parameter["beta"], height=None, route_output=True): def __init__(self, name, size=1, beta=parameter["beta"], height=None, route_output=True):
# We need to keep unique names because outputting to GDSII
# will use the last record with a given name. I.e., you will debug.info(2, "creating pinv structure {0} with size of {1}".format(name, size))
# over-write a design in GDS if one has and the other doesn't
# have poly connected, for example.
pgate.pgate.__init__(self, name, height)
debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.size = size self.size = size
self.nmos_size = size self.nmos_size = size
self.pmos_size = beta*size self.pmos_size = beta*size
self.beta = beta self.beta = beta
self.route_output = False self.route_output = False
self.create_netlist() # Creates the netlist and layout
if not OPTS.netlist_only: pgate.pgate.__init__(self, name, height)
self.create_layout()
# for run-time, we won't check every transitor DRC/LVS independently
# but this may be uncommented for debug purposes
#self.DRC_LVS()
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 """

View File

@ -1,18 +1,21 @@
import debug import debug
import design import pgate
from tech import drc from tech import drc
from math import log from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class pinvbuf(design.design): class pinvbuf(pgate.pgate):
""" """
This is a simple inverter/buffer used for driving loads. It is This is a simple inverter/buffer used for driving loads. It is
used in the column decoder for 1:2 decoding and as the clock buffer. used in the column decoder for 1:2 decoding and as the clock buffer.
""" """
def __init__(self, name, size=4, height=None): def __init__(self, name, size=4, height=None):
debug.info(1, "creating pinvbuf {}".format(name))
self.add_comment("size: {}".format(size))
self.stage_effort = 4 self.stage_effort = 4
self.row_height = height self.row_height = height
# FIXME: Change the number of stages to support high drives. # FIXME: Change the number of stages to support high drives.
@ -23,13 +26,8 @@ class pinvbuf(design.design):
self.size = size self.size = size
self.predriver_size = max(int(self.size/(self.stage_effort/2)),1) self.predriver_size = max(int(self.size/(self.stage_effort/2)),1)
design.design.__init__(self, name) # Creates the netlist and layout
debug.info(1, "Creating {}".format(self.name)) pgate.pgate.__init__(self, name)
self.add_comment("size: {}".format(size))
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self): def create_netlist(self):
@ -48,7 +46,6 @@ class pinvbuf(design.design):
self.offset_all_coordinates() self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self): def add_pins(self):
self.add_pin("A") self.add_pin("A")

View File

@ -14,8 +14,8 @@ class pnand2(pgate.pgate):
""" """
def __init__(self, name, size=1, height=None): def __init__(self, name, size=1, height=None):
""" Creates a cell for a simple 2 input nand """ """ Creates a cell for a simple 2 input nand """
pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) debug.info(2, "creating pnand2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.size = size self.size = size
@ -28,9 +28,8 @@ class pnand2(pgate.pgate):
debug.check(size==1,"Size 1 pnand2 is only supported now.") debug.check(size==1,"Size 1 pnand2 is only supported now.")
self.tx_mults = 1 self.tx_mults = 1
self.create_netlist() # Creates the netlist and layout
if not OPTS.netlist_only: pgate.pgate.__init__(self, name, height)
self.create_layout()
def create_netlist(self): def create_netlist(self):

View File

@ -14,8 +14,8 @@ class pnand3(pgate.pgate):
""" """
def __init__(self, name, size=1, height=None): def __init__(self, name, size=1, height=None):
""" Creates a cell for a simple 3 input nand """ """ Creates a cell for a simple 3 input nand """
pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) debug.info(2, "creating pnand3 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
# We have trouble pitch matching a 3x sizes to the bitcell... # We have trouble pitch matching a 3x sizes to the bitcell...
@ -30,9 +30,8 @@ class pnand3(pgate.pgate):
debug.check(size==1,"Size 1 pnand3 is only supported now.") debug.check(size==1,"Size 1 pnand3 is only supported now.")
self.tx_mults = 1 self.tx_mults = 1
self.create_netlist() # Creates the netlist and layout
if not OPTS.netlist_only: pgate.pgate.__init__(self, name, height)
self.create_layout()
def add_pins(self): def add_pins(self):

View File

@ -13,8 +13,8 @@ class pnor2(pgate.pgate):
""" """
def __init__(self, name, size=1, height=None): def __init__(self, name, size=1, height=None):
""" Creates a cell for a simple 2 input nor """ """ Creates a cell for a simple 2 input nor """
pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size)) debug.info(2, "creating pnor2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.nmos_size = size self.nmos_size = size
@ -27,9 +27,8 @@ class pnor2(pgate.pgate):
debug.check(size==1,"Size 1 pnor2 is only supported now.") debug.check(size==1,"Size 1 pnor2 is only supported now.")
self.tx_mults = 1 self.tx_mults = 1
self.create_netlist() # Creates the netlist and layout
self.create_layout() pgate.pgate.__init__(self, name, height)
#self.DRC_LVS()
def add_pins(self): def add_pins(self):
@ -38,12 +37,11 @@ class pnor2(pgate.pgate):
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
self.create_ptx()
self.setup_layout_constants()
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.create_ptx()
self.setup_layout_constants()
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.connect_rails() self.connect_rails()

View File

@ -12,20 +12,19 @@ class precharge(pgate.pgate):
This module implements the precharge bitline cell used in the design. This module implements the precharge bitline cell used in the design.
""" """
def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"): def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"):
pgate.pgate.__init__(self, name)
debug.info(2, "create single precharge cell: {0}".format(name)) debug.info(2, "creating precharge cell {0}".format(name))
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type="bitcell")
self.beta = parameter["beta"] self.beta = parameter["beta"]
self.ptx_width = self.beta*parameter["min_tx_size"] self.ptx_width = self.beta*parameter["min_tx_size"]
self.width = self.bitcell.width self.width = self.bitcell.width
self.bitcell_bl = bitcell_bl self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br self.bitcell_br = bitcell_br
self.create_netlist() # Creates the netlist and layout
if not OPTS.netlist_only: pgate.pgate.__init__(self, name)
self.create_layout()
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -40,7 +39,6 @@ class precharge(pgate.pgate):
self.route_vdd_rail() self.route_vdd_rail()
self.route_bitlines() self.route_bitlines()
self.connect_to_bitlines() self.connect_to_bitlines()
self.DRC_LVS()
def add_pins(self): def add_pins(self):
self.add_pin_list(["bl", "br", "en_bar", "vdd"]) self.add_pin_list(["bl", "br", "en_bar", "vdd"])

View File

@ -0,0 +1,220 @@
import contact
import pgate
import debug
from tech import drc, parameter, spice
from vector import vector
from math import ceil
from globals import OPTS
from utils import round_to_grid
import logical_effort
from sram_factory import factory
class ptristate_inv(pgate.pgate):
"""
ptristate generates gds of a parametrically sized tristate inverter.
There is some flexibility in the size, but we do not allow multiple fingers
to fit in the cell height.
"""
def __init__(self, name, size=1, height=None):
debug.info(2, "creating ptristate inv {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
# We are 2x since there are two series devices
self.size = 2*size
self.nmos_size = size
self.beta = parameter["beta"]
self.pmos_size = self.beta*size
self.nmos_width = self.nmos_size * drc("minwidth_tx")
self.pmos_width = self.pmos_size * drc("minwidth_tx")
# Creates the netlist and layout
pgate.pgate.__init__(self, name, height)
def create_netlist(self):
""" Calls all functions related to the generation of the netlist """
self.add_pins()
self.add_ptx()
self.create_ptx()
def create_layout(self):
""" Calls all functions related to the generation of the layout """
self.setup_layout_constants()
self.route_supply_rails()
self.place_ptx()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.connect_rails()
self.route_inputs()
self.route_outputs()
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["in", "out", "en", "en_bar", "vdd", "gnd"])
def setup_layout_constants(self):
"""
Pre-compute some handy layout parameters.
"""
# Compute the other pmos2 location, but determining offset to overlap the
# source and drain pins
self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
# Two PMOS devices and a well contact. Separation between each.
# Enclosure space on the sides.
self.well_width = 2*self.pmos.active_width + drc("well_enclosure_active")
# Add an extra space because we route the output on the right of the S/D
self.width = self.well_width + 0.5*self.m1_space
# Height is an input parameter, so it is not recomputed.
# Make sure we can put a well above and below
self.top_bottom_space = max(contact.well.width, contact.well.height)
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = factory.create(module_type="ptx",
width=self.nmos_width,
mults=1,
tx_type="nmos")
self.add_mod(self.nmos)
self.pmos = factory.create(module_type="ptx",
width=self.pmos_width,
mults=1,
tx_type="pmos")
self.add_mod(self.pmos)
def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
def create_ptx(self):
"""
Create the PMOS and NMOS netlist.
"""
# These are the inverter PMOS/NMOS
self.pmos1_inst=self.add_inst(name="ptri_pmos1", mod=self.pmos)
self.connect_inst(["vdd", "in", "n1", "vdd"])
self.nmos1_inst=self.add_inst(name="ptri_nmos1", mod=self.nmos)
self.connect_inst(["gnd", "in", "n2", "gnd"])
# These are the tristate PMOS/NMOS
self.pmos2_inst = self.add_inst(name="ptri_pmos2", mod=self.pmos)
self.connect_inst(["out", "en_bar", "n1", "vdd"])
self.nmos2_inst=self.add_inst(name="ptri_nmos2", mod=self.nmos)
self.connect_inst(["out", "en", "n2", "gnd"])
def place_ptx(self):
"""
Place PMOS and NMOS to the layout at the upper-most and lowest position
to provide maximum routing in channel
"""
pmos_yoff = self.height - self.pmos.active_height - self.top_bottom_space - 0.5*contact.well.height
nmos_yoff = self.top_bottom_space + 0.5*contact.well.height
# Tristate transistors
pmos1_pos = vector(self.pmos.active_offset.x, pmos_yoff)
self.pmos1_inst.place(pmos1_pos)
nmos1_pos = vector(self.pmos.active_offset.x, nmos_yoff)
self.nmos1_inst.place(nmos1_pos)
# Inverter transistors
self.pmos2_pos = pmos1_pos + self.overlap_offset
self.pmos2_inst.place(self.pmos2_pos)
self.nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst.place(self.nmos2_pos)
# Output position will be in between the PMOS and NMOS
self.output_pos = vector(0, 0.5*(pmos_yoff + nmos_yoff + self.nmos.height))
# This will help with the wells
self.well_pos = vector(0,self.nmos1_inst.uy())
def route_inputs(self):
""" Route the gates """
self.route_input_gate(self.pmos1_inst, self.nmos1_inst, self.output_pos.y, "in", position="farleft")
self.route_single_gate(self.pmos2_inst, "en_bar", position="left")
self.route_single_gate(self.nmos2_inst, "en", position="left")
def route_outputs(self):
""" Route the output (drains) together. """
nmos_drain_pin = self.nmos2_inst.get_pin("D")
pmos_drain_pin = self.pmos2_inst.get_pin("D")
nmos_drain_pos = nmos_drain_pin.lr()
pmos_drain_pos = pmos_drain_pin.ur()
self.add_layout_pin(text="out",
layer="metal1",
offset=nmos_drain_pos,
height=pmos_drain_pos.y-nmos_drain_pos.y)
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies AFTER the wells are created """
layer_stack = ("active", "contact", "metal1")
drain_pos = self.nmos1_inst.get_pin("S").center()
vdd_pos = self.get_pin("vdd").center()
self.nwell_contact=self.add_via_center(layers=layer_stack,
offset=vector(drain_pos.x,vdd_pos.y),
implant_type="n",
well_type="n")
gnd_pos = self.get_pin("gnd").center()
self.pwell_contact=self.add_via_center(layers=layer_stack,
offset=vector(drain_pos.x,gnd_pos.y),
implant_type="p",
well_type="p")
def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """
self.connect_pin_to_rail(self.nmos1_inst,"S","gnd")
self.connect_pin_to_rail(self.pmos1_inst,"S","vdd")
def analytical_delay(self, corner, slew, load=0.0):
from tech import spice
r = spice["min_tx_r"]
c_para = spice["min_tx_drain_c"]
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
total_power = self.return_power()
return total_power
def input_load(self):
return 9*spice["min_tx_gate_c"]

View File

@ -28,9 +28,7 @@ class ptx(design.design):
name += "_c{}".format(num_contacts) name += "_c{}".format(num_contacts)
# replace periods with underscore for newer spice compatibility # replace periods with underscore for newer spice compatibility
name=name.replace('.','_') name=name.replace('.','_')
debug.info(3, "creating ptx {0}".format(name))
design.design.__init__(self, name)
debug.info(3, "create ptx2 structure {0}".format(name))
self.tx_type = tx_type self.tx_type = tx_type
self.mults = mults self.mults = mults
@ -39,6 +37,9 @@ class ptx(design.design):
self.connect_poly = connect_poly self.connect_poly = connect_poly
self.num_contacts = num_contacts self.num_contacts = num_contacts
# Do NOT create the netlist and layout (not a pgate)
design.design.__init__(self, name)
self.create_netlist() self.create_netlist()
# We must always create ptx layout for pbitcell # We must always create ptx layout for pbitcell
# some transistor sizes in other netlist depend on pbitcell # some transistor sizes in other netlist depend on pbitcell

View File

@ -1,4 +1,4 @@
import design import pgate
import debug import debug
from tech import drc from tech import drc
from vector import vector from vector import vector
@ -7,7 +7,7 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import logical_effort import logical_effort
class single_level_column_mux(design.design): class single_level_column_mux(pgate.gate):
""" """
This module implements the columnmux bitline cell used in the design. This module implements the columnmux bitline cell used in the design.
Creates a single columnmux cell with the given integer size relative Creates a single columnmux cell with the given integer size relative
@ -15,18 +15,14 @@ class single_level_column_mux(design.design):
Column-mux transistors driven by the decoder must be sized for optimal speed Column-mux transistors driven by the decoder must be sized for optimal speed
""" """
def __init__(self, name, tx_size=8, bitcell_bl="bl", bitcell_br="br"): def __init__(self, name, tx_size=8, bitcell_bl="bl", bitcell_br="br"):
debug.info(2, "creating single column mux cell: {0}".format(name))
self.tx_size = int(tx_size) self.tx_size = int(tx_size)
design.design.__init__(self, name)
debug.info(2, "create single column mux cell: {0}".format(name))
self.bitcell_bl = bitcell_bl self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br self.bitcell_br = bitcell_br
self.create_netlist() pgate.pgate.__init__(self, name)
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()