Rewrite add_contact to use layer directions.

This commit is contained in:
Matt Guthaus 2019-04-01 14:23:47 -07:00 committed by Matt Guthaus
parent c1411f4227
commit be20408fb2
26 changed files with 430 additions and 460 deletions

View File

@ -9,44 +9,36 @@ class contact(hierarchy_design.hierarchy_design):
""" """
Object for a contact shape with its conductor enclosures. Object for a contact shape with its conductor enclosures.
Creates a contact array minimum active or poly enclosure and metal1 enclosure. Creates a contact array minimum active or poly enclosure and metal1 enclosure.
This class has enclosure on multiple sides of the contact whereas a via may This class has enclosure on two or four sides of the contact.
have extension on two or four sides. The direction specifies whether the first and second layer have asymmetric extension in the H or V direction.
The well/implant_type is an option to add a select/implant layer enclosing the contact. This is The well/implant_type is an option to add a select/implant layer enclosing the contact. This is
necessary to import layouts into Magic which requires the select to be in the same GDS necessary to import layouts into Magic which requires the select to be in the same GDS
hierarchy as the contact. hierarchy as the contact.
""" """
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None, name=""): def __init__(self, layer_stack, dimensions=(1,1), directions=("V","V"), implant_type=None, well_type=None, name=""):
# This will ignore the name parameter since we can guarantee a unique name here # This will ignore the name parameter since we can guarantee a unique name here
if implant_type or well_type:
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
layer_stack[1],
layer_stack[2],
dimensions[0],
dimensions[1],
implant_type,
well_type)
else:
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
layer_stack[1],
layer_stack[2],
dimensions[0],
dimensions[1])
hierarchy_design.hierarchy_design.__init__(self, name) hierarchy_design.hierarchy_design.__init__(self, name)
debug.info(4, "create contact object {0}".format(name)) debug.info(4, "create contact object {0}".format(name))
self.add_comment("layers: {0}".format(layer_stack))
self.add_comment("dimensions: {0}".format(dimensions))
if implant_type or well_type:
self.add_comment("implant type: {0}\nwell_type: {1}".format(implant_type,well_type))
self.layer_stack = layer_stack self.layer_stack = layer_stack
self.dimensions = dimensions self.dimensions = dimensions
self.directions = directions
self.offset = vector(0,0) self.offset = vector(0,0)
self.implant_type = implant_type self.implant_type = implant_type
self.well_type = well_type self.well_type = well_type
self.pins = [] # used for matching parm lengths # Module does not have pins, but has empty pin list.
self.pins = []
self.create_layout() self.create_layout()
def create_layout(self): def create_layout(self):
self.setup_layers() self.setup_layers()
self.setup_layout_constants() self.setup_layout_constants()
self.create_contact_array() self.create_contact_array()
@ -63,6 +55,8 @@ class contact(hierarchy_design.hierarchy_design):
debug.error(-1,"Must define both implant and well type or none at all.") debug.error(-1,"Must define both implant and well type or none at all.")
def setup_layers(self): def setup_layers(self):
""" Locally assign the layer names. """
(first_layer, via_layer, second_layer) = self.layer_stack (first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer self.first_layer_name = first_layer
self.via_layer_name = via_layer self.via_layer_name = via_layer
@ -75,37 +69,58 @@ class contact(hierarchy_design.hierarchy_design):
self.second_layer_name = second_layer self.second_layer_name = second_layer
def setup_layout_constants(self): def setup_layout_constants(self):
""" Determine the design rules for the enclosure layers """
self.contact_width = drc("minwidth_{0}". format(self.via_layer_name)) self.contact_width = drc("minwidth_{0}". format(self.via_layer_name))
contact_to_contact = drc("{0}_to_{0}".format(self.via_layer_name)) contact_to_contact = drc("{0}_to_{0}".format(self.via_layer_name))
self.contact_pitch = self.contact_width + contact_to_contact self.contact_pitch = self.contact_width + contact_to_contact
self.contact_array_width = self.contact_width + (self.dimensions[0] - 1) * self.contact_pitch self.contact_array_width = self.contact_width + (self.dimensions[0] - 1) * self.contact_pitch
self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
# DRC rules # DRC rules
# The extend rule applies to asymmetric enclosures in one direction.
# The enclosure rule applies to symmetric enclosure component.
first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name)) first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name))
first_layer_minarea = drc("minarea_{0}".format(self.first_layer_name))
first_layer_enclosure = drc("{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)) first_layer_enclosure = drc("{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name))
first_layer_extend = drc("{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)) first_layer_extend = drc("{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name))
second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name)) second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name))
second_layer_minarea = drc("minarea_{0}".format(self.second_layer_name))
second_layer_enclosure = drc("{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)) second_layer_enclosure = drc("{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name))
second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)) second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name))
self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
first_layer_enclosure)
self.first_layer_vertical_enclosure = max(utils.ceil((first_layer_minarea
/ (self.contact_array_width + 2*self.first_layer_horizontal_enclosure)
- self.contact_array_height)/2),
(first_layer_minwidth - self.contact_array_height)/2,
first_layer_extend)
self.second_layer_horizontal_enclosure = max((second_layer_minwidth - self.contact_array_width)/2, # In some technologies, the minimum width may be larger than the overlap requirement around the via, so
second_layer_enclosure) # check this for each dimension.
self.second_layer_vertical_enclosure = max(utils.ceil((second_layer_minarea if self.directions[0] == "V":
/ (self.contact_array_width + 2*self.second_layer_horizontal_enclosure) self.first_layer_horizontal_enclosure = max(first_layer_enclosure,
- self.contact_array_height)/2), (first_layer_minwidth - self.contact_array_width)/2)
(second_layer_minwidth - self.contact_array_height)/2, self.first_layer_vertical_enclosure = max(first_layer_extend,
second_layer_extend) (first_layer_minwidth - self.contact_array_height)/2)
elif self.directions[0] == "H":
self.first_layer_horizontal_enclosure = max(first_layer_extend,
(first_layer_minwidth - self.contact_array_width)/2)
self.first_layer_vertical_enclosure = max(first_layer_enclosure,
(first_layer_minwidth - self.contact_array_height)/2)
else:
debug.error("Invalid first layer direction.", -1)
# In some technologies, the minimum width may be larger than the overlap requirement around the via, so
# check this for each dimension.
if self.directions[1] == "V":
self.second_layer_horizontal_enclosure = max(second_layer_enclosure,
(second_layer_minwidth - self.contact_array_width)/2)
self.second_layer_vertical_enclosure = max(second_layer_extend,
(second_layer_minwidth - self.contact_array_height)/2)
elif self.directions[1] == "H":
self.second_layer_horizontal_enclosure = max(second_layer_extend,
(second_layer_minwidth - self.contact_array_height)/2)
self.second_layer_vertical_enclosure = max(second_layer_enclosure,
(second_layer_minwidth - self.contact_array_width)/2)
else:
debug.error("Invalid second layer direction.", -1)
def create_contact_array(self): def create_contact_array(self):
""" Create the contact array at the origin""" """ Create the contact array at the origin"""
@ -169,10 +184,10 @@ class contact(hierarchy_design.hierarchy_design):
from sram_factory import factory from sram_factory import factory
# This is not instantiated and used for calculations only. # This is not instantiated and used for calculations only.
# These are static 1x1 contacts to reuse in all the design modules. # These are static 1x1 contacts to reuse in all the design modules.
well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1")) well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"), directions=("H","V"))
active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly")) active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly"), directions=("H","V"))
poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1")) poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"), directions=("V","H"))
m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2")) m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"), directions=("H","V"))
m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3")) m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"), directions=("V","H"))
m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4")) m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"), directions=("H","V"))

View File

@ -355,75 +355,59 @@ class layout():
layer_stack=layers, layer_stack=layers,
position_list=coordinates) position_list=coordinates)
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): def get_preferred_direction(self, layer):
""" This is just an alias for a via.""" """ Return the preferred routing directions """
return self.add_via(layers=layers, if layer in ["metal1", "metal3", "metal5"]:
offset=offset, return "H"
size=size, elif layer in ["active", "poly", "metal2", "metal4"]:
mirror=mirror, return "V"
rotate=rotate, else:
implant_type=implant_type, return "N"
well_type=well_type)
def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" This is just an alias for a via."""
return self.add_via_center(layers=layers,
offset=offset,
size=size,
mirror=mirror,
rotate=rotate,
implant_type=implant_type,
well_type=well_type)
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): def add_via(self, layers, offset, size=[1,1], directions=None, implant_type=None, well_type=None):
""" Add a three layer via structure. """ """ Add a three layer via structure. """
if directions==None:
directions = (self.get_preferred_direction(layers[0]), self.get_preferred_direction(layers[2]))
from sram_factory import factory from sram_factory import factory
via = factory.create(module_type="contact", via = factory.create(module_type="contact",
layer_stack=layers, layer_stack=layers,
dimensions=size, dimensions=size,
directions=directions,
implant_type=implant_type, implant_type=implant_type,
well_type=well_type) well_type=well_type)
self.add_mod(via) self.add_mod(via)
inst=self.add_inst(name=via.name, inst=self.add_inst(name=via.name,
mod=via, mod=via,
offset=offset, offset=offset)
mirror=mirror,
rotate=rotate)
# We don't model the logical connectivity of wires/paths # We don't model the logical connectivity of wires/paths
self.connect_inst([]) self.connect_inst([])
return inst return inst
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): def add_via_center(self, layers, offset, directions=None, size=[1,1], implant_type=None, well_type=None):
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """ """ Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
if directions==None:
directions = (self.get_preferred_direction(layers[0]), self.get_preferred_direction(layers[2]))
from sram_factory import factory from sram_factory import factory
via = factory.create(module_type="contact", via = factory.create(module_type="contact",
layer_stack=layers, layer_stack=layers,
dimensions=size, dimensions=size,
directions=directions,
implant_type=implant_type, implant_type=implant_type,
well_type=well_type) well_type=well_type)
height = via.height height = via.height
width = via.width width = via.width
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
if rotate==0:
corrected_offset = offset + vector(-0.5*width,-0.5*height) corrected_offset = offset + vector(-0.5*width,-0.5*height)
elif rotate==90:
corrected_offset = offset + vector(0.5*height,-0.5*width)
elif rotate==180:
corrected_offset = offset + vector(0.5*width,0.5*height)
elif rotate==270:
corrected_offset = offset + vector(-0.5*height,0.5*width)
else:
debug.error("Invalid rotation argument.",-1)
#print(rotate,offset,"->",corrected_offset)
self.add_mod(via) self.add_mod(via)
inst=self.add_inst(name=via.name, inst=self.add_inst(name=via.name,
mod=via, mod=via,
offset=corrected_offset, offset=corrected_offset)
mirror=mirror,
rotate=rotate)
# We don't model the logical connectivity of wires/paths # We don't model the logical connectivity of wires/paths
self.connect_inst([]) self.connect_inst([])
return inst return inst
@ -748,8 +732,7 @@ class layout():
mid = vector(trunk_offset.x, pin.center().y) mid = vector(trunk_offset.x, pin.center().y)
self.add_path(layer_stack[0], [pin.center(), mid]) self.add_path(layer_stack[0], [pin.center(), mid])
self.add_via_center(layers=layer_stack, self.add_via_center(layers=layer_stack,
offset=mid, offset=mid)
rotate=90)
def create_channel_route(self, netlist, def create_channel_route(self, netlist,
@ -926,20 +909,27 @@ class layout():
def add_power_pin(self, name, loc, rotate=90, start_layer="metal1"): def add_power_pin(self, name, loc, vertical=False, start_layer="metal1"):
""" """
Add a single power pin from M3 down to M1 at the given center location. Add a single power pin from M3 down to M1 at the given center location.
The starting layer is specified to determine which vias are needed. The starting layer is specified to determine which vias are needed.
""" """
if vertical:
direction=("V","V")
else:
direction=("H","H")
if start_layer=="metal1": if start_layer=="metal1":
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=loc, offset=loc,
rotate=float(rotate)) directions=direction)
if start_layer=="metal1" or start_layer=="metal2": if start_layer=="metal1" or start_layer=="metal2":
via=self.add_via_center(layers=("metal2", "via2", "metal3"), via=self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=loc, offset=loc,
rotate=float(rotate)) directions=direction)
if start_layer=="metal3": if start_layer=="metal3":
self.add_layout_pin_rect_center(text=name, self.add_layout_pin_rect_center(text=name,
layer="metal3", layer="metal3",

View File

@ -65,7 +65,7 @@ class route(design):
for p0,p1 in plist: for p0,p1 in plist:
if p0.z != p1.z: # via if p0.z != p1.z: # via
via_size = [self.num_vias]*2 via_size = [self.num_vias]*2
self.obj.add_via_center(self.layer_stack,vector(p0.x,p0.y),size=via_size,rotate=90) self.obj.add_via_center(self.layer_stack,vector(p0.x,p0.y),size=via_size)
elif p0.x != p1.x and p0.y != p1.y: # diagonal! elif p0.x != p1.x and p0.y != p1.y: # diagonal!
debug.error("Diagonal route! {}".format(self.path),-3) debug.error("Diagonal route! {}".format(self.path),-3)
else: else:

View File

@ -62,18 +62,15 @@ class wire(wire_path):
continue continue
if a[1] == c[1]: if a[1] == c[1]:
continue continue
via_offset = [offset[0] + 0.5*c_height, self.obj.add_via_center(layers=self.layer_stack,
offset[1] - 0.5*c_width] offset=offset)
self.obj.add_via(layers=self.layer_stack,
offset=via_offset,
rotate=90)
corner_offset = [offset[0] - 0.5*(c_height + self.vert_layer_width),
offset[1] + 0.5*(c_width - self.horiz_layer_width)]
def create_rectangles(self): def create_rectangles(self):
""" Create the actual rectangles on teh appropriate layers """
using the position list of the corners. """ Create the actual rectangles on the appropriate layers
using the position list of the corners.
"""
pl = self.position_list # position list pl = self.position_list # position list
for index in range(len(pl) - 1): for index in range(len(pl) - 1):
if pl[index][0] != pl[index + 1][0]: if pl[index][0] != pl[index + 1][0]:

View File

@ -198,7 +198,7 @@ class pbitcell(design.design):
self.read_port_spacing = self.bitline_offset + self.m2_space self.read_port_spacing = self.bitline_offset + self.m2_space
# spacing between cross coupled inverters # spacing between cross coupled inverters
self.inverter_to_inverter_spacing = contact.poly.height + self.m1_space self.inverter_to_inverter_spacing = contact.poly.width + self.m1_space
# calculations related to inverter connections # calculations related to inverter connections
inverter_pmos_contact_extension = 0.5*(self.inverter_pmos.active_contact.height - self.inverter_pmos.active_height) inverter_pmos_contact_extension = 0.5*(self.inverter_pmos.active_contact.height - self.inverter_pmos.active_height)
@ -292,19 +292,20 @@ class pbitcell(design.design):
self.add_path("poly", [self.inverter_nmos_right.get_pin("G").uc(), self.inverter_pmos_right.get_pin("G").bc()]) self.add_path("poly", [self.inverter_nmos_right.get_pin("G").uc(), self.inverter_pmos_right.get_pin("G").bc()])
# connect output (drain/source) of inverters # connect output (drain/source) of inverters
self.add_path("metal1", [self.inverter_nmos_left.get_pin("D").uc(), self.inverter_pmos_left.get_pin("D").bc()], width=contact.well.second_layer_width) self.add_path("metal1", [self.inverter_nmos_left.get_pin("D").uc(), self.inverter_pmos_left.get_pin("D").bc()])
self.add_path("metal1", [self.inverter_nmos_right.get_pin("S").uc(), self.inverter_pmos_right.get_pin("S").bc()], width=contact.well.second_layer_width) self.add_path("metal1", [self.inverter_nmos_right.get_pin("S").uc(), self.inverter_pmos_right.get_pin("S").bc()])
# add contacts to connect gate poly to drain/source metal1 (to connect Q to Q_bar) # add contacts to connect gate poly to drain/source metal1 (to connect Q to Q_bar)
contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x + 0.5*contact.poly.height, self.cross_couple_upper_ypos) contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x + 0.5*contact.poly.height, self.cross_couple_upper_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset_left, offset=contact_offset_left,
rotate=90) directions=("H","H"))
contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x - 0.5*contact.poly.height, self.cross_couple_lower_ypos) contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x - 0.5*contact.poly.height, self.cross_couple_lower_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset_right, offset=contact_offset_right,
rotate=90) directions=("H","H"))
# connect contacts to gate poly (cross couple connections) # connect contacts to gate poly (cross couple connections)
gate_offset_right = vector(self.inverter_nmos_right.get_pin("G").lc().x, contact_offset_left.y) gate_offset_right = vector(self.inverter_nmos_right.get_pin("G").lc().x, contact_offset_left.y)
@ -395,7 +396,6 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.rw_bl_names[k], self.add_layout_pin_rect_center(text=self.rw_bl_names[k],
layer="metal2", layer="metal2",
offset=self.rwbl_positions[k], offset=self.rwbl_positions[k],
width=drc["minwidth_metal2"],
height=self.height) height=self.height)
rwbr_xpos = right_readwrite_transistor_xpos + self.readwrite_nmos.active_width + self.bitline_offset - 0.5*self.m2_width rwbr_xpos = right_readwrite_transistor_xpos + self.readwrite_nmos.active_width + self.bitline_offset - 0.5*self.m2_width
@ -403,7 +403,6 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.rw_br_names[k], self.add_layout_pin_rect_center(text=self.rw_br_names[k],
layer="metal2", layer="metal2",
offset=self.rwbr_positions[k], offset=self.rwbr_positions[k],
width=drc["minwidth_metal2"],
height=self.height) height=self.height)
# update furthest left and right transistor edges # update furthest left and right transistor edges
@ -472,7 +471,6 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.w_bl_names[k], self.add_layout_pin_rect_center(text=self.w_bl_names[k],
layer="metal2", layer="metal2",
offset=self.wbl_positions[k], offset=self.wbl_positions[k],
width=drc["minwidth_metal2"],
height=self.height) height=self.height)
wbr_xpos = right_write_transistor_xpos + self.write_nmos.active_width + self.bitline_offset - 0.5*self.m2_width wbr_xpos = right_write_transistor_xpos + self.write_nmos.active_width + self.bitline_offset - 0.5*self.m2_width
@ -480,7 +478,6 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.w_br_names[k], self.add_layout_pin_rect_center(text=self.w_br_names[k],
layer="metal2", layer="metal2",
offset=self.wbr_positions[k], offset=self.wbr_positions[k],
width=drc["minwidth_metal2"],
height=self.height) height=self.height)
# update furthest left and right transistor edges # update furthest left and right transistor edges
@ -571,7 +568,6 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.r_bl_names[k], self.add_layout_pin_rect_center(text=self.r_bl_names[k],
layer="metal2", layer="metal2",
offset=self.rbl_positions[k], offset=self.rbl_positions[k],
width=drc["minwidth_metal2"],
height=self.height) height=self.height)
rbr_xpos = right_read_transistor_xpos + self.read_port_width + self.bitline_offset - 0.5*self.m2_width rbr_xpos = right_read_transistor_xpos + self.read_port_width + self.bitline_offset - 0.5*self.m2_width
@ -579,7 +575,6 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.r_br_names[k], self.add_layout_pin_rect_center(text=self.r_br_names[k],
layer="metal2", layer="metal2",
offset=self.rbr_positions[k], offset=self.rbr_positions[k],
width=drc["minwidth_metal2"],
height=self.height) height=self.height)
def route_wordlines(self): def route_wordlines(self):
@ -613,21 +608,21 @@ class pbitcell(design.design):
# first transistor on either side of the cross coupled inverters does not need to route to wordline on metal2 # first transistor on either side of the cross coupled inverters does not need to route to wordline on metal2
if (k == 0) or (k == 1): if (k == 0) or (k == 1):
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset) offset=port_contact_offset)
self.add_path("poly", [gate_offset, port_contact_offset]) self.add_path("poly", [gate_offset, port_contact_offset])
self.add_path("metal1", [port_contact_offset, wl_contact_offset]) self.add_path("metal1", [port_contact_offset, wl_contact_offset])
else: else:
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset) offset=port_contact_offset)
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offset) offset=port_contact_offset)
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=wl_contact_offset, offset=wl_contact_offset,
rotate=90) directions=("H","H"))
self.add_path("poly", [gate_offset, port_contact_offset]) self.add_path("poly", [gate_offset, port_contact_offset])
self.add_path("metal2", [port_contact_offset, wl_contact_offset]) self.add_path("metal2", [port_contact_offset, wl_contact_offset])
@ -662,7 +657,7 @@ class pbitcell(design.design):
port_contact_offest = left_port_transistors[k].get_pin("S").center() port_contact_offest = left_port_transistors[k].get_pin("S").center()
bl_offset = vector(bl_positions[k].x, port_contact_offest.y) bl_offset = vector(bl_positions[k].x, port_contact_offest.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest) offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, bl_offset], width=contact.m1m2.height) self.add_path("metal2", [port_contact_offest, bl_offset], width=contact.m1m2.height)
@ -671,7 +666,7 @@ class pbitcell(design.design):
port_contact_offest = right_port_transistors[k].get_pin("D").center() port_contact_offest = right_port_transistors[k].get_pin("D").center()
br_offset = vector(br_positions[k].x, port_contact_offest.y) br_offset = vector(br_positions[k].x, port_contact_offest.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest) offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, br_offset], width=contact.m1m2.height) self.add_path("metal2", [port_contact_offest, br_offset], width=contact.m1m2.height)
@ -687,7 +682,7 @@ class pbitcell(design.design):
nmos_contact_positions.append(self.read_access_nmos_right[k].get_pin("S").center()) nmos_contact_positions.append(self.read_access_nmos_right[k].get_pin("S").center())
for position in nmos_contact_positions: for position in nmos_contact_positions:
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=position) offset=position)
if position.x > 0: if position.x > 0:
@ -695,9 +690,9 @@ class pbitcell(design.design):
else: else:
contact_correct = -0.5*contact.m1m2.height contact_correct = -0.5*contact.m1m2.height
supply_offset = vector(position.x + contact_correct, self.gnd_position.y) supply_offset = vector(position.x + contact_correct, self.gnd_position.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=supply_offset, offset=supply_offset,
rotate=90) directions=("H","H"))
self.add_path("metal2", [position, supply_offset]) self.add_path("metal2", [position, supply_offset])
@ -713,39 +708,35 @@ class pbitcell(design.design):
for k in range(self.num_rw_ports): for k in range(self.num_rw_ports):
mid = vector(self.readwrite_nmos_left[k].get_pin("D").uc().x, self.cross_couple_lower_ypos) mid = vector(self.readwrite_nmos_left[k].get_pin("D").uc().x, self.cross_couple_lower_ypos)
Q_pos = vector(self.inverter_nmos_left.get_pin("D").lx(), self.cross_couple_lower_ypos) Q_pos = vector(self.inverter_nmos_left.get_pin("D").lx(), self.cross_couple_lower_ypos)
self.add_path("metal1", [self.readwrite_nmos_left[k].get_pin("D").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width) self.add_path("metal1", [self.readwrite_nmos_left[k].get_pin("D").uc(), mid, Q_pos])
self.add_path("metal1", [mid, Q_pos])
mid = vector(self.readwrite_nmos_right[k].get_pin("S").uc().x, self.cross_couple_lower_ypos) mid = vector(self.readwrite_nmos_right[k].get_pin("S").uc().x, self.cross_couple_lower_ypos)
Q_bar_pos = vector(self.inverter_nmos_right.get_pin("S").rx(), self.cross_couple_lower_ypos) Q_bar_pos = vector(self.inverter_nmos_right.get_pin("S").rx(), self.cross_couple_lower_ypos)
self.add_path("metal1", [self.readwrite_nmos_right[k].get_pin("S").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width) self.add_path("metal1", [self.readwrite_nmos_right[k].get_pin("S").uc(), mid, Q_bar_pos])
self.add_path("metal1", [mid, Q_bar_pos])
def route_write_access(self): def route_write_access(self):
""" Routes read/write transistors to the storage component of the bitcell """ """ Routes read/write transistors to the storage component of the bitcell """
for k in range(self.num_w_ports): for k in range(self.num_w_ports):
mid = vector(self.write_nmos_left[k].get_pin("D").uc().x, self.cross_couple_lower_ypos) mid = vector(self.write_nmos_left[k].get_pin("D").uc().x, self.cross_couple_lower_ypos)
Q_pos = vector(self.inverter_nmos_left.get_pin("D").lx(), self.cross_couple_lower_ypos) Q_pos = vector(self.inverter_nmos_left.get_pin("D").lx(), self.cross_couple_lower_ypos)
self.add_path("metal1", [self.write_nmos_left[k].get_pin("D").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width) self.add_path("metal1", [self.write_nmos_left[k].get_pin("D").uc(), mid, Q_pos])
self.add_path("metal1", [mid, Q_pos])
mid = vector(self.write_nmos_right[k].get_pin("S").uc().x, self.cross_couple_lower_ypos) mid = vector(self.write_nmos_right[k].get_pin("S").uc().x, self.cross_couple_lower_ypos)
Q_bar_pos = vector(self.inverter_nmos_right.get_pin("S").rx(), self.cross_couple_lower_ypos) Q_bar_pos = vector(self.inverter_nmos_right.get_pin("S").rx(), self.cross_couple_lower_ypos)
self.add_path("metal1", [self.write_nmos_right[k].get_pin("S").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width) self.add_path("metal1", [self.write_nmos_right[k].get_pin("S").uc(), mid, Q_bar_pos])
self.add_path("metal1", [mid, Q_bar_pos])
def route_read_access(self): def route_read_access(self):
""" Routes read access transistors to the storage component of the bitcell """ """ Routes read access transistors to the storage component of the bitcell """
# add poly to metal1 contacts for gates of the inverters # add poly to metal1 contacts for gates of the inverters
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_polycontact"] - 0.5*contact.poly.width, self.cross_couple_upper_ypos) left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - self.poly_to_polycontact - 0.5*contact.poly.width, self.cross_couple_upper_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=left_storage_contact, offset=left_storage_contact,
rotate=90) directions=("H","H"))
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + drc["poly_to_polycontact"] + 0.5*contact.poly.width, self.cross_couple_upper_ypos) right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + self.poly_to_polycontact + 0.5*contact.poly.width, self.cross_couple_upper_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=right_storage_contact, offset=right_storage_contact,
rotate=90) directions=("H","H"))
inverter_gate_offset_left = vector(self.inverter_nmos_left.get_pin("G").lc().x, self.cross_couple_upper_ypos) inverter_gate_offset_left = vector(self.inverter_nmos_left.get_pin("G").lc().x, self.cross_couple_upper_ypos)
self.add_path("poly", [left_storage_contact, inverter_gate_offset_left]) self.add_path("poly", [left_storage_contact, inverter_gate_offset_left])
@ -758,25 +749,23 @@ class pbitcell(design.design):
for k in range(self.num_r_ports): for k in range(self.num_r_ports):
port_contact_offset = self.read_access_nmos_left[k].get_pin("G").uc() + vector(0, self.gate_contact_yoffset - self.poly_extend_active) port_contact_offset = self.read_access_nmos_left[k].get_pin("G").uc() + vector(0, self.gate_contact_yoffset - self.poly_extend_active)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset) offset=port_contact_offset)
self.add_path("poly", [self.read_access_nmos_left[k].get_pin("G").uc(), port_contact_offset]) self.add_path("poly", [self.read_access_nmos_left[k].get_pin("G").uc(), port_contact_offset])
mid = vector(self.read_access_nmos_left[k].get_pin("G").uc().x, self.cross_couple_upper_ypos) mid = vector(self.read_access_nmos_left[k].get_pin("G").uc().x, self.cross_couple_upper_ypos)
self.add_path("metal1", [port_contact_offset, mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width) self.add_path("metal1", [port_contact_offset, mid, left_storage_contact])
self.add_path("metal1", [mid, left_storage_contact])
port_contact_offset = self.read_access_nmos_right[k].get_pin("G").uc() + vector(0, self.gate_contact_yoffset - self.poly_extend_active) port_contact_offset = self.read_access_nmos_right[k].get_pin("G").uc() + vector(0, self.gate_contact_yoffset - self.poly_extend_active)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset) offset=port_contact_offset)
self.add_path("poly", [self.read_access_nmos_right[k].get_pin("G").uc(), port_contact_offset]) self.add_path("poly", [self.read_access_nmos_right[k].get_pin("G").uc(), port_contact_offset])
mid = vector(self.read_access_nmos_right[k].get_pin("G").uc().x, self.cross_couple_upper_ypos) mid = vector(self.read_access_nmos_right[k].get_pin("G").uc().x, self.cross_couple_upper_ypos)
self.add_path("metal1", [port_contact_offset, mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width) self.add_path("metal1", [port_contact_offset, mid, right_storage_contact])
self.add_path("metal1", [mid, right_storage_contact])
def extend_well(self): def extend_well(self):
""" """
@ -795,13 +784,13 @@ class pbitcell(design.design):
# extend nwell to encompass inverter_pmos # extend nwell to encompass inverter_pmos
# calculate offset of the left pmos well # calculate offset of the left pmos well
inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) - drc["well_enclosure_active"] inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) - self.well_enclose_active
inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap - drc["well_enclosure_active"] inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap - self.well_enclose_active
# calculate width of the two combined nwells # calculate width of the two combined nwells
# calculate height to encompass nimplant connected to vdd # calculate height to encompass nimplant connected to vdd
well_width = 2*(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) + 2*drc["well_enclosure_active"] well_width = 2*(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) + 2*self.well_enclose_active
well_height = self.vdd_position.y - inverter_well_ypos + drc["well_enclosure_active"] + drc["minwidth_tx"] well_height = self.vdd_position.y - inverter_well_ypos + self.well_enclose_active + drc["minwidth_tx"]
offset = [inverter_well_xpos,inverter_well_ypos] offset = [inverter_well_xpos,inverter_well_ypos]
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
@ -812,17 +801,17 @@ class pbitcell(design.design):
# add well contacts # add well contacts
# connect pimplants to gnd # connect pimplants to gnd
offset = vector(0, self.gnd_position.y) offset = vector(0, self.gnd_position.y)
self.add_contact_center(layers=("active", "contact", "metal1"), self.add_via_center(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
rotate=90, directions=("H","H"),
implant_type="p", implant_type="p",
well_type="p") well_type="p")
# connect nimplants to vdd # connect nimplants to vdd
offset = vector(0, self.vdd_position.y) offset = vector(0, self.vdd_position.y)
self.add_contact_center(layers=("active", "contact", "metal1"), self.add_via_center(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
rotate=90, directions=("H","H"),
implant_type="n", implant_type="n",
well_type="n") well_type="n")

View File

@ -800,14 +800,11 @@ class bank(design.design):
bus_pos = vector(self.bus_xoffset[port][name].x, out_pos.y) bus_pos = vector(self.bus_xoffset[port][name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos]) self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos, offset=bus_pos)
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_pos, offset=out_pos)
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=out_pos, offset=out_pos)
rotate=90)
def setup_routing_constraints(self): def setup_routing_constraints(self):
@ -1197,8 +1194,7 @@ class bank(design.design):
control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y) control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y)
self.add_path("metal1", [control_pos, pin_pos]) self.add_path("metal1", [control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos, offset=control_pos)
rotate=90)
# clk to wordline_driver # clk to wordline_driver
control_signal = self.prefix+"wl_en{}".format(port) control_signal = self.prefix+"wl_en{}".format(port)
@ -1212,8 +1208,7 @@ class bank(design.design):
control_pos = vector(control_x_offset, mid_pos.y) control_pos = vector(control_x_offset, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos]) self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos, offset=control_pos)
rotate=90)
def analytical_delay(self, corner, slew, load, port): def analytical_delay(self, corner, slew, load, port):
""" return analytical delay of the bank. This will track the clock to output path""" """ return analytical delay of the bank. This will track the clock to output path"""

View File

@ -213,7 +213,7 @@ class bank_select(design.design):
end=bank_sel_pin_end) end=bank_sel_pin_end)
self.add_via_center(layers=("metal2","via2","metal3"), self.add_via_center(layers=("metal2","via2","metal3"),
offset=bank_sel_pin_end, offset=bank_sel_pin_end,
rotate=90) directions=("H","H"))
# bank_sel_bar is vertical wire # bank_sel_bar is vertical wire
bank_sel_bar_pin = self.bank_sel_inv.get_pin("Z") bank_sel_bar_pin = self.bank_sel_inv.get_pin("Z")
@ -252,7 +252,7 @@ class bank_select(design.design):
self.add_path("metal2",[logic_pos, input_pos]) self.add_path("metal2",[logic_pos, input_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos, offset=logic_pos,
rotate=90) directions=("H","H"))
# Connect the logic A input to the input pin # Connect the logic A input to the input pin
@ -260,10 +260,10 @@ class bank_select(design.design):
input_pos = vector(0,logic_pos.y) input_pos = vector(0,logic_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos, offset=logic_pos,
rotate=90) directions=("H","H"))
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=logic_pos, offset=logic_pos,
rotate=90) directions=("H","H"))
self.add_layout_pin_segment_center(text=input_name, self.add_layout_pin_segment_center(text=input_name,
layer="metal3", layer="metal3",
start=input_pos, start=input_pos,
@ -295,10 +295,10 @@ class bank_select(design.design):
pin_pos = vector(xoffset, supply_pin.cy()) pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos, offset=pin_pos,
rotate=90) directions=("H","H"))
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos, offset=pin_pos,
rotate=90) directions=("H","H"))
self.add_layout_pin_rect_center(text=n, self.add_layout_pin_rect_center(text=n,
layer="metal3", layer="metal3",
offset=pin_pos) offset=pin_pos)

View File

@ -128,7 +128,7 @@ class bitcell_array(design.design):
inst = self.cell_inst[row,col] inst = self.cell_inst[row,col]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name): for pin in inst.get_pins(pin_name):
self.add_power_pin(pin_name, pin.center(), 0, pin.layer) self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
def analytical_delay(self, corner, slew, load): def analytical_delay(self, corner, slew, load):
"""Returns relative delay of the bitline in the bitcell array""" """Returns relative delay of the bitline in the bitcell array"""

View File

@ -615,11 +615,9 @@ class control_logic(design.design):
mid1 = vector(in_pos.x,out_pos.y) mid1 = vector(in_pos.x,out_pos.y)
self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, in_pos]) self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, in_pos])
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=out_pos, offset=out_pos)
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"), self.add_via_center(layers=("metal2","via2","metal3"),
offset=out_pos, offset=out_pos)
rotate=90)
def create_pen_row(self): def create_pen_row(self):
if self.port_type == "rw": if self.port_type == "rw":
@ -759,8 +757,7 @@ class control_logic(design.design):
rail_pos = vector(self.rail_offsets["clk_buf"].x, mid_pos.y) rail_pos = vector(self.rail_offsets["clk_buf"].x, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[in_pos, mid_pos, rail_pos]) self.add_wire(("metal1","via1","metal2"),[in_pos, mid_pos, rail_pos])
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail_pos, offset=rail_pos)
rotate=90)
self.copy_layout_pin(self.ctrl_dff_inst, "din_0", "csb") self.copy_layout_pin(self.ctrl_dff_inst, "din_0", "csb")
if (self.port_type == "rw"): if (self.port_type == "rw"):

View File

@ -213,11 +213,9 @@ class hierarchical_decoder(design.design):
""" Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """ """ Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=input_offset, offset=input_offset)
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=output_offset, offset=output_offset)
rotate=90)
self.add_path(("metal3"), [input_offset, output_offset]) self.add_path(("metal3"), [input_offset, output_offset])
@ -575,8 +573,7 @@ class hierarchical_decoder(design.design):
rail_pos = vector(self.predecode_rails[rail_name].x,pin.lc().y) rail_pos = vector(self.predecode_rails[rail_name].x,pin.lc().y)
self.add_path("metal1", [rail_pos, pin.lc()]) self.add_path("metal1", [rail_pos, pin.lc()])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_pos, offset=rail_pos)
rotate=90)
def route_predecode_rail_m3(self, rail_name, pin): def route_predecode_rail_m3(self, rail_name, pin):
@ -586,12 +583,10 @@ class hierarchical_decoder(design.design):
mid_point = vector(pin.cx(), pin.cy()+self.inv.height/2) mid_point = vector(pin.cx(), pin.cy()+self.inv.height/2)
rail_pos = vector(self.predecode_rails[rail_name].x,mid_point.y) rail_pos = vector(self.predecode_rails[rail_name].x,mid_point.y)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin.center(), offset=pin.center())
rotate=90)
self.add_wire(("metal3","via2","metal2"), [rail_pos, mid_point, pin.uc()]) self.add_wire(("metal3","via2","metal2"), [rail_pos, mid_point, pin.uc()])
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=rail_pos, offset=rail_pos)
rotate=90)
def analytical_delay(self, corner, slew, load = 0.0): def analytical_delay(self, corner, slew, load = 0.0):

View File

@ -178,11 +178,9 @@ class hierarchical_predecode(design.design):
a_pos = vector(self.decode_rails[a_pin].x,y_offset) a_pos = vector(self.decode_rails[a_pin].x,y_offset)
self.add_path("metal1",[in_pos, a_pos]) self.add_path("metal1",[in_pos, a_pos])
self.add_via_center(layers = ("metal1", "via1", "metal2"), self.add_via_center(layers = ("metal1", "via1", "metal2"),
offset=[self.input_rails[in_pin].x, y_offset], offset=[self.input_rails[in_pin].x, y_offset])
rotate=90)
self.add_via_center(layers = ("metal1", "via1", "metal2"), self.add_via_center(layers = ("metal1", "via1", "metal2"),
offset=[self.decode_rails[a_pin].x, y_offset], offset=[self.decode_rails[a_pin].x, y_offset])
rotate=90)
def route_output_inverters(self): def route_output_inverters(self):
""" """
@ -223,8 +221,7 @@ class hierarchical_predecode(design.design):
rail_pos = vector(self.decode_rails[out_pin].x,y_offset) rail_pos = vector(self.decode_rails[out_pin].x,y_offset)
self.add_path("metal1", [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos]) self.add_path("metal1", [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos])
self.add_via_center(layers = ("metal1", "via1", "metal2"), self.add_via_center(layers = ("metal1", "via1", "metal2"),
offset=rail_pos, offset=rail_pos)
rotate=90)
#route input #route input
@ -232,8 +229,7 @@ class hierarchical_predecode(design.design):
in_pos = vector(self.input_rails[in_pin].x,inv_in_pos.y) in_pos = vector(self.input_rails[in_pin].x,inv_in_pos.y)
self.add_path("metal1", [in_pos, inv_in_pos]) self.add_path("metal1", [in_pos, inv_in_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=in_pos, offset=in_pos)
rotate=90)
def route_nand_to_rails(self): def route_nand_to_rails(self):
@ -254,8 +250,8 @@ class hierarchical_predecode(design.design):
rail_pos = vector(self.decode_rails[rail_pin].x, pin_pos.y) rail_pos = vector(self.decode_rails[rail_pin].x, pin_pos.y)
self.add_path("metal1", [rail_pos, pin_pos]) self.add_path("metal1", [rail_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_pos, offset=rail_pos)
rotate=90)

View File

@ -39,8 +39,8 @@ class replica_bitline(design.design):
#self.add_lvs_correspondence_points() #self.add_lvs_correspondence_points()
# Extra pitch on top and right # Extra pitch on top and right
self.width = self.rbl_inst.rx() - self.dc_inst.lx() + self.m2_pitch self.width = self.replica_column_inst.rx() - self.delay_chain_inst.lx() + self.m2_pitch
self.height = max(self.rbl_inst.uy(), self.dc_inst.uy()) + self.m3_pitch self.height = max(self.replica_column_inst.uy(), self.delay_chain_inst.uy()) + self.m3_pitch
self.DRC_LVS() self.DRC_LVS()
@ -111,11 +111,11 @@ class replica_bitline(design.design):
self.connect_inst(["vdd", "delayed_en", "bl0_0", "vdd"]) self.connect_inst(["vdd", "delayed_en", "bl0_0", "vdd"])
# add the well and poly contact # add the well and poly contact
self.dc_inst=self.add_inst(name="delay_chain", self.delay_chain_inst=self.add_inst(name="delay_chain",
mod=self.delay_chain) mod=self.delay_chain)
self.connect_inst(["en", "delayed_en", "vdd", "gnd"]) self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
self.rbc_inst=self.add_inst(name="bitcell", self.replica_cell_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell) mod=self.replica_bitcell)
temp = [] temp = []
for port in self.all_ports: for port in self.all_ports:
@ -127,7 +127,7 @@ class replica_bitline(design.design):
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
self.rbl_inst=self.add_inst(name="load", self.replica_column_inst=self.add_inst(name="load",
mod=self.rbl) mod=self.rbl)
temp = [] temp = []
@ -153,12 +153,12 @@ class replica_bitline(design.design):
self.tx_inst.place(self.access_tx_offset) self.tx_inst.place(self.access_tx_offset)
self.dc_inst.place(self.delay_chain_offset) self.delay_chain_inst.place(self.delay_chain_offset)
self.rbc_inst.place(offset=self.bitcell_offset, self.replica_cell_inst.place(offset=self.bitcell_offset,
mirror="MX") mirror="MX")
self.rbl_inst.place(self.rbl_offset) self.replica_column_inst.place(self.rbl_offset)
def route(self): def route(self):
@ -172,7 +172,7 @@ class replica_bitline(design.design):
# Connect the WL and gnd pins directly to the center and right gnd rails # Connect the WL and gnd pins directly to the center and right gnd rails
for row in range(self.bitcell_loads): for row in range(self.bitcell_loads):
wl = self.wl_list[0]+"_{}".format(row) wl = self.wl_list[0]+"_{}".format(row)
pin = self.rbl_inst.get_pin(wl) pin = self.replica_column_inst.get_pin(wl)
# Route the connection to the right so that it doesn't interfere with the cells # Route the connection to the right so that it doesn't interfere with the cells
# Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions # Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
@ -188,7 +188,7 @@ class replica_bitline(design.design):
# for multiport, need to short wordlines to each other so they all connect to gnd. # for multiport, need to short wordlines to each other so they all connect to gnd.
wl_last = self.wl_list[-1]+"_{}".format(row) wl_last = self.wl_list[-1]+"_{}".format(row)
pin_last = self.rbl_inst.get_pin(wl_last) pin_last = self.replica_column_inst.get_pin(wl_last)
self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0)) self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0))
def short_wordlines(self, wl_pin_a, wl_pin_b, pin_side, is_replica_cell, cell_row=0, offset_x_vec=None): def short_wordlines(self, wl_pin_a, wl_pin_b, pin_side, is_replica_cell, cell_row=0, offset_x_vec=None):
@ -229,10 +229,10 @@ class replica_bitline(design.design):
for port in self.all_ports: for port in self.all_ports:
if is_replica_cell: if is_replica_cell:
wl = self.wl_list[port] wl = self.wl_list[port]
pin = self.rbc_inst.get_pin(wl) pin = self.replica_cell_inst.get_pin(wl)
else: else:
wl = self.wl_list[port]+"_{}".format(cell_row) wl = self.wl_list[port]+"_{}".format(cell_row)
pin = self.rbl_inst.get_pin(wl) pin = self.replica_column_inst.get_pin(wl)
if pin_side == "left": if pin_side == "left":
self.add_path("metal1", [pin.lc()-correct_x, pin.lc()]) self.add_path("metal1", [pin.lc()-correct_x, pin.lc()])
@ -245,8 +245,8 @@ class replica_bitline(design.design):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has # These are the instances that every bank has
top_instances = [self.rbl_inst, top_instances = [self.replica_column_inst,
self.dc_inst] self.delay_chain_inst]
for inst in top_instances: for inst in top_instances:
self.copy_layout_pin(inst, "vdd") self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd") self.copy_layout_pin(inst, "gnd")
@ -257,11 +257,11 @@ class replica_bitline(design.design):
pin = self.rbl_inv_inst.get_pin("vdd") pin = self.rbl_inv_inst.get_pin("vdd")
self.add_power_pin("vdd", pin.lc()) self.add_power_pin("vdd", pin.lc())
pin=self.rbc_inst.get_pin("vdd") for pin in self.replica_cell_inst.get_pins("vdd"):
self.add_power_pin("vdd", pin.center(), 0, pin.layer) self.add_power_pin(name="vdd", loc=pin.center(), vertical=True, start_layer=pin.layer)
for pin in self.rbc_inst.get_pins("gnd"): for pin in self.replica_cell_inst.get_pins("gnd"):
self.add_power_pin("gnd", pin.center()) self.add_power_pin("gnd", pin.center(), vertical=True, start_layer=pin.layer)
@ -275,9 +275,9 @@ class replica_bitline(design.design):
poly_offset = poly_pin.uc() poly_offset = poly_pin.uc()
# This centers the contact above the poly by one pitch # This centers the contact above the poly by one pitch
contact_offset = poly_offset + vector(0,self.m2_pitch) contact_offset = poly_offset + vector(0,self.m2_pitch)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset) offset=contact_offset)
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=contact_offset) offset=contact_offset)
self.add_segment_center(layer="poly", self.add_segment_center(layer="poly",
start=poly_offset, start=poly_offset,
@ -289,12 +289,12 @@ class replica_bitline(design.design):
# height=self.delay_chain_offset.y-nwell_offset.y) # height=self.delay_chain_offset.y-nwell_offset.y)
# 2. Route delay chain output to access tx gate # 2. Route delay chain output to access tx gate
delay_en_offset = self.dc_inst.get_pin("out").bc() delay_en_offset = self.delay_chain_inst.get_pin("out").bc()
self.add_path("metal2", [delay_en_offset,contact_offset]) self.add_path("metal2", [delay_en_offset,contact_offset])
# 3. Route the contact of previous route to the bitcell WL # 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL # route bend of previous net to bitcell WL
wl_offset = self.rbc_inst.get_pin(self.wl_list[0]).lc() wl_offset = self.replica_cell_inst.get_pin(self.wl_list[0]).lc()
wl_mid1 = wl_offset - vector(1.5*drc("minwidth_metal1"), 0) wl_mid1 = wl_offset - vector(1.5*drc("minwidth_metal1"), 0)
wl_mid2 = vector(wl_mid1.x, contact_offset.y) wl_mid2 = vector(wl_mid1.x, contact_offset.y)
#xmid_point= 0.5*(wl_offset.x+contact_offset.x) #xmid_point= 0.5*(wl_offset.x+contact_offset.x)
@ -305,8 +305,8 @@ class replica_bitline(design.design):
# 4. Short wodlines if multiport # 4. Short wodlines if multiport
wl = self.wl_list[0] wl = self.wl_list[0]
wl_last = self.wl_list[-1] wl_last = self.wl_list[-1]
pin = self.rbc_inst.get_pin(wl) pin = self.replica_cell_inst.get_pin(wl)
pin_last = self.rbc_inst.get_pin(wl_last) pin_last = self.replica_cell_inst.get_pin(wl_last)
x_offset = self.short_wordlines(pin, pin_last, "left", True) x_offset = self.short_wordlines(pin, pin_last, "left", True)
#correct = vector(0.5*drc("minwidth_metal1"), 0) #correct = vector(0.5*drc("minwidth_metal1"), 0)
@ -315,7 +315,7 @@ class replica_bitline(design.design):
# DRAIN ROUTE # DRAIN ROUTE
# Route the drain to the vdd rail # Route the drain to the vdd rail
drain_offset = self.tx_inst.get_pin("D").center() drain_offset = self.tx_inst.get_pin("D").center()
self.add_power_pin("vdd", drain_offset, rotate=0) self.add_power_pin("vdd", drain_offset, vertical=True)
# SOURCE ROUTE # SOURCE ROUTE
# Route the drain to the RBL inverter input # Route the drain to the RBL inverter input
@ -325,7 +325,7 @@ class replica_bitline(design.design):
# Route the connection of the source route to the RBL bitline (left) # Route the connection of the source route to the RBL bitline (left)
# Via will go halfway down from the bitcell # Via will go halfway down from the bitcell
bl_offset = self.rbc_inst.get_pin(self.bl_list[0]).bc() bl_offset = self.replica_cell_inst.get_pin(self.bl_list[0]).bc()
# Route down a pitch so we can use M2 routing # Route down a pitch so we can use M2 routing
bl_down_offset = bl_offset - vector(0, self.m2_pitch) bl_down_offset = bl_offset - vector(0, self.m2_pitch)
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset]) self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
@ -344,12 +344,12 @@ class replica_bitline(design.design):
def route_vdd(self): def route_vdd(self):
""" Route all signals connected to vdd """ """ Route all signals connected to vdd """
self.copy_layout_pin(self.dc_inst,"vdd") self.copy_layout_pin(self.delay_chain_inst,"vdd")
self.copy_layout_pin(self.rbc_inst,"vdd") self.copy_layout_pin(self.replica_cell_inst,"vdd")
# Connect the WL and vdd pins directly to the center and right vdd rails # Connect the WL and vdd pins directly to the center and right vdd rails
# Connect RBL vdd pins to center and right rails # Connect RBL vdd pins to center and right rails
rbl_vdd_pins = self.rbl_inst.get_pins("vdd") rbl_vdd_pins = self.replica_column_inst.get_pins("vdd")
for pin in rbl_vdd_pins: for pin in rbl_vdd_pins:
if pin.layer != "metal1": if pin.layer != "metal1":
continue continue
@ -360,11 +360,9 @@ class replica_bitline(design.design):
start=start, start=start,
end=end) end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start, offset=start)
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end, offset=end)
rotate=90)
# Add via for the inverter # Add via for the inverter
pin = self.rbl_inv_inst.get_pin("vdd") pin = self.rbl_inv_inst.get_pin("vdd")
@ -374,38 +372,34 @@ class replica_bitline(design.design):
start=start, start=start,
end=end) end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start, offset=start)
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end, offset=end)
rotate=90)
# Add via for the RBC # Add via for the RBC
pin = self.rbc_inst.get_pin("vdd") pin = self.replica_cell_inst.get_pin("vdd")
start = pin.lc() start = pin.lc()
end = vector(self.right_vdd_pin.cx(),pin.cy()) end = vector(self.right_vdd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1", self.add_segment_center(layer="metal1",
start=start, start=start,
end=end) end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end, offset=end)
rotate=90)
# Create the RBL rails too # Create the RBL rails too
rbl_pins = self.rbl_inst.get_pins("vdd") rbl_pins = self.replica_column_inst.get_pins("vdd")
for pin in rbl_pins: for pin in rbl_pins:
if pin.layer != "metal1": if pin.layer != "metal1":
continue continue
# If above the delay line, route the full width # If above the delay line, route the full width
left = vector(self.left_vdd_pin.cx(),pin.cy()) left = vector(self.left_vdd_pin.cx(),pin.cy())
center = vector(self.center_vdd_pin.cx(),pin.cy()) center = vector(self.center_vdd_pin.cx(),pin.cy())
if pin.cy() > self.dc_inst.uy() + self.m1_pitch: if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
start = left start = left
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left, offset=left)
rotate=90)
else: else:
start = center start = center
end = vector(self.right_vdd_pin.cx()+0.5*self.m1_width,pin.cy()) end = vector(self.right_vdd_pin.cx()+0.5*self.m1_width,pin.cy())
@ -425,22 +419,22 @@ class replica_bitline(design.design):
# Route the gnd lines from left to right # Route the gnd lines from left to right
# Add via for the delay chain # Add via for the delay chain
left_gnd_start = self.dc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0) left_gnd_start = self.delay_chain_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
left_gnd_end = vector(left_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch) left_gnd_end = vector(left_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
self.left_gnd_pin=self.add_segment_center(layer="metal2", self.left_gnd_pin=self.add_segment_center(layer="metal2",
start=left_gnd_start, start=left_gnd_start,
end=left_gnd_end) end=left_gnd_end)
# Gnd line to the left of the replica bitline # Gnd line to the left of the replica bitline
center_gnd_start = self.rbc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0) center_gnd_start = self.replica_cell_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
center_gnd_end = vector(center_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch) center_gnd_end = vector(center_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
self.center_gnd_pin=self.add_segment_center(layer="metal2", self.center_gnd_pin=self.add_segment_center(layer="metal2",
start=center_gnd_start, start=center_gnd_start,
end=center_gnd_end) end=center_gnd_end)
# Gnd line to the right of the replica bitline # Gnd line to the right of the replica bitline
right_gnd_start = self.rbc_inst.lr().scale(1,0) + vector(self.m2_pitch,0) right_gnd_start = self.replica_cell_inst.lr().scale(1,0) + vector(self.m2_pitch,0)
right_gnd_end = vector(right_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch) right_gnd_end = vector(right_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
self.right_gnd_pin=self.add_segment_center(layer="metal2", self.right_gnd_pin=self.add_segment_center(layer="metal2",
start=right_gnd_start, start=right_gnd_start,
end=right_gnd_end) end=right_gnd_end)
@ -450,13 +444,13 @@ class replica_bitline(design.design):
# Connect the WL and gnd pins directly to the center and right gnd rails # Connect the WL and gnd pins directly to the center and right gnd rails
for row in range(self.bitcell_loads): for row in range(self.bitcell_loads):
wl = self.wl_list[0]+"_{}".format(row) wl = self.wl_list[0]+"_{}".format(row)
pin = self.rbl_inst.get_pin(wl) pin = self.replica_column_inst.get_pin(wl)
if pin.layer != "metal1": if pin.layer != "metal1":
continue continue
# If above the delay line, route the full width # If above the delay line, route the full width
left = vector(self.left_gnd_pin.cx(),pin.cy()) left = vector(self.left_gnd_pin.cx(),pin.cy())
center = vector(self.center_gnd_pin.cx(),pin.cy()) center = vector(self.center_gnd_pin.cx(),pin.cy())
if pin.cy() > self.dc_inst.uy() + self.m1_pitch: if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
start = left start = left
else: else:
start = center start = center
@ -467,47 +461,41 @@ class replica_bitline(design.design):
end=end) end=end)
if start == left: if start == left:
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left, offset=left)
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=center, offset=center)
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end, offset=end)
rotate=90)
rbl_gnd_pins = self.rbl_inst.get_pins("gnd") # rbl_gnd_pins = self.replica_column_inst.get_pins("gnd")
# Add L shapes to each vertical gnd rail # # Add L shapes to each vertical gnd rail
for pin in rbl_gnd_pins: # for pin in rbl_gnd_pins:
if pin.layer != "metal1": # if pin.layer != "metal1":
continue # continue
# If above the delay line, route the full width # # If above the delay line, route the full width
left = vector(self.left_gnd_pin.cx(),pin.cy()) # left = vector(self.left_gnd_pin.cx(),pin.cy())
center = vector(self.center_gnd_pin.cx(),pin.cy()) # center = vector(self.center_gnd_pin.cx(),pin.cy())
if pin.cy() > self.dc_inst.uy() + self.m1_pitch: # if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
start = left # start = left
else: # else:
start = center # start = center
end = vector(self.right_gnd_pin.cx(),pin.cy()) # end = vector(self.right_gnd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1", # self.add_segment_center(layer="metal1",
start=start, # start=start,
end=end) # end=end)
if start == left: # if start == left:
self.add_via_center(layers=("metal1", "via1", "metal2"), # self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left, # offset=left)
rotate=90) # self.add_via_center(layers=("metal1", "via1", "metal2"),
self.add_via_center(layers=("metal1", "via1", "metal2"), # offset=center)
offset=center, # self.add_via_center(layers=("metal1", "via1", "metal2"),
rotate=90) # offset=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
# Connect the gnd pins of the delay chain to the left rails # Connect the gnd pins of the delay chain to the left rails
dc_gnd_pins = self.dc_inst.get_pins("gnd") dc_gnd_pins = self.delay_chain_inst.get_pins("gnd")
for pin in dc_gnd_pins: for pin in dc_gnd_pins:
if pin.layer != "metal1": if pin.layer != "metal1":
continue continue
@ -520,12 +508,10 @@ class replica_bitline(design.design):
start=start, start=start,
end=end) end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start, offset=start)
rotate=90)
# self.add_via_center(layers=("metal1", "via1", "metal2"), # self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end, # offset=end)
#rotate=90)
# Add via for the inverter # Add via for the inverter
@ -536,16 +522,14 @@ class replica_bitline(design.design):
# start=start, # start=start,
# end=end) # end=end)
# self.add_via_center(layers=("metal1", "via1", "metal2"), # self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=start, # offset=start)
#rotate=90)
# self.add_via_center(layers=("metal1", "via1", "metal2"), # self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end, # offset=end)
#rotate=90)
# Create RBL rails too # Create RBL rails too
rbl_pins = self.rbl_inst.get_pins("gnd") rbl_pins = self.replica_column_inst.get_pins("gnd")
for pin in rbl_pins: for pin in rbl_pins:
if pin.layer != "metal2": if pin.layer != "metal2":
continue continue
@ -560,7 +544,7 @@ class replica_bitline(design.design):
def add_layout_pins(self): def add_layout_pins(self):
""" Route the input and output signal """ """ Route the input and output signal """
en_offset = self.dc_inst.get_pin("in").bc() en_offset = self.delay_chain_inst.get_pin("in").bc()
self.add_layout_pin_segment_center(text="en", self.add_layout_pin_segment_center(text="en",
layer="metal2", layer="metal2",
start=en_offset, start=en_offset,
@ -587,7 +571,7 @@ class replica_bitline(design.design):
height=pin.height(), height=pin.height(),
width=pin.width()) width=pin.width())
pin = self.dc_inst.get_pin("out") pin = self.delay_chain_inst.get_pin("out")
self.add_label_pin(text="delayed_en", self.add_label_pin(text="delayed_en",
layer=pin.layer, layer=pin.layer,
offset=pin.ll(), offset=pin.ll(),

View File

@ -131,8 +131,7 @@ class single_level_column_mux_array(design.design):
self.add_layout_pin(text="sel_{}".format(j), self.add_layout_pin(text="sel_{}".format(j),
layer="metal1", layer="metal1",
offset=offset, offset=offset,
width=self.mux.width * self.columns, width=self.mux.width * self.columns)
height=contact.m1m2.width)
def add_vertical_poly_rail(self): def add_vertical_poly_rail(self):
""" Connect the poly to the address rails """ """ Connect the poly to the address rails """
@ -149,73 +148,60 @@ class single_level_column_mux_array(design.design):
offset = vector(gate_offset.x,self.get_pin("sel_{}".format(sel_index)).cy()) offset = vector(gate_offset.x,self.get_pin("sel_{}".format(sel_index)).cy())
# Add the poly contact with a shift to account for the rotation # Add the poly contact with a shift to account for the rotation
self.add_via_center(layers=("metal1", "contact", "poly"), self.add_via_center(layers=("metal1", "contact", "poly"),
offset=offset, offset=offset)
rotate=90)
self.add_path("poly", [offset, gate_offset]) self.add_path("poly", [offset, gate_offset])
def route_bitlines(self): def route_bitlines(self):
""" Connect the output bit-lines to form the appropriate width mux """ """ Connect the output bit-lines to form the appropriate width mux """
for j in range(self.columns): for j in range(self.columns):
bl_offset = self.mux_inst[j].get_pin("bl_out").ll() bl_offset = self.mux_inst[j].get_pin("bl_out").bc()
br_offset = self.mux_inst[j].get_pin("br_out").ll() br_offset = self.mux_inst[j].get_pin("br_out").bc()
bl_out_offset = bl_offset - vector(0,(self.words_per_row+1)*self.m1_pitch) bl_out_offset = bl_offset - vector(0,(self.words_per_row+1)*self.m1_pitch)
br_out_offset = br_offset - vector(0,(self.words_per_row+2)*self.m1_pitch) br_out_offset = br_offset - vector(0,(self.words_per_row+2)*self.m1_pitch)
bl_out_offset_end = bl_out_offset + vector(0,self.route_height)
br_out_offset_end = br_out_offset + vector(0,self.route_height)
if (j % self.words_per_row) == 0: if (j % self.words_per_row) == 0:
# Create the metal1 to connect the n-way mux output from the pass gate # Create the metal1 to connect the n-way mux output from the pass gate
# These will be located below the select lines. Yes, these are M2 width # These will be located below the select lines. Yes, these are M2 width
# to ensure vias are enclosed and M1 min width rules. # to ensure vias are enclosed and M1 min width rules.
width = contact.m1m2.width + self.mux.width * (self.words_per_row - 1) width = self.m2_width + self.mux.width * (self.words_per_row - 1)
self.add_rect(layer="metal1", self.add_path("metal1", [bl_out_offset, bl_out_offset+vector(width,0)])
offset=bl_out_offset, self.add_path("metal1", [br_out_offset, br_out_offset+vector(width,0)])
width=width,
height=drc("minwidth_metal2"))
self.add_rect(layer="metal1",
offset=br_out_offset,
width=width,
height=drc("minwidth_metal2"))
# Extend the bitline output rails and gnd downward on the first bit of each n-way mux # Extend the bitline output rails and gnd downward on the first bit of each n-way mux
self.add_layout_pin(text="bl_out_{}".format(int(j/self.words_per_row)), self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j/self.words_per_row)),
layer="metal2", layer="metal2",
offset=bl_out_offset.scale(1,0), start=bl_out_offset,
width=drc('minwidth_metal2'), end=bl_out_offset_end)
height=self.route_height) self.add_layout_pin_segment_center(text="br_out_{}".format(int(j/self.words_per_row)),
self.add_layout_pin(text="br_out_{}".format(int(j/self.words_per_row)),
layer="metal2", layer="metal2",
offset=br_out_offset.scale(1,0), start=br_out_offset,
width=drc('minwidth_metal2'), end=br_out_offset_end)
height=self.route_height)
# This via is on the right of the wire # This via is on the right of the wire
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=bl_out_offset + vector(contact.m1m2.height,0), offset=bl_out_offset)
rotate=90)
# This via is on the left of the wire # This via is on the left of the wire
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset= br_out_offset, offset=br_out_offset)
rotate=90)
else: else:
self.add_rect(layer="metal2", self.add_path("metal2", [ bl_out_offset, bl_out_offset_end])
offset=bl_out_offset, self.add_path("metal2", [ br_out_offset, br_out_offset_end])
width=drc('minwidth_metal2'),
height=self.route_height-bl_out_offset.y)
# This via is on the right of the wire # This via is on the right of the wire
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=bl_out_offset + vector(contact.m1m2.height,0), offset=bl_out_offset)
rotate=90)
self.add_rect(layer="metal2",
offset=br_out_offset,
width=drc('minwidth_metal2'),
height=self.route_height-br_out_offset.y)
# This via is on the left of the wire # This via is on the left of the wire
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset= br_out_offset, offset=br_out_offset)
rotate=90)
def analytical_delay(self, corner, slew, load): def analytical_delay(self, corner, slew, load):
from tech import parameter from tech import parameter

View File

@ -81,21 +81,13 @@ class wordline_driver(design.design):
(gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num) (gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num)
# Route both supplies # Route both supplies
for n in ["vdd", "gnd"]: for name in ["vdd", "gnd"]:
supply_pin = self.inv2_inst[num].get_pin(n) supply_pin = self.inv2_inst[num].get_pin(name)
# Add pins in two locations # Add pins in two locations
for xoffset in [a_xoffset, b_xoffset]: for xoffset in [a_xoffset, b_xoffset]:
pin_pos = vector(xoffset, supply_pin.cy()) pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_power_pin(name, pin_pos)
offset=pin_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
rotate=90)
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
@ -193,13 +185,14 @@ class wordline_driver(design.design):
start=input_offset, start=input_offset,
end=mid_via_offset) end=mid_via_offset)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=mid_via_offset) offset=mid_via_offset,
directions=("V","V"))
# now connect to the nand2 B # now connect to the nand2 B
self.add_path("metal2", [mid_via_offset, b_pos]) self.add_path("metal2", [mid_via_offset, b_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=b_pos - vector(0.5*contact.m1m2.height,0), offset=b_pos - vector(0.5*contact.m1m2.height,0),
rotate=90) directions=("H","H"))
# output each WL on the right # output each WL on the right

View File

@ -42,7 +42,7 @@ class pgate(design.design):
height=height, height=height,
width=source_pin.width()) width=source_pin.width())
def route_input_gate(self, pmos_inst, nmos_inst, ypos, name, position="left", rotate=90): def route_input_gate(self, pmos_inst, nmos_inst, ypos, name, position="left", rotate=False):
""" Route the input gate to the left side of the cell for access. """ Route the input gate to the left side of the cell for access.
Position specifies to place the contact the left, center, or right of gate. """ Position specifies to place the contact the left, center, or right of gate. """
@ -61,14 +61,16 @@ class pgate(design.design):
left_gate_offset = vector(nmos_gate_pin.lx(),ypos) left_gate_offset = vector(nmos_gate_pin.lx(),ypos)
# Center is completely symmetric. # Center is completely symmetric.
if rotate==90: if rotate:
contact_width = contact.poly.height contact_width = contact.poly.height
contact_m1_width = contact.poly.second_layer_height contact_m1_width = contact.poly.second_layer_height
contact_m1_height = contact.poly.second_layer_width contact_m1_height = contact.poly.second_layer_width
directions = ("H","V")
else: else:
contact_width = contact.poly.width contact_width = contact.poly.width
contact_m1_width = contact.poly.second_layer_width contact_m1_width = contact.poly.second_layer_width
contact_m1_height = contact.poly.second_layer_height contact_m1_height = contact.poly.second_layer_height
directions = ("V","H")
if position=="center": if position=="center":
contact_offset = left_gate_offset + vector(0.5*self.poly_width, 0) contact_offset = left_gate_offset + vector(0.5*self.poly_width, 0)
@ -79,9 +81,12 @@ class pgate(design.design):
else: else:
debug.error("Invalid contact placement option.", -1) debug.error("Invalid contact placement option.", -1)
self.add_contact_center(layers=("poly", "contact", "metal1"), # Non-preferred direction via
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset, offset=contact_offset,
rotate=rotate) directions=directions)
# self.add_layout_pin_segment_center(text=name, # self.add_layout_pin_segment_center(text=name,
# layer="metal1", # layer="metal1",
# start=left_gate_offset.scale(0,1), # start=left_gate_offset.scale(0,1),
@ -145,8 +150,9 @@ class pgate(design.design):
# Offset by half a contact in x and y # Offset by half a contact in x and y
contact_offset += vector(0.5*pmos.active_contact.first_layer_width, contact_offset += vector(0.5*pmos.active_contact.first_layer_width,
0.5*pmos.active_contact.first_layer_height) 0.5*pmos.active_contact.first_layer_height)
self.nwell_contact=self.add_contact_center(layers=layer_stack, self.nwell_contact=self.add_via_center(layers=layer_stack,
offset=contact_offset, offset=contact_offset,
directions=("H","V"),
implant_type="n", implant_type="n",
well_type="n") well_type="n")
self.add_rect_center(layer="metal1", self.add_rect_center(layer="metal1",
@ -191,8 +197,9 @@ class pgate(design.design):
# Offset by half a contact # Offset by half a contact
contact_offset += vector(0.5*nmos.active_contact.first_layer_width, contact_offset += vector(0.5*nmos.active_contact.first_layer_width,
0.5*nmos.active_contact.first_layer_height) 0.5*nmos.active_contact.first_layer_height)
self.pwell_contact=self.add_contact_center(layers=layer_stack, self.pwell_contact=self.add_via_center(layers=layer_stack,
offset=contact_offset, offset=contact_offset,
directions=("H","V"),
implant_type="p", implant_type="p",
well_type="p") well_type="p")
self.add_rect_center(layer="metal1", self.add_rect_center(layer="metal1",

View File

@ -58,7 +58,7 @@ class pinv(pgate.pgate):
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells(self.well_pos)
self.connect_rails() self.connect_rails()
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0) self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A")
self.route_outputs() self.route_outputs()
def add_pins(self): def add_pins(self):
@ -222,8 +222,8 @@ class pinv(pgate.pgate):
pmos_drain_pin = self.pmos_inst.get_pin("D") pmos_drain_pin = self.pmos_inst.get_pin("D")
# Pick point at right most of NMOS and connect down to PMOS # Pick point at right most of NMOS and connect down to PMOS
nmos_drain_pos = nmos_drain_pin.lr() - vector(0.5*self.m1_width,0) nmos_drain_pos = nmos_drain_pin.lr()
pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.bc().y) pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.uc().y)
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos]) self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
# Remember the mid for the output # Remember the mid for the output

View File

@ -203,13 +203,15 @@ class pnand2(pgate.pgate):
mid1_offset = vector(out_offset.x, top_pin_offset.y) mid1_offset = vector(out_offset.x, top_pin_offset.y)
mid2_offset = vector(out_offset.x, bottom_pin_offset.y) mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pmos_pin.center()) offset=pmos_pin.center(),
self.add_contact_center(layers=("metal1", "via1", "metal2"), directions=("V","H"))
offset=nmos_pin.center()) self.add_via_center(layers=("metal1", "via1", "metal2"),
self.add_contact_center(layers=("metal1", "via1", "metal2"), offset=nmos_pin.center(),
offset=out_offset, directions=("V","H"))
rotate=90) self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_offset)
# PMOS1 to mid-drain to NMOS2 drain # PMOS1 to mid-drain to NMOS2 drain
self.add_path("metal2",[top_pin_offset, mid1_offset, out_offset, mid2_offset, bottom_pin_offset]) self.add_path("metal2",[top_pin_offset, mid1_offset, out_offset, mid2_offset, bottom_pin_offset])

View File

@ -213,11 +213,11 @@ class pnand3(pgate.pgate):
nmos3_pin = self.nmos3_inst.get_pin("D") nmos3_pin = self.nmos3_inst.get_pin("D")
# Go up to metal2 for ease on all output pins # Go up to metal2 for ease on all output pins
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pmos1_pin.center()) offset=pmos1_pin.center())
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pmos3_pin.center()) offset=pmos3_pin.center())
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=nmos3_pin.center()) offset=nmos3_pin.center())
# PMOS3 and NMOS3 are drain aligned # PMOS3 and NMOS3 are drain aligned
@ -227,7 +227,7 @@ class pnand3(pgate.pgate):
self.add_path("metal2",[pmos1_pin.bc(), mid_offset, nmos3_pin.uc()]) self.add_path("metal2",[pmos1_pin.bc(), mid_offset, nmos3_pin.uc()])
# This extends the output to the edge of the cell # This extends the output to the edge of the cell
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=mid_offset) offset=mid_offset)
self.add_layout_pin_rect_center(text="Z", self.add_layout_pin_rect_center(text="Z",
layer="metal1", layer="metal1",

View File

@ -184,11 +184,11 @@ class pnor2(pgate.pgate):
nmos2_pin = self.nmos2_inst.get_pin("D") nmos2_pin = self.nmos2_inst.get_pin("D")
# Go up to metal2 for ease on all output pins # Go up to metal2 for ease on all output pins
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pmos_pin.center()) offset=pmos_pin.center())
m1m2_contact=self.add_contact_center(layers=("metal1", "via1", "metal2"), m1m2_contact=self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=nmos_pin.center(), offset=nmos_pin.center())
rotate=90)
mid1_offset = vector(pmos_pin.center().x,nmos2_pin.center().y) mid1_offset = vector(pmos_pin.center().x,nmos2_pin.center().y)
mid2_offset = vector(pmos_pin.center().x,self.inputA_yoffset) mid2_offset = vector(pmos_pin.center().x,self.inputA_yoffset)
@ -198,9 +198,8 @@ class pnor2(pgate.pgate):
self.add_path("metal2",[pmos_pin.bc(), mid2_offset, mid3_offset]) self.add_path("metal2",[pmos_pin.bc(), mid2_offset, mid3_offset])
self.add_path("metal2",[nmos_pin.rc(), mid1_offset, mid2_offset]) self.add_path("metal2",[nmos_pin.rc(), mid1_offset, mid2_offset])
# This extends the output to the edge of the cell # This extends the output to the edge of the cell
self.add_contact_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=mid3_offset, offset=mid3_offset)
rotate=90)
self.add_layout_pin_rect_center(text="Z", self.add_layout_pin_rect_center(text="Z",
layer="metal1", layer="metal1",
offset=mid3_offset, offset=mid3_offset,

View File

@ -75,7 +75,7 @@ class precharge(pgate.pgate):
self.add_path("metal1", [pmos_pin.uc(), pmos_vdd_pos]) self.add_path("metal1", [pmos_pin.uc(), pmos_vdd_pos])
# Add vdd pin above the transistor # Add vdd pin above the transistor
self.add_power_pin("vdd", pmos_pin.center(), rotate=0) self.add_power_pin("vdd", pmos_pin.center(), vertical=True)
def create_ptx(self): def create_ptx(self):
@ -149,9 +149,9 @@ class precharge(pgate.pgate):
# adds the en contact to connect the gates to the en rail on metal1 # adds the en contact to connect the gates to the en rail on metal1
offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space) offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_via_center(layers=("poly", "contact", "metal1"),
offset=offset, offset=offset)
rotate=90)
# adds the en rail on metal1 # adds the en rail on metal1
self.add_layout_pin_segment_center(text="en_bar", self.add_layout_pin_segment_center(text="en_bar",
@ -168,7 +168,7 @@ class precharge(pgate.pgate):
# adds the contact from active to metal1 # adds the contact from active to metal1
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \ well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
+ vector(0, self.upper_pmos1_inst.uy() + contact.well.height/2 + drc("well_extend_active")) + vector(0, self.upper_pmos1_inst.uy() + contact.well.height/2 + drc("well_extend_active"))
self.add_contact_center(layers=("active", "contact", "metal1"), self.add_via_center(layers=("active", "contact", "metal1"),
offset=well_contact_pos, offset=well_contact_pos,
implant_type="n", implant_type="n",
well_type="n") well_type="n")
@ -225,16 +225,20 @@ class precharge(pgate.pgate):
lower_pin = self.lower_pmos_inst.get_pin("S") lower_pin = self.lower_pmos_inst.get_pin("S")
# BL goes up to M2 at the transistor # BL goes up to M2 at the transistor
self.bl_contact=self.add_contact_center(layers=stack, self.bl_contact=self.add_via_center(layers=stack,
offset=upper_pin.center()) offset=upper_pin.center(),
self.add_contact_center(layers=stack, directions=("V","V"))
offset=lower_pin.center()) self.add_via_center(layers=stack,
offset=lower_pin.center(),
directions=("V","V"))
# BR routes over on M1 first # BR routes over on M1 first
self.add_contact_center(layers=stack, self.add_via_center(layers=stack,
offset = vector(self.br_pin.cx(), upper_pin.cy())) offset = vector(self.br_pin.cx(), upper_pin.cy()),
self.add_contact_center(layers=stack, directions=("V","V"))
offset = vector(self.br_pin.cx(), lower_pin.cy())) self.add_via_center(layers=stack,
offset = vector(self.br_pin.cx(), lower_pin.cy()),
directions=("V","V"))
def connect_pmos_m1(self, pmos_pin, bit_pin): def connect_pmos_m1(self, pmos_pin, bit_pin):
""" """

View File

@ -326,9 +326,10 @@ class ptx(design.design):
[source_positions,drain_positions] = self.get_contact_positions() [source_positions,drain_positions] = self.get_contact_positions()
for pos in source_positions: for pos in source_positions:
contact=self.add_contact_center(layers=("active", "contact", "metal1"), contact=self.add_via_center(layers=("active", "contact", "metal1"),
offset=pos, offset=pos,
size=(1, self.num_contacts), size=(1, self.num_contacts),
directions=("H","V"),
implant_type=self.implant_type, implant_type=self.implant_type,
well_type=self.well_type) well_type=self.well_type)
self.add_layout_pin_rect_center(text="S", self.add_layout_pin_rect_center(text="S",
@ -339,9 +340,10 @@ class ptx(design.design):
for pos in drain_positions: for pos in drain_positions:
contact=self.add_contact_center(layers=("active", "contact", "metal1"), contact=self.add_via_center(layers=("active", "contact", "metal1"),
offset=pos, offset=pos,
size=(1, self.num_contacts), size=(1, self.num_contacts),
directions=("H","V"),
implant_type=self.implant_type, implant_type=self.implant_type,
well_type=self.well_type) well_type=self.well_type)
self.add_layout_pin_rect_center(text="D", self.add_layout_pin_rect_center(text="D",

View File

@ -127,13 +127,18 @@ class single_level_column_mux(design.design):
# Add vias to bl, br_out, nmos_upper/S, nmos_lower/D # Add vias to bl, br_out, nmos_upper/S, nmos_lower/D
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=bl_pin.bc()) offset=bl_pin.bc(),
directions=("V","V"))
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=br_out_pin.uc()) offset=br_out_pin.uc(),
directions=("V","V"))
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=nmos_upper_s_pin.center()) offset=nmos_upper_s_pin.center(),
directions=("V","V"))
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=nmos_lower_d_pin.center()) offset=nmos_lower_d_pin.center(),
directions=("V","V"))
# bl -> nmos_upper/D on metal1 # bl -> nmos_upper/D on metal1
# bl_out -> nmos_upper/S on metal2 # bl_out -> nmos_upper/S on metal2

View File

@ -200,8 +200,7 @@ class sram_1bank(sram_base):
clk_steiner_pos = vector(mid1_pos.x, control_clk_buf_pos.y) clk_steiner_pos = vector(mid1_pos.x, control_clk_buf_pos.y)
self.add_path("metal1", [control_clk_buf_pos, clk_steiner_pos]) self.add_path("metal1", [control_clk_buf_pos, clk_steiner_pos])
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=clk_steiner_pos, offset=clk_steiner_pos)
rotate=90)
# Note, the via to the control logic is taken care of above # Note, the via to the control logic is taken care of above
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos]) self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos])
@ -233,8 +232,7 @@ class sram_1bank(sram_base):
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port)) dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin) self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(), offset=src_pin.rc())
rotate=90)
def route_row_addr_dff(self): def route_row_addr_dff(self):
@ -250,8 +248,7 @@ class sram_1bank(sram_base):
mid_pos = vector(bank_pos.x,flop_pos.y) mid_pos = vector(bank_pos.x,flop_pos.y)
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos]) self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
self.add_via_center(layers=("metal2","via2","metal3"), self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos, offset=flop_pos)
rotate=90)
def route_col_addr_dff(self): def route_col_addr_dff(self):
""" Connect the output of the row flops to the bank pins """ """ Connect the output of the row flops to the bank pins """

View File

@ -469,8 +469,7 @@ class sram_base(design, verilog, lef):
out_pos = dest_pin.center() out_pos = dest_pin.center()
self.add_wire(("metal3","via2","metal2"),[in_pos, vector(out_pos.x,in_pos.y),out_pos]) self.add_wire(("metal3","via2","metal2"),[in_pos, vector(out_pos.x,in_pos.y),out_pos])
self.add_via_center(layers=("metal2","via2","metal3"), self.add_via_center(layers=("metal2","via2","metal3"),
offset=src_pin.rc(), offset=src_pin.rc())
rotate=90)
def connect_rail_from_left_m2m1(self, src_pin, dest_pin): def connect_rail_from_left_m2m1(self, src_pin, dest_pin):

View File

@ -54,12 +54,15 @@ class sram_factory:
self.objects[module_type] = [] self.objects[module_type] = []
# Either retreive a previous object or create a new one # Either retreive a previous object or create a new one
#print("new",kwargs)
for obj in self.objects[module_type]: for obj in self.objects[module_type]:
(obj_kwargs, obj_item) = obj (obj_kwargs, obj_item) = obj
# Must have the same dictionary exactly (conservative) # Must have the same dictionary exactly (conservative)
if obj_kwargs == kwargs: if obj_kwargs == kwargs:
debug.info(3, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs))) #debug.info(0, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs)))
return obj_item return obj_item
#else:
# print("obj",obj_kwargs)
# Use the default name if there are default arguments # Use the default name if there are default arguments
# This is especially for library cells so that the spice and gds files can be found. # This is especially for library cells so that the spice and gds files can be found.
@ -67,7 +70,8 @@ class sram_factory:
# Create a unique name and increment the index # Create a unique name and increment the index
module_name = "{0}_{1}".format(module_name, self.module_indices[module_type]) module_name = "{0}_{1}".format(module_name, self.module_indices[module_type])
self.module_indices[module_type] += 1 self.module_indices[module_type] += 1
#debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
#debug.info(0, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
obj = mod(name=module_name,**kwargs) obj = mod(name=module_name,**kwargs)
self.objects[module_type].append((kwargs,obj)) self.objects[module_type].append((kwargs,obj))
return obj return obj

View File

@ -7,36 +7,50 @@ import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
from sram_factory import factory
import debug import debug
class contact_test(openram_test): class contact_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
import contact
for layer_stack in [("metal1", "via1", "metal2"), ("poly", "contact", "metal1")]:
for layer_stack in [("poly", "contact", "metal1"), ("metal1", "via1", "metal2")]:
stack_name = ":".join(map(str, layer_stack)) stack_name = ":".join(map(str, layer_stack))
# Check single 1 x 1 contact" # Check single 1 x 1 contact"
debug.info(2, "1 x 1 {} test".format(stack_name)) debug.info(2, "1 x 1 {} test".format(stack_name))
c = contact.contact(layer_stack, (1, 1)) c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1))
self.local_drc_check(c)
# Check single 1 x 1 contact"
debug.info(2, "1 x 1 {} test".format(stack_name))
c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1), directions=("H","V"))
self.local_drc_check(c)
# Check single x 1 contact"
debug.info(2, "1 x 1 {} test".format(stack_name))
c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1), directions=("H","H"))
self.local_drc_check(c)
# Check single 1 x 1 contact"
debug.info(2, "1 x 1 {} test".format(stack_name))
c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1), directions=("V","V"))
self.local_drc_check(c) self.local_drc_check(c)
# check vertical array with one in the middle and two ends # check vertical array with one in the middle and two ends
debug.info(2, "1 x 3 {} test".format(stack_name)) debug.info(2, "1 x 3 {} test".format(stack_name))
c = contact.contact(layer_stack, (1, 3)) c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 3))
self.local_drc_check(c) self.local_drc_check(c)
# check horizontal array with one in the middle and two ends # check horizontal array with one in the middle and two ends
debug.info(2, "3 x 1 {} test".format(stack_name)) debug.info(2, "3 x 1 {} test".format(stack_name))
c = contact.contact(layer_stack, (3, 1)) c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(3, 1))
self.local_drc_check(c) self.local_drc_check(c)
# check 3x3 array for all possible neighbors # check 3x3 array for all possible neighbors
debug.info(2, "3 x 3 {} test".format(stack_name)) debug.info(2, "3 x 3 {} test".format(stack_name))
c = contact.contact(layer_stack, (3, 3)) c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(3, 3))
self.local_drc_check(c) self.local_drc_check(c)
globals.end_openram() globals.end_openram()