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.
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
have extension on two or four sides.
This class has enclosure on two or four sides of the contact.
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
necessary to import layouts into Magic which requires the select to be in the same GDS
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
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)
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.dimensions = dimensions
self.directions = directions
self.offset = vector(0,0)
self.implant_type = implant_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()
def create_layout(self):
self.setup_layers()
self.setup_layout_constants()
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.")
def setup_layers(self):
""" Locally assign the layer names. """
(first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer
self.via_layer_name = via_layer
@ -75,37 +69,58 @@ class contact(hierarchy_design.hierarchy_design):
self.second_layer_name = second_layer
def setup_layout_constants(self):
""" Determine the design rules for the enclosure layers """
self.contact_width = drc("minwidth_{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_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
# 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_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_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_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_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,
second_layer_enclosure)
self.second_layer_vertical_enclosure = max(utils.ceil((second_layer_minarea
/ (self.contact_array_width + 2*self.second_layer_horizontal_enclosure)
- self.contact_array_height)/2),
(second_layer_minwidth - self.contact_array_height)/2,
second_layer_extend)
# 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[0] == "V":
self.first_layer_horizontal_enclosure = max(first_layer_enclosure,
(first_layer_minwidth - self.contact_array_width)/2)
self.first_layer_vertical_enclosure = max(first_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):
""" Create the contact array at the origin"""
@ -169,10 +184,10 @@ class contact(hierarchy_design.hierarchy_design):
from sram_factory import factory
# This is not instantiated and used for calculations only.
# These are static 1x1 contacts to reuse in all the design modules.
well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"))
active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly"))
poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"))
m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"))
m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"))
m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"))
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"), directions=("H","V"))
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"), directions=("H","V"))
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"), directions=("H","V"))

View File

@ -355,75 +355,59 @@ class layout():
layer_stack=layers,
position_list=coordinates)
def add_contact(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(layers=layers,
offset=offset,
size=size,
mirror=mirror,
rotate=rotate,
implant_type=implant_type,
well_type=well_type)
def get_preferred_direction(self, layer):
""" Return the preferred routing directions """
if layer in ["metal1", "metal3", "metal5"]:
return "H"
elif layer in ["active", "poly", "metal2", "metal4"]:
return "V"
else:
return "N"
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. """
if directions==None:
directions = (self.get_preferred_direction(layers[0]), self.get_preferred_direction(layers[2]))
from sram_factory import factory
via = factory.create(module_type="contact",
layer_stack=layers,
dimensions=size,
directions=directions,
implant_type=implant_type,
well_type=well_type)
self.add_mod(via)
inst=self.add_inst(name=via.name,
mod=via,
offset=offset,
mirror=mirror,
rotate=rotate)
offset=offset)
# We don't model the logical connectivity of wires/paths
self.connect_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. """
if directions==None:
directions = (self.get_preferred_direction(layers[0]), self.get_preferred_direction(layers[2]))
from sram_factory import factory
via = factory.create(module_type="contact",
layer_stack=layers,
dimensions=size,
directions=directions,
implant_type=implant_type,
well_type=well_type)
height = via.height
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)
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)
corrected_offset = offset + vector(-0.5*width,-0.5*height)
#print(rotate,offset,"->",corrected_offset)
self.add_mod(via)
inst=self.add_inst(name=via.name,
mod=via,
offset=corrected_offset,
mirror=mirror,
rotate=rotate)
offset=corrected_offset)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return inst
@ -748,8 +732,7 @@ class layout():
mid = vector(trunk_offset.x, pin.center().y)
self.add_path(layer_stack[0], [pin.center(), mid])
self.add_via_center(layers=layer_stack,
offset=mid,
rotate=90)
offset=mid)
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.
The starting layer is specified to determine which vias are needed.
"""
if vertical:
direction=("V","V")
else:
direction=("H","H")
if start_layer=="metal1":
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=loc,
rotate=float(rotate))
directions=direction)
if start_layer=="metal1" or start_layer=="metal2":
via=self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=loc,
rotate=float(rotate))
directions=direction)
if start_layer=="metal3":
self.add_layout_pin_rect_center(text=name,
layer="metal3",

View File

@ -65,7 +65,7 @@ class route(design):
for p0,p1 in plist:
if p0.z != p1.z: # via
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!
debug.error("Diagonal route! {}".format(self.path),-3)
else:

View File

@ -62,18 +62,15 @@ class wire(wire_path):
continue
if a[1] == c[1]:
continue
via_offset = [offset[0] + 0.5*c_height,
offset[1] - 0.5*c_width]
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)]
self.obj.add_via_center(layers=self.layer_stack,
offset=offset)
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
for index in range(len(pl) - 1):
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
# 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
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()])
# 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_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_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()])
# 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)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=contact_offset_left,
rotate=90)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset_left,
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)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=contact_offset_right,
rotate=90)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset_right,
directions=("H","H"))
# 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)
@ -395,7 +396,6 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.rw_bl_names[k],
layer="metal2",
offset=self.rwbl_positions[k],
width=drc["minwidth_metal2"],
height=self.height)
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],
layer="metal2",
offset=self.rwbr_positions[k],
width=drc["minwidth_metal2"],
height=self.height)
# 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],
layer="metal2",
offset=self.wbl_positions[k],
width=drc["minwidth_metal2"],
height=self.height)
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],
layer="metal2",
offset=self.wbr_positions[k],
width=drc["minwidth_metal2"],
height=self.height)
# 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],
layer="metal2",
offset=self.rbl_positions[k],
width=drc["minwidth_metal2"],
height=self.height)
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],
layer="metal2",
offset=self.rbr_positions[k],
width=drc["minwidth_metal2"],
height=self.height)
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
if (k == 0) or (k == 1):
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset)
self.add_path("poly", [gate_offset, port_contact_offset])
self.add_path("metal1", [port_contact_offset, wl_contact_offset])
else:
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offset)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offset)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=wl_contact_offset,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=wl_contact_offset,
directions=("H","H"))
self.add_path("poly", [gate_offset, port_contact_offset])
self.add_path("metal2", [port_contact_offset, wl_contact_offset])
@ -662,8 +657,8 @@ class pbitcell(design.design):
port_contact_offest = left_port_transistors[k].get_pin("S").center()
bl_offset = vector(bl_positions[k].x, port_contact_offest.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, bl_offset], width=contact.m1m2.height)
@ -671,8 +666,8 @@ class pbitcell(design.design):
port_contact_offest = right_port_transistors[k].get_pin("D").center()
br_offset = vector(br_positions[k].x, port_contact_offest.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, br_offset], width=contact.m1m2.height)
@ -687,17 +682,17 @@ class pbitcell(design.design):
nmos_contact_positions.append(self.read_access_nmos_right[k].get_pin("S").center())
for position in nmos_contact_positions:
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=position)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=position)
if position.x > 0:
contact_correct = 0.5*contact.m1m2.height
else:
contact_correct = -0.5*contact.m1m2.height
supply_offset = vector(position.x + contact_correct, self.gnd_position.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=supply_offset,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=supply_offset,
directions=("H","H"))
self.add_path("metal2", [position, supply_offset])
@ -713,39 +708,35 @@ class pbitcell(design.design):
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)
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", [mid, Q_pos])
self.add_path("metal1", [self.readwrite_nmos_left[k].get_pin("D").uc(), mid, Q_pos])
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)
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", [mid, Q_bar_pos])
self.add_path("metal1", [self.readwrite_nmos_right[k].get_pin("S").uc(), mid, Q_bar_pos])
def route_write_access(self):
""" Routes read/write transistors to the storage component of the bitcell """
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)
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", [mid, Q_pos])
self.add_path("metal1", [self.write_nmos_left[k].get_pin("D").uc(), mid, Q_pos])
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)
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", [mid, Q_bar_pos])
self.add_path("metal1", [self.write_nmos_right[k].get_pin("S").uc(), mid, Q_bar_pos])
def route_read_access(self):
""" Routes read access transistors to the storage component of the bitcell """
# 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)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=left_storage_contact,
rotate=90)
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_via_center(layers=("poly", "contact", "metal1"),
offset=left_storage_contact,
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)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=right_storage_contact,
rotate=90)
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_via_center(layers=("poly", "contact", "metal1"),
offset=right_storage_contact,
directions=("H","H"))
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])
@ -758,25 +749,23 @@ class pbitcell(design.design):
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)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=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)
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", [mid, left_storage_contact])
self.add_path("metal1", [port_contact_offset, 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)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=port_contact_offset)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=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)
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", [mid, right_storage_contact])
self.add_path("metal1", [port_contact_offset, mid, right_storage_contact])
def extend_well(self):
"""
@ -795,13 +784,13 @@ class pbitcell(design.design):
# extend nwell to encompass inverter_pmos
# 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_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap - 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 - self.well_enclose_active
# calculate width of the two combined nwells
# 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_height = self.vdd_position.y - inverter_well_ypos + drc["well_enclosure_active"] + drc["minwidth_tx"]
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 + self.well_enclose_active + drc["minwidth_tx"]
offset = [inverter_well_xpos,inverter_well_ypos]
self.add_rect(layer="nwell",
@ -812,19 +801,19 @@ class pbitcell(design.design):
# add well contacts
# connect pimplants to gnd
offset = vector(0, self.gnd_position.y)
self.add_contact_center(layers=("active", "contact", "metal1"),
offset=offset,
rotate=90,
implant_type="p",
well_type="p")
self.add_via_center(layers=("active", "contact", "metal1"),
offset=offset,
directions=("H","H"),
implant_type="p",
well_type="p")
# connect nimplants to vdd
offset = vector(0, self.vdd_position.y)
self.add_contact_center(layers=("active", "contact", "metal1"),
offset=offset,
rotate=90,
implant_type="n",
well_type="n")
self.add_via_center(layers=("active", "contact", "metal1"),
offset=offset,
directions=("H","H"),
implant_type="n",
well_type="n")
def list_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """

View File

@ -800,14 +800,11 @@ class bank(design.design):
bus_pos = vector(self.bus_xoffset[port][name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos,
rotate=90)
offset=bus_pos)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_pos,
rotate=90)
offset=out_pos)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=out_pos,
rotate=90)
offset=out_pos)
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)
self.add_path("metal1", [control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos,
rotate=90)
offset=control_pos)
# clk to wordline_driver
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)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos,
rotate=90)
offset=control_pos)
def analytical_delay(self, corner, slew, load, port):
""" 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)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=bank_sel_pin_end,
rotate=90)
directions=("H","H"))
# bank_sel_bar is vertical wire
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_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
rotate=90)
directions=("H","H"))
# 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)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
rotate=90)
directions=("H","H"))
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=logic_pos,
rotate=90)
directions=("H","H"))
self.add_layout_pin_segment_center(text=input_name,
layer="metal3",
start=input_pos,
@ -295,10 +295,10 @@ class bank_select(design.design):
pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos,
rotate=90)
directions=("H","H"))
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
rotate=90)
directions=("H","H"))
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)

View File

@ -128,7 +128,7 @@ class bitcell_array(design.design):
inst = self.cell_inst[row,col]
for pin_name in ["vdd", "gnd"]:
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):
"""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)
self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, in_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=out_pos,
rotate=90)
offset=out_pos)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=out_pos,
rotate=90)
offset=out_pos)
def create_pen_row(self):
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)
self.add_wire(("metal1","via1","metal2"),[in_pos, mid_pos, rail_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail_pos,
rotate=90)
offset=rail_pos)
self.copy_layout_pin(self.ctrl_dff_inst, "din_0", "csb")
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 """
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=input_offset,
rotate=90)
offset=input_offset)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=output_offset,
rotate=90)
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)
self.add_path("metal1", [rail_pos, pin.lc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_pos,
rotate=90)
offset=rail_pos)
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)
rail_pos = vector(self.predecode_rails[rail_name].x,mid_point.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin.center(),
rotate=90)
offset=pin.center())
self.add_wire(("metal3","via2","metal2"), [rail_pos, mid_point, pin.uc()])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=rail_pos,
rotate=90)
offset=rail_pos)
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)
self.add_path("metal1",[in_pos, a_pos])
self.add_via_center(layers = ("metal1", "via1", "metal2"),
offset=[self.input_rails[in_pin].x, y_offset],
rotate=90)
offset=[self.input_rails[in_pin].x, y_offset])
self.add_via_center(layers = ("metal1", "via1", "metal2"),
offset=[self.decode_rails[a_pin].x, y_offset],
rotate=90)
offset=[self.decode_rails[a_pin].x, y_offset])
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)
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"),
offset=rail_pos,
rotate=90)
offset=rail_pos)
#route input
@ -232,8 +229,7 @@ class hierarchical_predecode(design.design):
in_pos = vector(self.input_rails[in_pin].x,inv_in_pos.y)
self.add_path("metal1", [in_pos, inv_in_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=in_pos,
rotate=90)
offset=in_pos)
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)
self.add_path("metal1", [rail_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_pos,
rotate=90)
offset=rail_pos)

View File

@ -39,8 +39,8 @@ class replica_bitline(design.design):
#self.add_lvs_correspondence_points()
# Extra pitch on top and right
self.width = self.rbl_inst.rx() - self.dc_inst.lx() + self.m2_pitch
self.height = max(self.rbl_inst.uy(), self.dc_inst.uy()) + self.m3_pitch
self.width = self.replica_column_inst.rx() - self.delay_chain_inst.lx() + self.m2_pitch
self.height = max(self.replica_column_inst.uy(), self.delay_chain_inst.uy()) + self.m3_pitch
self.DRC_LVS()
@ -111,12 +111,12 @@ class replica_bitline(design.design):
self.connect_inst(["vdd", "delayed_en", "bl0_0", "vdd"])
# add the well and poly contact
self.dc_inst=self.add_inst(name="delay_chain",
mod=self.delay_chain)
self.delay_chain_inst=self.add_inst(name="delay_chain",
mod=self.delay_chain)
self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
self.rbc_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell)
self.replica_cell_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell)
temp = []
for port in self.all_ports:
temp.append("bl{}_0".format(port))
@ -127,8 +127,8 @@ class replica_bitline(design.design):
temp.append("gnd")
self.connect_inst(temp)
self.rbl_inst=self.add_inst(name="load",
mod=self.rbl)
self.replica_column_inst=self.add_inst(name="load",
mod=self.rbl)
temp = []
for port in self.all_ports:
@ -153,12 +153,12 @@ class replica_bitline(design.design):
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")
self.rbl_inst.place(self.rbl_offset)
self.replica_column_inst.place(self.rbl_offset)
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
for row in range(self.bitcell_loads):
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
# 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.
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))
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:
if is_replica_cell:
wl = self.wl_list[port]
pin = self.rbc_inst.get_pin(wl)
pin = self.replica_cell_inst.get_pin(wl)
else:
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":
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 """
# These are the instances that every bank has
top_instances = [self.rbl_inst,
self.dc_inst]
top_instances = [self.replica_column_inst,
self.delay_chain_inst]
for inst in top_instances:
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
@ -257,11 +257,11 @@ class replica_bitline(design.design):
pin = self.rbl_inv_inst.get_pin("vdd")
self.add_power_pin("vdd", pin.lc())
pin=self.rbc_inst.get_pin("vdd")
self.add_power_pin("vdd", pin.center(), 0, pin.layer)
for pin in self.replica_cell_inst.get_pins("vdd"):
self.add_power_pin(name="vdd", loc=pin.center(), vertical=True, start_layer=pin.layer)
for pin in self.rbc_inst.get_pins("gnd"):
self.add_power_pin("gnd", pin.center())
for pin in self.replica_cell_inst.get_pins("gnd"):
self.add_power_pin("gnd", pin.center(), vertical=True, start_layer=pin.layer)
@ -275,10 +275,10 @@ class replica_bitline(design.design):
poly_offset = poly_pin.uc()
# This centers the contact above the poly by one pitch
contact_offset = poly_offset + vector(0,self.m2_pitch)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=contact_offset)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=contact_offset)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=contact_offset)
self.add_segment_center(layer="poly",
start=poly_offset,
end=contact_offset)
@ -289,12 +289,12 @@ class replica_bitline(design.design):
# height=self.delay_chain_offset.y-nwell_offset.y)
# 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])
# 3. Route the contact of previous route to the 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_mid2 = vector(wl_mid1.x, contact_offset.y)
#xmid_point= 0.5*(wl_offset.x+contact_offset.x)
@ -305,8 +305,8 @@ class replica_bitline(design.design):
# 4. Short wodlines if multiport
wl = self.wl_list[0]
wl_last = self.wl_list[-1]
pin = self.rbc_inst.get_pin(wl)
pin_last = self.rbc_inst.get_pin(wl_last)
pin = self.replica_cell_inst.get_pin(wl)
pin_last = self.replica_cell_inst.get_pin(wl_last)
x_offset = self.short_wordlines(pin, pin_last, "left", True)
#correct = vector(0.5*drc("minwidth_metal1"), 0)
@ -315,7 +315,7 @@ class replica_bitline(design.design):
# DRAIN ROUTE
# Route the drain to the vdd rail
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
# 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)
# 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
bl_down_offset = bl_offset - vector(0, self.m2_pitch)
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
@ -344,12 +344,12 @@ class replica_bitline(design.design):
def route_vdd(self):
""" Route all signals connected to vdd """
self.copy_layout_pin(self.dc_inst,"vdd")
self.copy_layout_pin(self.rbc_inst,"vdd")
self.copy_layout_pin(self.delay_chain_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 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:
if pin.layer != "metal1":
continue
@ -360,11 +360,9 @@ class replica_bitline(design.design):
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start,
rotate=90)
offset=start)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
offset=end)
# Add via for the inverter
pin = self.rbl_inv_inst.get_pin("vdd")
@ -374,38 +372,34 @@ class replica_bitline(design.design):
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start,
rotate=90)
offset=start)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
offset=end)
# Add via for the RBC
pin = self.rbc_inst.get_pin("vdd")
pin = self.replica_cell_inst.get_pin("vdd")
start = pin.lc()
end = vector(self.right_vdd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
offset=end)
# 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:
if pin.layer != "metal1":
continue
# If above the delay line, route the full width
left = vector(self.left_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
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left,
rotate=90)
offset=left)
else:
start = center
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
# Add via for the delay chain
left_gnd_start = self.dc_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_start = self.delay_chain_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
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",
start=left_gnd_start,
end=left_gnd_end)
# 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_end = vector(center_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
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.replica_column_inst.uy()+self.m2_pitch)
self.center_gnd_pin=self.add_segment_center(layer="metal2",
start=center_gnd_start,
end=center_gnd_end)
# 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_end = vector(right_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
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.replica_column_inst.uy()+self.m2_pitch)
self.right_gnd_pin=self.add_segment_center(layer="metal2",
start=right_gnd_start,
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
for row in range(self.bitcell_loads):
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":
continue
# If above the delay line, route the full width
left = vector(self.left_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
else:
start = center
@ -467,47 +461,41 @@ class replica_bitline(design.design):
end=end)
if start == left:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left,
rotate=90)
offset=left)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=center,
rotate=90)
offset=center)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
offset=end)
rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
# Add L shapes to each vertical gnd rail
for pin in rbl_gnd_pins:
if pin.layer != "metal1":
continue
# If above the delay line, route the full width
left = vector(self.left_gnd_pin.cx(),pin.cy())
center = vector(self.center_gnd_pin.cx(),pin.cy())
if pin.cy() > self.dc_inst.uy() + self.m1_pitch:
start = left
else:
start = center
end = vector(self.right_gnd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=end)
if start == left:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=center,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end,
rotate=90)
# rbl_gnd_pins = self.replica_column_inst.get_pins("gnd")
# # Add L shapes to each vertical gnd rail
# for pin in rbl_gnd_pins:
# if pin.layer != "metal1":
# continue
# # If above the delay line, route the full width
# left = vector(self.left_gnd_pin.cx(),pin.cy())
# center = vector(self.center_gnd_pin.cx(),pin.cy())
# if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
# start = left
# else:
# start = center
# end = vector(self.right_gnd_pin.cx(),pin.cy())
# self.add_segment_center(layer="metal1",
# start=start,
# end=end)
# if start == left:
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=left)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=center)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end)
# 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:
if pin.layer != "metal1":
continue
@ -520,12 +508,10 @@ class replica_bitline(design.design):
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start,
rotate=90)
offset=start)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end,
#rotate=90)
# offset=end)
# Add via for the inverter
@ -536,16 +522,14 @@ class replica_bitline(design.design):
# start=start,
# end=end)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=start,
#rotate=90)
# offset=start)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end,
#rotate=90)
# offset=end)
# 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:
if pin.layer != "metal2":
continue
@ -560,7 +544,7 @@ class replica_bitline(design.design):
def add_layout_pins(self):
""" 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",
layer="metal2",
start=en_offset,
@ -587,7 +571,7 @@ class replica_bitline(design.design):
height=pin.height(),
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",
layer=pin.layer,
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),
layer="metal1",
offset=offset,
width=self.mux.width * self.columns,
height=contact.m1m2.width)
width=self.mux.width * self.columns)
def add_vertical_poly_rail(self):
""" 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())
# Add the poly contact with a shift to account for the rotation
self.add_via_center(layers=("metal1", "contact", "poly"),
offset=offset,
rotate=90)
offset=offset)
self.add_path("poly", [offset, gate_offset])
def route_bitlines(self):
""" Connect the output bit-lines to form the appropriate width mux """
for j in range(self.columns):
bl_offset = self.mux_inst[j].get_pin("bl_out").ll()
br_offset = self.mux_inst[j].get_pin("br_out").ll()
bl_offset = self.mux_inst[j].get_pin("bl_out").bc()
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)
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:
# 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
# to ensure vias are enclosed and M1 min width rules.
width = contact.m1m2.width + self.mux.width * (self.words_per_row - 1)
self.add_rect(layer="metal1",
offset=bl_out_offset,
width=width,
height=drc("minwidth_metal2"))
self.add_rect(layer="metal1",
offset=br_out_offset,
width=width,
height=drc("minwidth_metal2"))
width = self.m2_width + self.mux.width * (self.words_per_row - 1)
self.add_path("metal1", [bl_out_offset, bl_out_offset+vector(width,0)])
self.add_path("metal1", [br_out_offset, br_out_offset+vector(width,0)])
# 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)),
layer="metal2",
offset=bl_out_offset.scale(1,0),
width=drc('minwidth_metal2'),
height=self.route_height)
self.add_layout_pin(text="br_out_{}".format(int(j/self.words_per_row)),
layer="metal2",
offset=br_out_offset.scale(1,0),
width=drc('minwidth_metal2'),
height=self.route_height)
self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j/self.words_per_row)),
layer="metal2",
start=bl_out_offset,
end=bl_out_offset_end)
self.add_layout_pin_segment_center(text="br_out_{}".format(int(j/self.words_per_row)),
layer="metal2",
start=br_out_offset,
end=br_out_offset_end)
# This via is on the right of the wire
self.add_via(layers=("metal1", "via1", "metal2"),
offset=bl_out_offset + vector(contact.m1m2.height,0),
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=bl_out_offset)
# This via is on the left of the wire
self.add_via(layers=("metal1", "via1", "metal2"),
offset= br_out_offset,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=br_out_offset)
else:
self.add_rect(layer="metal2",
offset=bl_out_offset,
width=drc('minwidth_metal2'),
height=self.route_height-bl_out_offset.y)
self.add_path("metal2", [ bl_out_offset, bl_out_offset_end])
self.add_path("metal2", [ br_out_offset, br_out_offset_end])
# This via is on the right of the wire
self.add_via(layers=("metal1", "via1", "metal2"),
offset=bl_out_offset + vector(contact.m1m2.height,0),
rotate=90)
self.add_rect(layer="metal2",
offset=br_out_offset,
width=drc('minwidth_metal2'),
height=self.route_height-br_out_offset.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=bl_out_offset)
# This via is on the left of the wire
self.add_via(layers=("metal1", "via1", "metal2"),
offset= br_out_offset,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=br_out_offset)
def analytical_delay(self, corner, slew, load):
from tech import parameter
@ -230,4 +216,4 @@ class single_level_column_mux_array(design.design):
from tech import parameter
#Bitcell drain load being used to estimate mux NMOS drain load
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
return drain_load
return drain_load

View File

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

View File

@ -42,7 +42,7 @@ class pgate(design.design):
height=height,
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.
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)
# Center is completely symmetric.
if rotate==90:
if rotate:
contact_width = contact.poly.height
contact_m1_width = contact.poly.second_layer_height
contact_m1_height = contact.poly.second_layer_width
directions = ("H","V")
else:
contact_width = contact.poly.width
contact_m1_width = contact.poly.second_layer_width
contact_m1_height = contact.poly.second_layer_height
directions = ("V","H")
if position=="center":
contact_offset = left_gate_offset + vector(0.5*self.poly_width, 0)
@ -79,9 +81,12 @@ class pgate(design.design):
else:
debug.error("Invalid contact placement option.", -1)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=contact_offset,
rotate=rotate)
# Non-preferred direction via
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset,
directions=directions)
# self.add_layout_pin_segment_center(text=name,
# layer="metal1",
# start=left_gate_offset.scale(0,1),
@ -145,10 +150,11 @@ class pgate(design.design):
# Offset by half a contact in x and y
contact_offset += vector(0.5*pmos.active_contact.first_layer_width,
0.5*pmos.active_contact.first_layer_height)
self.nwell_contact=self.add_contact_center(layers=layer_stack,
offset=contact_offset,
implant_type="n",
well_type="n")
self.nwell_contact=self.add_via_center(layers=layer_stack,
offset=contact_offset,
directions=("H","V"),
implant_type="n",
well_type="n")
self.add_rect_center(layer="metal1",
offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
width=self.nwell_contact.mod.second_layer_width,
@ -191,10 +197,11 @@ class pgate(design.design):
# Offset by half a contact
contact_offset += vector(0.5*nmos.active_contact.first_layer_width,
0.5*nmos.active_contact.first_layer_height)
self.pwell_contact=self.add_contact_center(layers=layer_stack,
offset=contact_offset,
implant_type="p",
well_type="p")
self.pwell_contact=self.add_via_center(layers=layer_stack,
offset=contact_offset,
directions=("H","V"),
implant_type="p",
well_type="p")
self.add_rect_center(layer="metal1",
offset=contact_offset.scale(1,0.5),
width=self.pwell_contact.mod.second_layer_width,

View File

@ -58,7 +58,7 @@ class pinv(pgate.pgate):
self.add_well_contacts()
self.extend_wells(self.well_pos)
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()
def add_pins(self):
@ -222,8 +222,8 @@ class pinv(pgate.pgate):
pmos_drain_pin = self.pmos_inst.get_pin("D")
# 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)
pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.bc().y)
nmos_drain_pos = nmos_drain_pin.lr()
pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.uc().y)
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
# 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)
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=pmos_pin.center())
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=nmos_pin.center())
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=out_offset,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pmos_pin.center(),
directions=("V","H"))
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=nmos_pin.center(),
directions=("V","H"))
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_offset)
# PMOS1 to mid-drain to NMOS2 drain
self.add_path("metal2",[top_pin_offset, mid1_offset, out_offset, mid2_offset, bottom_pin_offset])

View File

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

View File

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

View File

@ -75,7 +75,7 @@ class precharge(pgate.pgate):
self.add_path("metal1", [pmos_pin.uc(), pmos_vdd_pos])
# 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):
@ -149,9 +149,9 @@ class precharge(pgate.pgate):
# 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)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=offset,
rotate=90)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=offset)
# adds the en rail on metal1
self.add_layout_pin_segment_center(text="en_bar",
@ -168,10 +168,10 @@ class precharge(pgate.pgate):
# adds the contact from active to metal1
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"))
self.add_contact_center(layers=("active", "contact", "metal1"),
offset=well_contact_pos,
implant_type="n",
well_type="n")
self.add_via_center(layers=("active", "contact", "metal1"),
offset=well_contact_pos,
implant_type="n",
well_type="n")
# leave an extra pitch for the height
self.height = well_contact_pos.y + contact.well.height + self.m1_pitch
@ -225,16 +225,20 @@ class precharge(pgate.pgate):
lower_pin = self.lower_pmos_inst.get_pin("S")
# BL goes up to M2 at the transistor
self.bl_contact=self.add_contact_center(layers=stack,
offset=upper_pin.center())
self.add_contact_center(layers=stack,
offset=lower_pin.center())
self.bl_contact=self.add_via_center(layers=stack,
offset=upper_pin.center(),
directions=("V","V"))
self.add_via_center(layers=stack,
offset=lower_pin.center(),
directions=("V","V"))
# BR routes over on M1 first
self.add_contact_center(layers=stack,
offset = vector(self.br_pin.cx(), upper_pin.cy()))
self.add_contact_center(layers=stack,
offset = vector(self.br_pin.cx(), lower_pin.cy()))
self.add_via_center(layers=stack,
offset = vector(self.br_pin.cx(), upper_pin.cy()),
directions=("V","V"))
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):
"""

View File

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

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
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"),
offset=br_out_pin.uc())
offset=br_out_pin.uc(),
directions=("V","V"))
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"),
offset=nmos_lower_d_pin.center())
offset=nmos_lower_d_pin.center(),
directions=("V","V"))
# bl -> nmos_upper/D on metal1
# 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)
self.add_path("metal1", [control_clk_buf_pos, clk_steiner_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=clk_steiner_pos,
rotate=90)
offset=clk_steiner_pos)
# 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])
@ -233,8 +232,7 @@ class sram_1bank(sram_base):
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(),
rotate=90)
offset=src_pin.rc())
def route_row_addr_dff(self):
@ -250,8 +248,7 @@ class sram_1bank(sram_base):
mid_pos = vector(bank_pos.x,flop_pos.y)
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos,
rotate=90)
offset=flop_pos)
def route_col_addr_dff(self):
""" 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()
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"),
offset=src_pin.rc(),
rotate=90)
offset=src_pin.rc())
def connect_rail_from_left_m2m1(self, src_pin, dest_pin):

View File

@ -54,12 +54,15 @@ class sram_factory:
self.objects[module_type] = []
# Either retreive a previous object or create a new one
#print("new",kwargs)
for obj in self.objects[module_type]:
(obj_kwargs, obj_item) = obj
# Must have the same dictionary exactly (conservative)
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
#else:
# print("obj",obj_kwargs)
# 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.
@ -67,7 +70,8 @@ class sram_factory:
# Create a unique name and increment the index
module_name = "{0}_{1}".format(module_name, self.module_indices[module_type])
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)
self.objects[module_type].append((kwargs,obj))
return obj

View File

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