mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into update_scmos_models
This commit is contained in:
commit
d722311822
|
|
@ -7,39 +7,44 @@
|
|||
#
|
||||
import hierarchy_design
|
||||
import debug
|
||||
import utils
|
||||
from tech import drc,layer
|
||||
from tech import drc, layer
|
||||
from vector import vector
|
||||
|
||||
|
||||
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 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.
|
||||
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 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.
|
||||
|
||||
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), directions=("V","V"), implant_type=None, well_type=None, name=""):
|
||||
# This will ignore the name parameter since we can guarantee a unique name here
|
||||
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
|
||||
|
||||
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.add_comment("implant type: {}\n".format(implant_type))
|
||||
self.add_comment("well_type: {}\n".format(well_type))
|
||||
|
||||
self.layer_stack = layer_stack
|
||||
self.dimensions = dimensions
|
||||
self.directions = directions
|
||||
self.offset = vector(0,0)
|
||||
self.offset = vector(0, 0)
|
||||
self.implant_type = implant_type
|
||||
self.well_type = well_type
|
||||
self.well_type = well_type
|
||||
# Module does not have pins, but has empty pin list.
|
||||
self.pins = []
|
||||
self.create_layout()
|
||||
|
|
@ -59,7 +64,7 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
if self.implant_type and self.well_type:
|
||||
self.create_implant_well_enclosures()
|
||||
elif self.implant_type or self.well_type:
|
||||
debug.error(-1,"Must define both implant and well type or none at all.")
|
||||
debug.error(-1, "Must define both implant and well type or none at all.")
|
||||
|
||||
def setup_layers(self):
|
||||
""" Locally assign the layer names. """
|
||||
|
|
@ -67,10 +72,11 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
(first_layer, via_layer, second_layer) = self.layer_stack
|
||||
self.first_layer_name = first_layer
|
||||
self.via_layer_name = via_layer
|
||||
# Some technologies have a separate active contact from the poly contact
|
||||
# Some technologies have a separate active
|
||||
# contact from the poly contact
|
||||
# We will use contact for DRC, but active_contact for output
|
||||
if first_layer=="active" or second_layer=="active":
|
||||
self.via_layer_name_expanded = "active_"+via_layer
|
||||
if first_layer == "active" or second_layer == "active":
|
||||
self.via_layer_name_expanded = "active_" + via_layer
|
||||
else:
|
||||
self.via_layer_name_expanded = via_layer
|
||||
self.second_layer_name = second_layer
|
||||
|
|
@ -97,19 +103,19 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
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))
|
||||
|
||||
|
||||
# In some technologies, the minimum width may be larger than the overlap requirement around the via, so
|
||||
# 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)
|
||||
(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)
|
||||
(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)
|
||||
(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)
|
||||
(first_layer_minwidth - self.contact_array_height) / 2)
|
||||
else:
|
||||
debug.error("Invalid first layer direction.", -1)
|
||||
|
||||
|
|
@ -117,23 +123,23 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
# 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)
|
||||
(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)
|
||||
(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)
|
||||
(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)
|
||||
(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"""
|
||||
# offset for the via array
|
||||
self.via_layer_position =vector(max(self.first_layer_horizontal_enclosure,self.second_layer_horizontal_enclosure),
|
||||
max(self.first_layer_vertical_enclosure,self.second_layer_vertical_enclosure))
|
||||
self.via_layer_position = vector(
|
||||
max(self.first_layer_horizontal_enclosure, self.second_layer_horizontal_enclosure),
|
||||
max(self.first_layer_vertical_enclosure, self.second_layer_vertical_enclosure))
|
||||
|
||||
for i in range(self.dimensions[1]):
|
||||
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
||||
|
|
@ -142,15 +148,16 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
offset=offset,
|
||||
width=self.contact_width,
|
||||
height=self.contact_width)
|
||||
offset = offset + vector(self.contact_pitch,0)
|
||||
offset = offset + vector(self.contact_pitch, 0)
|
||||
|
||||
def create_first_layer_enclosure(self):
|
||||
# this is if the first and second layers are different
|
||||
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
|
||||
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
|
||||
self.first_layer_position = vector(
|
||||
max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure, 0),
|
||||
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure, 0))
|
||||
|
||||
self.first_layer_width = self.contact_array_width + 2*self.first_layer_horizontal_enclosure
|
||||
self.first_layer_height = self.contact_array_height + 2*self.first_layer_vertical_enclosure
|
||||
self.first_layer_width = self.contact_array_width + 2 * self.first_layer_horizontal_enclosure
|
||||
self.first_layer_height = self.contact_array_height + 2 * self.first_layer_vertical_enclosure
|
||||
self.add_rect(layer=self.first_layer_name,
|
||||
offset=self.first_layer_position,
|
||||
width=self.first_layer_width,
|
||||
|
|
@ -158,27 +165,28 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
|
||||
def create_second_layer_enclosure(self):
|
||||
# this is if the first and second layers are different
|
||||
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
|
||||
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
|
||||
self.second_layer_position = vector(
|
||||
max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure, 0),
|
||||
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure, 0))
|
||||
|
||||
self.second_layer_width = self.contact_array_width + 2*self.second_layer_horizontal_enclosure
|
||||
self.second_layer_height = self.contact_array_height + 2*self.second_layer_vertical_enclosure
|
||||
self.second_layer_width = self.contact_array_width + 2 * self.second_layer_horizontal_enclosure
|
||||
self.second_layer_height = self.contact_array_height + 2 * self.second_layer_vertical_enclosure
|
||||
self.add_rect(layer=self.second_layer_name,
|
||||
offset=self.second_layer_position,
|
||||
width=self.second_layer_width,
|
||||
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_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")
|
||||
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_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")
|
||||
self.add_rect(layer="{}well".format(self.well_type),
|
||||
offset=well_position,
|
||||
width=well_width,
|
||||
|
|
@ -188,16 +196,30 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
""" Get total power of a module """
|
||||
return self.return_power()
|
||||
|
||||
|
||||
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"), directions=("H","V"))
|
||||
active = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"), 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"))
|
||||
well = factory.create(module_type="contact",
|
||||
layer_stack=("active", "contact", "metal1"),
|
||||
directions=("H", "V"))
|
||||
active = factory.create(module_type="contact",
|
||||
layer_stack=("active", "contact", "metal1"),
|
||||
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"))
|
||||
if "metal4" in layer.keys():
|
||||
m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"), directions=("H","V"))
|
||||
m3m4 = factory.create(module_type="contact",
|
||||
layer_stack=("metal3", "via3", "metal4"),
|
||||
directions=("H", "V"))
|
||||
else:
|
||||
m3m4 = None
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
|
||||
|
||||
class delay_data():
|
||||
"""
|
||||
This is the delay class to represent the delay information
|
||||
|
|
@ -20,13 +21,13 @@ class delay_data():
|
|||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
return "Delay Data: Delay "+str(self.delay)+", Slew "+str(self.slew)+""
|
||||
return "Delta Data: Delay {} Slew {}".format(self.delay, self.slew)
|
||||
|
||||
def __add__(self, other):
|
||||
"""
|
||||
Override - function (left), for delay_data: a+b != b+a
|
||||
"""
|
||||
assert isinstance(other,delay_data)
|
||||
assert isinstance(other, delay_data)
|
||||
return delay_data(other.delay + self.delay,
|
||||
other.slew)
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ class delay_data():
|
|||
"""
|
||||
Override - function (right), for delay_data: a+b != b+a
|
||||
"""
|
||||
assert isinstance(other,delay_data)
|
||||
assert isinstance(other, delay_data)
|
||||
return delay_data(other.delay + self.delay,
|
||||
self.slew)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,9 @@
|
|||
#
|
||||
from hierarchy_design import hierarchy_design
|
||||
import contact
|
||||
import globals
|
||||
import verify
|
||||
import debug
|
||||
import os
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class design(hierarchy_design):
|
||||
"""
|
||||
This is the same as the hierarchy_design class except it contains
|
||||
|
|
@ -21,29 +18,29 @@ class design(hierarchy_design):
|
|||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
hierarchy_design.__init__(self,name)
|
||||
hierarchy_design.__init__(self, name)
|
||||
|
||||
self.setup_drc_constants()
|
||||
self.setup_multiport_constants()
|
||||
|
||||
from tech import layer
|
||||
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)
|
||||
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 layer:
|
||||
self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space)
|
||||
self.m3_pitch = max(contact.m3m4.width, contact.m3m4.height) + max(self.m3_space, self.m4_space)
|
||||
else:
|
||||
self.m3_pitch = self.m2_pitch
|
||||
|
||||
def setup_drc_constants(self):
|
||||
""" These are some DRC constants used in many places in the compiler."""
|
||||
from tech import drc,layer
|
||||
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.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.m2_space = drc("metal2_to_metal2")
|
||||
self.m3_width = drc("minwidth_metal3")
|
||||
self.m3_space = drc("metal3_to_metal3")
|
||||
if "metal4" in layer:
|
||||
|
|
@ -93,12 +90,12 @@ class design(hierarchy_design):
|
|||
port_number += 1
|
||||
for port in range(OPTS.num_w_ports):
|
||||
self.write_ports.append(port_number)
|
||||
self.writeonly_ports.append(port_number)
|
||||
self.writeonly_ports.append(port_number)
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_r_ports):
|
||||
self.read_ports.append(port_number)
|
||||
self.readonly_ports.append(port_number)
|
||||
port_number += 1
|
||||
port_number += 1
|
||||
|
||||
def analytical_power(self, corner, load):
|
||||
""" Get total power of a module """
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
"""
|
||||
This provides a set of useful generic types for the gdsMill interface.
|
||||
This provides a set of useful generic types for the gdsMill interface.
|
||||
"""
|
||||
import debug
|
||||
from vector import vector
|
||||
|
|
@ -15,6 +15,7 @@ import math
|
|||
from globals import OPTS
|
||||
from utils import round_to_grid
|
||||
|
||||
|
||||
class geometry:
|
||||
"""
|
||||
A specific path, shape, or text geometry. Base class for shared
|
||||
|
|
@ -27,11 +28,11 @@ class geometry:
|
|||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
debug.error("__str__ must be overridden by all geometry types.",1)
|
||||
debug.error("__str__ must be overridden by all geometry types.", 1)
|
||||
|
||||
def __repr__(self):
|
||||
""" override print function output """
|
||||
debug.error("__repr__ must be overridden by all geometry types.",1)
|
||||
debug.error("__repr__ must be overridden by all geometry types.", 1)
|
||||
|
||||
# def translate_coords(self, coords, mirr, angle, xyShift):
|
||||
# """Calculate coordinates after flip, rotate, and shift"""
|
||||
|
|
@ -46,50 +47,52 @@ class geometry:
|
|||
"""Calculate coordinates after flip, rotate, and shift"""
|
||||
coordinate = []
|
||||
for item in coords:
|
||||
x = item[0]*math.cos(angle) - item[1]*mirr*math.sin(angle) + offset[0]
|
||||
y = item[0]*math.sin(angle) + item[1]*mirr*math.cos(angle) + offset[1]
|
||||
x = item[0] * math.cos(angle) - item[1] * mirr * math.sin(angle) + offset[0]
|
||||
y = item[0] * math.sin(angle) + item[1] * mirr * math.cos(angle) + offset[1]
|
||||
coordinate += [[x, y]]
|
||||
return coordinate
|
||||
|
||||
def normalize(self):
|
||||
""" Re-find the LL and UR points after a transform """
|
||||
(first,second)=self.boundary
|
||||
ll = vector(min(first[0],second[0]),min(first[1],second[1])).snap_to_grid()
|
||||
ur = vector(max(first[0],second[0]),max(first[1],second[1])).snap_to_grid()
|
||||
self.boundary=[ll,ur]
|
||||
(first, second) = self.boundary
|
||||
ll = vector(min(first[0], second[0]),
|
||||
min(first[1], second[1])).snap_to_grid()
|
||||
ur = vector(max(first[0], second[0]),
|
||||
max(first[1], second[1])).snap_to_grid()
|
||||
self.boundary = [ll, ur]
|
||||
|
||||
def update_boundary(self):
|
||||
""" Update the boundary with a new placement. """
|
||||
self.compute_boundary(self.offset,self.mirror,self.rotate)
|
||||
self.compute_boundary(self.offset, self.mirror, self.rotate)
|
||||
|
||||
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
|
||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||
def compute_boundary(self, offset=vector(0, 0), mirror="", rotate=0):
|
||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||
We must then re-find the ll and ur. The master is the cell instance. """
|
||||
if OPTS.netlist_only:
|
||||
return
|
||||
(ll,ur) = [vector(0,0),vector(self.width,self.height)]
|
||||
(ll, ur) = [vector(0, 0), vector(self.width, self.height)]
|
||||
|
||||
if mirror=="MX":
|
||||
ll=ll.scale(1,-1)
|
||||
ur=ur.scale(1,-1)
|
||||
elif mirror=="MY":
|
||||
ll=ll.scale(-1,1)
|
||||
ur=ur.scale(-1,1)
|
||||
elif mirror=="XY":
|
||||
ll=ll.scale(-1,-1)
|
||||
ur=ur.scale(-1,-1)
|
||||
if mirror == "MX":
|
||||
ll = ll.scale(1, -1)
|
||||
ur = ur.scale(1, -1)
|
||||
elif mirror == "MY":
|
||||
ll = ll.scale(-1, 1)
|
||||
ur = ur.scale(-1, 1)
|
||||
elif mirror == "XY":
|
||||
ll = ll.scale(-1, -1)
|
||||
ur = ur.scale(-1, -1)
|
||||
|
||||
if rotate==90:
|
||||
ll=ll.rotate_scale(-1,1)
|
||||
ur=ur.rotate_scale(-1,1)
|
||||
elif rotate==180:
|
||||
ll=ll.scale(-1,-1)
|
||||
ur=ur.scale(-1,-1)
|
||||
elif rotate==270:
|
||||
ll=ll.rotate_scale(1,-1)
|
||||
ur=ur.rotate_scale(1,-1)
|
||||
if rotate == 90:
|
||||
ll = ll.rotate_scale(-1, 1)
|
||||
ur = ur.rotate_scale(-1, 1)
|
||||
elif rotate == 180:
|
||||
ll = ll.scale(-1, -1)
|
||||
ur = ur.scale(-1, -1)
|
||||
elif rotate == 270:
|
||||
ll = ll.rotate_scale(1, -1)
|
||||
ur = ur.rotate_scale(1, -1)
|
||||
|
||||
self.boundary=[offset+ll,offset+ur]
|
||||
self.boundary = [offset + ll, offset + ur]
|
||||
self.normalize()
|
||||
|
||||
def ll(self):
|
||||
|
|
@ -108,7 +111,6 @@ class geometry:
|
|||
""" Return the upper left corner """
|
||||
return vector(self.boundary[0].x, self.boundary[1].y)
|
||||
|
||||
|
||||
def uy(self):
|
||||
""" Return the upper edge """
|
||||
return self.boundary[1].y
|
||||
|
|
@ -127,11 +129,11 @@ class geometry:
|
|||
|
||||
def cx(self):
|
||||
""" Return the center x """
|
||||
return 0.5*(self.boundary[0].x + self.boundary[1].x)
|
||||
return 0.5 * (self.boundary[0].x + self.boundary[1].x)
|
||||
|
||||
def cy(self):
|
||||
""" Return the center y """
|
||||
return 0.5*(self.boundary[0].y + self.boundary[1].y)
|
||||
return 0.5 * (self.boundary[0].y + self.boundary[1].y)
|
||||
|
||||
|
||||
class instance(geometry):
|
||||
|
|
@ -139,10 +141,11 @@ class instance(geometry):
|
|||
An instance of an instance/module with a specified location and
|
||||
rotation
|
||||
"""
|
||||
def __init__(self, name, mod, offset=[0,0], mirror="R0", rotate=0):
|
||||
def __init__(self, name, mod, offset=[0, 0], mirror="R0", rotate=0):
|
||||
"""Initializes an instance to represent a module"""
|
||||
geometry.__init__(self)
|
||||
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
|
||||
debug.check(mirror not in ["R90", "R180", "R270"],
|
||||
"Please use rotation and not mirroring during instantiation.")
|
||||
|
||||
self.name = name
|
||||
self.mod = mod
|
||||
|
|
@ -154,13 +157,13 @@ class instance(geometry):
|
|||
self.width = 0
|
||||
self.height = 0
|
||||
else:
|
||||
if mirror in ["R90","R270"] or rotate in [90,270]:
|
||||
if mirror in ["R90", "R270"] or rotate in [90, 270]:
|
||||
self.width = round_to_grid(mod.height)
|
||||
self.height = round_to_grid(mod.width)
|
||||
else:
|
||||
self.width = round_to_grid(mod.width)
|
||||
self.height = round_to_grid(mod.height)
|
||||
self.compute_boundary(offset,mirror,rotate)
|
||||
self.compute_boundary(offset, mirror, rotate)
|
||||
|
||||
debug.info(4, "creating instance: " + self.name)
|
||||
|
||||
|
|
@ -169,18 +172,18 @@ class instance(geometry):
|
|||
Apply the transform of the instance placement to give absolute blockages."""
|
||||
angle = math.radians(float(self.rotate))
|
||||
mirr = 1
|
||||
if self.mirror=="R90":
|
||||
if self.mirror == "R90":
|
||||
angle += math.radians(90.0)
|
||||
elif self.mirror=="R180":
|
||||
elif self.mirror == "R180":
|
||||
angle += math.radians(180.0)
|
||||
elif self.mirror=="R270":
|
||||
elif self.mirror == "R270":
|
||||
angle += math.radians(270.0)
|
||||
elif self.mirror=="MX":
|
||||
elif self.mirror == "MX":
|
||||
mirr = -1
|
||||
elif self.mirror=="MY":
|
||||
elif self.mirror == "MY":
|
||||
mirr = -1
|
||||
angle += math.radians(180.0)
|
||||
elif self.mirror=="XY":
|
||||
elif self.mirror == "XY":
|
||||
mirr = 1
|
||||
angle += math.radians(180.0)
|
||||
|
||||
|
|
@ -226,7 +229,7 @@ class instance(geometry):
|
|||
this instance location. Index will return one of several pins."""
|
||||
|
||||
import copy
|
||||
if index==-1:
|
||||
if index == -1:
|
||||
pin = copy.deepcopy(self.mod.get_pin(name))
|
||||
pin.transform(self.offset,self.mirror,self.rotate)
|
||||
return pin
|
||||
|
|
@ -339,6 +342,7 @@ class label(geometry):
|
|||
""" override print function output """
|
||||
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " )"
|
||||
|
||||
|
||||
class rectangle(geometry):
|
||||
"""Represents a rectangular shape"""
|
||||
|
||||
|
|
@ -351,22 +355,23 @@ class rectangle(geometry):
|
|||
self.size = vector(width, height).snap_to_grid()
|
||||
self.width = round_to_grid(self.size.x)
|
||||
self.height = round_to_grid(self.size.y)
|
||||
self.compute_boundary(offset,"",0)
|
||||
self.compute_boundary(offset, "", 0)
|
||||
|
||||
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
|
||||
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
|
||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||
|
||||
|
||||
def get_blockages(self, layer):
|
||||
""" Returns a list of one rectangle if it is on this layer"""
|
||||
if self.layerNumber == layer:
|
||||
return [[self.offset, vector(self.offset.x+self.width,self.offset.y+self.height)]]
|
||||
return [[self.offset,
|
||||
vector(self.offset.x + self.width,
|
||||
self.offset.y + self.height)]]
|
||||
else:
|
||||
return []
|
||||
|
||||
def gds_write_file(self, new_layout):
|
||||
"""Writes the rectangular shape to GDS"""
|
||||
debug.info(4, "writing rectangle (" + str(self.layerNumber) + "):"
|
||||
debug.info(4, "writing rectangle (" + str(self.layerNumber) + "):"
|
||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||
new_layout.addBox(layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ def info(lev, str):
|
|||
frm = inspect.stack()[1]
|
||||
mod = inspect.getmodule(frm[0])
|
||||
# classname = frm.f_globals['__name__']
|
||||
if mod.__name__ == None:
|
||||
if mod.__name__ is None:
|
||||
class_name = ""
|
||||
else:
|
||||
class_name = mod.__name__
|
||||
|
|
|
|||
|
|
@ -13,10 +13,7 @@ created without re-running the entire process. Right now, it assumes the nominal
|
|||
corner, but should probably be extended.
|
||||
"""
|
||||
|
||||
import sys,os
|
||||
import datetime
|
||||
import re
|
||||
import importlib
|
||||
import sys
|
||||
from globals import *
|
||||
|
||||
(OPTS, args) = parse_args()
|
||||
|
|
|
|||
|
|
@ -16,34 +16,32 @@ a LEF (.lef) file for preliminary P&R (real one should be from layout)
|
|||
a Liberty (.lib) file for timing analysis/optimization
|
||||
"""
|
||||
|
||||
import sys,os
|
||||
import sys
|
||||
import datetime
|
||||
import re
|
||||
import importlib
|
||||
from globals import *
|
||||
import globals as g
|
||||
|
||||
(OPTS, args) = parse_args()
|
||||
(OPTS, args) = g.parse_args()
|
||||
|
||||
# Check that we are left with a single configuration file as argument.
|
||||
if len(args) != 1:
|
||||
print(USAGE)
|
||||
print(g.USAGE)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
# These depend on arguments, so don't load them until now.
|
||||
import debug
|
||||
|
||||
init_openram(config_file=args[0], is_unit_test=False)
|
||||
g.init_openram(config_file=args[0], is_unit_test=False)
|
||||
|
||||
# Only print banner here so it's not in unit tests
|
||||
print_banner()
|
||||
g.print_banner()
|
||||
|
||||
# Keep track of running stats
|
||||
start_time = datetime.datetime.now()
|
||||
print_time("Start",start_time)
|
||||
g.print_time("Start", start_time)
|
||||
|
||||
# Output info about this run
|
||||
report_status()
|
||||
g.report_status()
|
||||
|
||||
from sram_config import sram_config
|
||||
|
||||
|
|
@ -54,15 +52,16 @@ c = sram_config(word_size=OPTS.word_size,
|
|||
write_size=OPTS.write_size)
|
||||
debug.print_raw("Words per row: {}".format(c.words_per_row))
|
||||
|
||||
#from parser import *
|
||||
output_extensions = ["sp","v","lib","py","html","log"]
|
||||
output_extensions = ["sp", "v", "lib", "py", "html", "log"]
|
||||
# Only output lef/gds if back-end
|
||||
if not OPTS.netlist_only:
|
||||
output_extensions.extend(["lef","gds"])
|
||||
output_extensions.extend(["lef", "gds"])
|
||||
|
||||
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
|
||||
output_files = ["{0}{1}.{2}".format(OPTS.output_path,
|
||||
OPTS.output_name, x)
|
||||
for x in output_extensions]
|
||||
debug.print_raw("Output files are: ")
|
||||
for path in output_files:
|
||||
for path in output_files:
|
||||
debug.print_raw(path)
|
||||
|
||||
|
||||
|
|
@ -74,7 +73,7 @@ s = sram(sram_config=c,
|
|||
s.save()
|
||||
|
||||
# Delete temp files etc.
|
||||
end_openram()
|
||||
print_time("End",datetime.datetime.now(), start_time)
|
||||
g.end_openram()
|
||||
g.print_time("End", datetime.datetime.now(), start_time)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import optparse
|
||||
import getpass
|
||||
import getpass
|
||||
import os
|
||||
#import sram_config
|
||||
|
||||
class options(optparse.Values):
|
||||
"""
|
||||
Class for holding all of the OpenRAM options. All of these options can be over-riden in a configuration file
|
||||
Class for holding all of the OpenRAM options. All
|
||||
of these options can be over-riden in a configuration file
|
||||
that is the sole required command-line positional argument for openram.py.
|
||||
"""
|
||||
|
||||
|
|
@ -39,15 +39,16 @@ class options(optparse.Values):
|
|||
process_corners = ""
|
||||
|
||||
# Size parameters must be specified by user in config file.
|
||||
#num_words = 0
|
||||
#word_size = 0
|
||||
# num_words = 0
|
||||
# word_size = 0
|
||||
# You can manually specify banks, but it is better to auto-detect it.
|
||||
num_banks = 1
|
||||
|
||||
###################
|
||||
# Optimization options
|
||||
###################
|
||||
rbl_delay_percentage = 0.5 #Approximate percentage of delay compared to bitlines
|
||||
# Approximate percentage of delay compared to bitlines
|
||||
rbl_delay_percentage = 0.5
|
||||
|
||||
# Allow manual adjustment of the delay chain over automatic
|
||||
use_tech_delay_chain_size = False
|
||||
|
|
@ -65,7 +66,8 @@ class options(optparse.Values):
|
|||
openram_temp = os.path.abspath(os.environ.get("OPENRAM_TMP"))
|
||||
except:
|
||||
# Else use a unique temporary directory
|
||||
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),
|
||||
os.getpid())
|
||||
# This is the verbosity level to control debug information. 0 is none, 1
|
||||
# is minimal, etc.
|
||||
debug_level = 0
|
||||
|
|
@ -100,7 +102,8 @@ class options(optparse.Values):
|
|||
drc_name = ""
|
||||
lvs_name = ""
|
||||
pex_name = ""
|
||||
# The DRC/LVS/PEX executable being used which is derived from the user PATH.
|
||||
# The DRC/LVS/PEX executable being used
|
||||
# which is derived from the user PATH.
|
||||
drc_exe = None
|
||||
lvs_exe = None
|
||||
pex_exe = None
|
||||
|
|
@ -113,15 +116,14 @@ class options(optparse.Values):
|
|||
output_path = "."
|
||||
# Define the output file base name
|
||||
output_name = ""
|
||||
# Use analytical delay models by default rather than (slow) characterization
|
||||
# Use analytical delay models by default
|
||||
# rather than (slow) characterization
|
||||
analytical_delay = True
|
||||
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
|
||||
# Purge the temp directory after a successful
|
||||
# run (doesn't purge on errors, anyhow)
|
||||
purge_temp = True
|
||||
|
||||
|
||||
###################
|
||||
# These are the default modules that can be over-riden
|
||||
###################
|
||||
bank_select = "bank_select"
|
||||
bitcell_array = "bitcell_array"
|
||||
bitcell = "bitcell"
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class sram_factory:
|
||||
"""
|
||||
This is a factory pattern to create modules for usage in an SRAM.
|
||||
|
|
@ -19,7 +19,7 @@ class sram_factory:
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
# A dictionary of modules indexed by module type
|
||||
# A dictionary of modules indexed by module type
|
||||
self.modules = {}
|
||||
# These are the indices to append to name to make unique object names
|
||||
self.module_indices = {}
|
||||
|
|
@ -34,8 +34,8 @@ class sram_factory:
|
|||
|
||||
def create(self, module_type, **kwargs):
|
||||
"""
|
||||
A generic function to create a module with a given module_type. The args
|
||||
are passed directly to the module constructor.
|
||||
A generic function to create a module with a given module_type.
|
||||
The args are passed directly to the module constructor.
|
||||
"""
|
||||
# if name!="":
|
||||
# # This is a special case where the name and type don't match
|
||||
|
|
@ -58,28 +58,30 @@ 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(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.
|
||||
if len(kwargs)>0:
|
||||
# This is especially for library cells so that the
|
||||
# spice and gds files can be found.
|
||||
if len(kwargs) > 0:
|
||||
# Create a unique name and increment the index
|
||||
module_name = "{0}_{1}".format(module_type, self.module_indices[module_type])
|
||||
module_name = "{0}_{1}".format(module_type,
|
||||
self.module_indices[module_type])
|
||||
self.module_indices[module_type] += 1
|
||||
else:
|
||||
module_name = module_type
|
||||
|
||||
#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))
|
||||
|
||||
# type_str = "type={}".format(module_type)
|
||||
# name_str = "name={}".format(module_name)
|
||||
# kwargs_str = "kwargs={}".format(str(kwargs))
|
||||
# import debug
|
||||
# debug.info(0, "New module:" + type_str + name_str + kwargs_str)
|
||||
obj = mod(name=module_name, **kwargs)
|
||||
self.objects[module_type].append((kwargs, obj))
|
||||
return obj
|
||||
|
||||
def get_mods(self, module_type):
|
||||
|
|
@ -90,11 +92,11 @@ class sram_factory:
|
|||
module_type = getattr(OPTS, module_type)
|
||||
try:
|
||||
mod_tuples = self.objects[module_type]
|
||||
mods = [mod for kwargs,mod in mod_tuples]
|
||||
mods = [mod for kwargs, mod in mod_tuples]
|
||||
except KeyError:
|
||||
mods = []
|
||||
return mods
|
||||
|
||||
|
||||
|
||||
# Make a factory
|
||||
factory = sram_factory()
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
import pstats
|
||||
p = pstats.Stats("profile.dat")
|
||||
p.strip_dirs()
|
||||
#p.sort_stats("cumulative")
|
||||
# p.sort_stats("cumulative")
|
||||
p.sort_stats("tottime")
|
||||
#p.print_stats(50)
|
||||
# p.print_stats(50)
|
||||
p.print_stats()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue