mirror of https://github.com/VLSIDA/OpenRAM.git
Rewrite add_contact to use layer directions.
This commit is contained in:
parent
c1411f4227
commit
be20408fb2
|
|
@ -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"))
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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 """
|
||||
|
|
|
|||
|
|
@ -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"""
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"""
|
||||
|
|
|
|||
|
|
@ -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"):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 """
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue