mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-03 08:27:11 +02:00
Clean up and generalize layer rules.
Convert metalN to mN. Generalize helper constants in modules for space, width, enclose, etc. Use layer stacks whever possible. Try to remove drc() calls in liu of helper constants.
This commit is contained in:
@@ -104,11 +104,11 @@ class contact(hierarchy_design.hierarchy_design):
|
||||
# The enclosure rule applies to symmetric enclosure component.
|
||||
|
||||
first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name))
|
||||
first_layer_enclosure = drc("{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name))
|
||||
first_layer_enclosure = drc("{0}_enclose_{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_enclosure = drc("{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name))
|
||||
second_layer_enclosure = drc("{0}_enclose_{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))
|
||||
|
||||
# In some technologies, the minimum width may be larger
|
||||
@@ -204,16 +204,16 @@ class contact(hierarchy_design.hierarchy_design):
|
||||
height=self.second_layer_height)
|
||||
|
||||
def create_implant_well_enclosures(self):
|
||||
implant_position = self.first_layer_position - [drc("implant_enclosure_active")] * 2
|
||||
implant_width = self.first_layer_width + 2 * drc("implant_enclosure_active")
|
||||
implant_height = self.first_layer_height + 2 * drc("implant_enclosure_active")
|
||||
implant_position = self.first_layer_position - [drc("implant_enclose_active")] * 2
|
||||
implant_width = self.first_layer_width + 2 * drc("implant_enclose_active")
|
||||
implant_height = self.first_layer_height + 2 * drc("implant_enclose_active")
|
||||
self.add_rect(layer="{}implant".format(self.implant_type),
|
||||
offset=implant_position,
|
||||
width=implant_width,
|
||||
height=implant_height)
|
||||
well_position = self.first_layer_position - [drc("well_enclosure_active")] * 2
|
||||
well_width = self.first_layer_width + 2 * drc("well_enclosure_active")
|
||||
well_height = self.first_layer_height + 2 * drc("well_enclosure_active")
|
||||
well_position = self.first_layer_position - [drc("well_enclose_active")] * 2
|
||||
well_width = self.first_layer_width + 2 * drc("well_enclose_active")
|
||||
well_height = self.first_layer_height + 2 * drc("well_enclose_active")
|
||||
self.add_rect(layer="{}well".format(self.well_type),
|
||||
offset=well_position,
|
||||
width=well_width,
|
||||
@@ -250,7 +250,7 @@ m1m2 = factory.create(module_type="contact",
|
||||
m2m3 = factory.create(module_type="contact",
|
||||
layer_stack=m2_stack,
|
||||
directions=("V", "H"))
|
||||
if "metal4" in layer.keys():
|
||||
if "m4" in layer.keys():
|
||||
m3m4 = factory.create(module_type="contact",
|
||||
layer_stack=m3_stack,
|
||||
directions=("H", "V"))
|
||||
|
||||
+57
-31
@@ -8,7 +8,7 @@
|
||||
from hierarchy_design import hierarchy_design
|
||||
import contact
|
||||
from globals import OPTS
|
||||
|
||||
import re
|
||||
|
||||
class design(hierarchy_design):
|
||||
"""
|
||||
@@ -32,7 +32,7 @@ class design(hierarchy_design):
|
||||
|
||||
self.m1_pitch = max(contact.m1m2.width, contact.m1m2.height) + max(self.m1_space, self.m2_space)
|
||||
self.m2_pitch = max(contact.m2m3.width, contact.m2m3.height) + max(self.m2_space, self.m3_space)
|
||||
if "metal4" in tech.layer:
|
||||
if "m4" in tech.layer:
|
||||
self.m3_pitch = max(contact.m3m4.width, contact.m3m4.height) + max(self.m3_space, self.m4_space)
|
||||
else:
|
||||
self.m3_pitch = self.m2_pitch
|
||||
@@ -46,36 +46,62 @@ class design(hierarchy_design):
|
||||
def setup_drc_constants(self):
|
||||
""" These are some DRC constants used in many places in the compiler."""
|
||||
from tech import drc, layer
|
||||
self.well_width = drc("minwidth_well")
|
||||
self.poly_width = drc("minwidth_poly")
|
||||
self.poly_space = drc("poly_to_poly")
|
||||
self.m1_width = drc("minwidth_metal1")
|
||||
self.m1_space = drc("metal1_to_metal1")
|
||||
self.m2_width = drc("minwidth_metal2")
|
||||
self.m2_space = drc("metal2_to_metal2")
|
||||
self.m3_width = drc("minwidth_metal3")
|
||||
self.m3_space = drc("metal3_to_metal3")
|
||||
if "metal4" in layer:
|
||||
self.m4_width = drc("minwidth_metal4")
|
||||
self.m4_space = drc("metal4_to_metal4")
|
||||
self.active_width = drc("minwidth_active")
|
||||
self.active_space = drc("active_to_body_active")
|
||||
if "contact" in layer:
|
||||
self.contact_width = drc("minwidth_contact")
|
||||
else:
|
||||
self.contact_width = drc("minwidth_active_contact")
|
||||
|
||||
self.poly_to_active = drc("poly_to_active")
|
||||
self.poly_extend_active = drc("poly_extend_active")
|
||||
if "contact" in layer:
|
||||
self.poly_to_contact = drc("poly_to_contact")
|
||||
else:
|
||||
self.poly_to_contact = drc("poly_to_active_contact")
|
||||
self.contact_to_gate = drc("contact_to_gate")
|
||||
self.well_enclose_active = drc("well_enclosure_active")
|
||||
self.implant_enclose_active = drc("implant_enclosure_active")
|
||||
self.implant_space = drc("implant_to_implant")
|
||||
|
||||
# Make some local rules for convenience
|
||||
for rule in drc.keys():
|
||||
# Single layer width rules
|
||||
match = re.search(r"minwidth_(.*)", rule)
|
||||
if match:
|
||||
if match.group(1)=="active_contact":
|
||||
setattr(self, "contact_width", drc(match.group(0)))
|
||||
else:
|
||||
setattr(self, match.group(1)+"_width", drc(match.group(0)))
|
||||
|
||||
# Single layer area rules
|
||||
match = re.search(r"minarea_(.*)", rule)
|
||||
if match:
|
||||
setattr(self, match.group(0), drc(match.group(0)))
|
||||
|
||||
# Single layer spacing rules
|
||||
match = re.search(r"(.*)_to_(.*)", rule)
|
||||
if match and match.group(1)==match.group(2):
|
||||
setattr(self, match.group(1)+"_space", drc(match.group(0)))
|
||||
elif match and match.group(1)!=match.group(2):
|
||||
if match.group(2)=="poly_active":
|
||||
setattr(self, match.group(1)+"_to_contact", drc(match.group(0)))
|
||||
else:
|
||||
setattr(self, match.group(0), drc(match.group(0)))
|
||||
|
||||
match = re.search(r"(.*)_enclose_(.*)", rule)
|
||||
if match:
|
||||
setattr(self, match.group(0), drc(match.group(0)))
|
||||
|
||||
match = re.search(r"(.*)_extend_(.*)", rule)
|
||||
if match:
|
||||
setattr(self, match.group(0), drc(match.group(0)))
|
||||
|
||||
# These are for debugging previous manual rules
|
||||
# print("poly_width", self.poly_width)
|
||||
# print("poly_space", self.poly_space)
|
||||
# print("m1_width", self.m1_width)
|
||||
# print("m1_space", self.m1_space)
|
||||
# print("m2_width", self.m2_width)
|
||||
# print("m2_space", self.m2_space)
|
||||
# print("m3_width", self.m3_width)
|
||||
# print("m3_space", self.m3_space)
|
||||
# print("m4_width", self.m4_width)
|
||||
# print("m4_space", self.m4_space)
|
||||
# print("active_width", self.active_width)
|
||||
# print("active_space", self.active_space)
|
||||
# print("contact_width", self.contact_width)
|
||||
# print("poly_to_active", self.poly_to_active)
|
||||
# print("poly_extend_active", self.poly_extend_active)
|
||||
# print("poly_to_contact", self.poly_to_contact)
|
||||
# print("contact_to_gate", self.contact_to_gate)
|
||||
# print("well_enclose_active", self.well_enclose_active)
|
||||
# print("implant_enclose_active", self.implant_enclose_active)
|
||||
# print("implant_space", self.implant_space)
|
||||
|
||||
def setup_multiport_constants(self):
|
||||
"""
|
||||
These are contants and lists that aid multiport design.
|
||||
|
||||
@@ -61,7 +61,7 @@ class layout():
|
||||
y_dir = 1
|
||||
else:
|
||||
# we lose a rail after every 2 gates
|
||||
base_offset=vector(x_offset, (inv_num+1) * height - (inv_num%2)*drc["minwidth_metal1"])
|
||||
base_offset=vector(x_offset, (inv_num+1) * height - (inv_num%2)*drc["minwidth_m1"])
|
||||
y_dir = -1
|
||||
|
||||
return (base_offset,y_dir)
|
||||
@@ -388,9 +388,9 @@ class layout():
|
||||
|
||||
def get_preferred_direction(self, layer):
|
||||
""" Return the preferred routing directions """
|
||||
if layer in ["metal1", "metal3", "metal5"]:
|
||||
if layer in ["m1", "m3", "m5"]:
|
||||
return "H"
|
||||
elif layer in ["active", "poly", "metal2", "metal4"]:
|
||||
elif layer in ["active", "poly", "m2", "m4"]:
|
||||
return "V"
|
||||
else:
|
||||
return "N"
|
||||
@@ -682,12 +682,12 @@ class layout():
|
||||
return line_positions
|
||||
|
||||
def connect_horizontal_bus(self, mapping, inst, bus_offsets,
|
||||
layer_stack=("metal1","via1","metal2")):
|
||||
layer_stack=("m1", "via1", "m2")):
|
||||
""" Horizontal version of connect_bus. """
|
||||
self.connect_bus(mapping, inst, bus_offsets, layer_stack, True)
|
||||
|
||||
def connect_vertical_bus(self, mapping, inst, bus_offsets,
|
||||
layer_stack=("metal1","via1","metal2")):
|
||||
layer_stack=("m1", "via1", "m2")):
|
||||
""" Vertical version of connect_bus. """
|
||||
self.connect_bus(mapping, inst, bus_offsets, layer_stack, False)
|
||||
|
||||
@@ -734,15 +734,15 @@ class layout():
|
||||
rotate=90)
|
||||
def get_layer_pitch(self, layer):
|
||||
""" Return the track pitch on a given layer """
|
||||
if layer=="metal1":
|
||||
if layer=="m1":
|
||||
return (self.m1_pitch,self.m1_pitch-self.m1_space,self.m1_space)
|
||||
elif layer=="metal2":
|
||||
elif layer=="m2":
|
||||
return (self.m2_pitch,self.m2_pitch-self.m2_space,self.m2_space)
|
||||
elif layer=="metal3":
|
||||
elif layer=="m3":
|
||||
return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space)
|
||||
elif layer=="metal4":
|
||||
elif layer=="m4":
|
||||
from tech import layer as tech_layer
|
||||
if "metal4" in tech_layer:
|
||||
if "m4" in tech_layer:
|
||||
return (self.m3_pitch,self.m3_pitch-self.m4_space,self.m4_space)
|
||||
else:
|
||||
return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space)
|
||||
@@ -1006,16 +1006,16 @@ class layout():
|
||||
"""
|
||||
pins=inst.get_pins(name)
|
||||
for pin in pins:
|
||||
if pin.layer=="metal3":
|
||||
if pin.layer=="m3":
|
||||
self.add_layout_pin(name, pin.layer, pin.ll(), pin.width(), pin.height())
|
||||
elif pin.layer=="metal1":
|
||||
elif pin.layer=="m1":
|
||||
self.add_power_pin(name, pin.center())
|
||||
else:
|
||||
debug.warning("{0} pins of {1} should be on metal3 or metal1 for supply router.".format(name,inst.name))
|
||||
|
||||
|
||||
|
||||
def add_power_pin(self, name, loc, vertical=False, start_layer="metal1"):
|
||||
def add_power_pin(self, name, loc, vertical=False, start_layer="m1"):
|
||||
"""
|
||||
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.
|
||||
@@ -1025,24 +1025,24 @@ class layout():
|
||||
else:
|
||||
direction=("H","H")
|
||||
|
||||
if start_layer=="metal1":
|
||||
if start_layer=="m1":
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=loc,
|
||||
directions=direction)
|
||||
|
||||
|
||||
if start_layer=="metal1" or start_layer=="metal2":
|
||||
if start_layer=="m1" or start_layer=="m2":
|
||||
via=self.add_via_center(layers=self.m2_stack,
|
||||
offset=loc,
|
||||
directions=direction)
|
||||
|
||||
if start_layer=="metal3":
|
||||
if start_layer=="m3":
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer="metal3",
|
||||
layer="m3",
|
||||
offset=loc)
|
||||
else:
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer="metal3",
|
||||
layer="m3",
|
||||
offset=loc,
|
||||
width=via.width,
|
||||
height=via.height)
|
||||
@@ -1064,7 +1064,7 @@ class layout():
|
||||
# LEFT vertical rails
|
||||
offset = ll + vector(-2*self.supply_rail_pitch, -2*self.supply_rail_pitch)
|
||||
left_gnd_pin=self.add_layout_pin(text="gnd",
|
||||
layer="metal2",
|
||||
layer="m2",
|
||||
offset=offset,
|
||||
width=self.supply_rail_width,
|
||||
height=height)
|
||||
@@ -1072,7 +1072,7 @@ class layout():
|
||||
|
||||
offset = ll + vector(-1*self.supply_rail_pitch, -1*self.supply_rail_pitch)
|
||||
left_vdd_pin=self.add_layout_pin(text="vdd",
|
||||
layer="metal2",
|
||||
layer="m2",
|
||||
offset=offset,
|
||||
width=self.supply_rail_width,
|
||||
height=height)
|
||||
@@ -1080,14 +1080,14 @@ class layout():
|
||||
# RIGHT vertical rails
|
||||
offset = vector(ur.x,ll.y) + vector(0,-2*self.supply_rail_pitch)
|
||||
right_gnd_pin = self.add_layout_pin(text="gnd",
|
||||
layer="metal2",
|
||||
layer="m2",
|
||||
offset=offset,
|
||||
width=self.supply_rail_width,
|
||||
height=height)
|
||||
|
||||
offset = vector(ur.x,ll.y) + vector(self.supply_rail_pitch,-1*self.supply_rail_pitch)
|
||||
right_vdd_pin=self.add_layout_pin(text="vdd",
|
||||
layer="metal2",
|
||||
layer="m2",
|
||||
offset=offset,
|
||||
width=self.supply_rail_width,
|
||||
height=height)
|
||||
@@ -1095,14 +1095,14 @@ class layout():
|
||||
# BOTTOM horizontal rails
|
||||
offset = ll + vector(-2*self.supply_rail_pitch, -2*self.supply_rail_pitch)
|
||||
bottom_gnd_pin=self.add_layout_pin(text="gnd",
|
||||
layer="metal1",
|
||||
layer="m1",
|
||||
offset=offset,
|
||||
width=width,
|
||||
height=self.supply_rail_width)
|
||||
|
||||
offset = ll + vector(-1*self.supply_rail_pitch, -1*self.supply_rail_pitch)
|
||||
bottom_vdd_pin=self.add_layout_pin(text="vdd",
|
||||
layer="metal1",
|
||||
layer="m1",
|
||||
offset=offset,
|
||||
width=width,
|
||||
height=self.supply_rail_width)
|
||||
@@ -1110,14 +1110,14 @@ class layout():
|
||||
# TOP horizontal rails
|
||||
offset = vector(ll.x, ur.y) + vector(-2*self.supply_rail_pitch,0)
|
||||
top_gnd_pin=self.add_layout_pin(text="gnd",
|
||||
layer="metal1",
|
||||
layer="m1",
|
||||
offset=offset,
|
||||
width=width,
|
||||
height=self.supply_rail_width)
|
||||
|
||||
offset = vector(ll.x, ur.y) + vector(-1*self.supply_rail_pitch, self.supply_rail_pitch)
|
||||
top_vdd_pin=self.add_layout_pin(text="vdd",
|
||||
layer="metal1",
|
||||
layer="m1",
|
||||
offset=offset,
|
||||
width=width,
|
||||
height=self.supply_rail_width)
|
||||
@@ -1139,7 +1139,7 @@ class layout():
|
||||
from sram_factory import factory
|
||||
while True:
|
||||
c=factory.create(module_type="contact",
|
||||
layer_stack=("metal1","via1","metal2"),
|
||||
layer_stack=self.m1_stack,
|
||||
dimensions=(self.supply_vias, self.supply_vias))
|
||||
if c.second_layer_width < self.supply_rail_width and c.second_layer_height < self.supply_rail_width:
|
||||
self.supply_vias += 1
|
||||
|
||||
Reference in New Issue
Block a user