Merge branch 'dev' of https://github.com/VLSIDA/PrivateRAM into multiport

This commit is contained in:
Michael Timothy Grimes 2018-11-05 08:56:19 -08:00
commit 3c9821991b
93 changed files with 1514 additions and 868 deletions

View File

@ -147,8 +147,12 @@ class instance(geometry):
self.width = 0
self.height = 0
else:
self.width = round_to_grid(mod.width)
self.height = round_to_grid(mod.height)
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)
debug.info(4, "creating instance: " + self.name)

View File

@ -2,6 +2,7 @@ import debug
from tech import GDS, drc
from vector import vector
from tech import layer
import math
class pin_layout:
"""
@ -18,6 +19,10 @@ class pin_layout:
self.rect = [vector(rect[0]),vector(rect[1])]
# snap the rect to the grid
self.rect = [x.snap_to_grid() for x in self.rect]
debug.check(self.width()>0,"Zero width pin.")
debug.check(self.height()>0,"Zero height pin.")
# if it's a layer number look up the layer name. this assumes a unique layer number.
if type(layer_name_num)==int:
self.layer = list(layer.keys())[list(layer.values()).index(layer_name_num)]
@ -113,24 +118,45 @@ class pin_layout:
return y_overlaps
def xcontains(self, other):
""" Check if shape contains the x overlap """
(ll,ur) = self.rect
(oll,our) = other.rect
return (oll.x >= ll.x and our.x <= ur.x)
def ycontains(self, other):
""" Check if shape contains the y overlap """
(ll,ur) = self.rect
(oll,our) = other.rect
return (oll.y >= ll.y and our.y <= ur.y)
def contains(self, other):
""" Check if a shape contains another rectangle """
# If it is the same shape entirely, it is contained!
if self == other:
return True
# Can only overlap on the same layer
if self.layer != other.layer:
return False
(ll,ur) = self.rect
(oll,our) = other.rect
if not (oll.y >= ll.y and oll.y <= ur.y):
if not self.xcontains(other):
return False
if not (oll.x >= ll.x and oll.x <= ur.x):
if not self.ycontains(other):
return False
return True
def contained_by_any(self, shape_list):
""" Checks if shape is contained by any in the list """
for shape in shape_list:
if shape.contains(self):
return True
return False
def overlaps(self, other):
""" Check if a shape overlaps with a rectangle """
@ -274,3 +300,127 @@ class pin_layout:
magnification=GDS["zoom"],
rotate=None)
def compute_overlap(self, other):
""" Calculate the rectangular overlap of two rectangles. """
(r1_ll,r1_ur) = self.rect
(r2_ll,r2_ur) = other.rect
#ov_ur = vector(min(r1_ur.x,r2_ur.x),min(r1_ur.y,r2_ur.y))
#ov_ll = vector(max(r1_ll.x,r2_ll.x),max(r1_ll.y,r2_ll.y))
dy = min(r1_ur.y,r2_ur.y)-max(r1_ll.y,r2_ll.y)
dx = min(r1_ur.x,r2_ur.x)-max(r1_ll.x,r2_ll.x)
if dx>=0 and dy>=0:
return [dx,dy]
else:
return [0,0]
def overlap_length(self, other):
"""
Calculate the intersection segment and determine its length
"""
if self.contains(other):
return math.inf
elif other.contains(self):
return math.inf
else:
intersections = self.compute_overlap_segment(other)
# This is the common case where two pairs of edges overlap
# at two points, so just find the distance between those two points
if len(intersections)==2:
(p1,p2) = intersections
return math.sqrt(pow(p1[0]-p2[0],2) + pow(p1[1]-p2[1],2))
else:
# This is where we had a corner intersection or none
return 0
def compute_overlap_segment(self, other):
"""
Calculate the intersection segment of two rectangles
(if any)
"""
(r1_ll,r1_ur) = self.rect
(r2_ll,r2_ur) = other.rect
# The other corners besides ll and ur
r1_ul = vector(r1_ll.x, r1_ur.y)
r1_lr = vector(r1_ur.x, r1_ll.y)
r2_ul = vector(r2_ll.x, r2_ur.y)
r2_lr = vector(r2_ur.x, r2_ll.y)
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
# R1 edges CW
r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll]
r1_edges = []
for (p,q) in pairwise(r1_cw_points):
r1_edges.append([p,q])
# R2 edges CW
r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll]
r2_edges = []
for (p,q) in pairwise(r2_cw_points):
r2_edges.append([p,q])
# There are 4 edges on each rectangle
# so just brute force check intersection of each
# Two pairs of them should intersect
intersections = []
for r1e in r1_edges:
for r2e in r2_edges:
i = self.segment_intersection(r1e, r2e)
if i:
intersections.append(i)
return intersections
def on_segment(self, p, q, r):
"""
Given three co-linear points, determine if q lies on segment pr
"""
if q[0] <= max(p[0], r[0]) and \
q[0] >= min(p[0], r[0]) and \
q[1] <= max(p[1], r[1]) and \
q[1] >= min(p[1], r[1]):
return True
return False
def segment_intersection(self, s1, s2):
"""
Determine the intersection point of two segments
Return the a segment if they overlap.
Return None if they don't.
"""
(a,b) = s1
(c,d) = s2
# Line AB represented as a1x + b1y = c1
a1 = b.y - a.y
b1 = a.x - b.x
c1 = a1*a.x + b1*a.y
# Line CD represented as a2x + b2y = c2
a2 = d.y - c.y
b2 = c.x - d.x
c2 = a2*c.x + b2*c.y
determinant = a1*b2 - a2*b1
if determinant!=0:
x = (b2*c1 - b1*c2)/determinant
y = (a1*c2 - a2*c1)/determinant
r = [x,y]
if self.on_segment(a, r, b) and self.on_segment(c, r, d):
return [x, y]
return None

View File

@ -62,14 +62,10 @@ class route(design):
plist = list(pairwise(self.path))
for p0,p1 in plist:
if p0.z != p1.z: # via
# offset if not rotated
#via_offset = vector(p0.x+0.5*self.c.width,p0.y+0.5*self.c.height)
# offset if rotated
via_offset = vector(p0.x+0.5*self.c.height,p0.y-0.5*self.c.width)
via_size = [self.num_vias]*2
self.obj.add_via(self.layer_stack,via_offset,size=via_size,rotate=90)
self.obj.add_via_center(self.layer_stack,vector(p0.x,p0.y),size=via_size,rotate=90)
elif p0.x != p1.x and p0.y != p1.y: # diagonal!
debug.error("Non-changing direction!")
debug.error("Diagonal route! {}".format(self.path),-3)
else:
# this will draw an extra corner at the end but that is ok
self.draw_corner_wire(p1)

View File

@ -66,7 +66,7 @@ def get_gds_size(name, gds_filename, units, layer):
Open a GDS file and return the size from either the
bounding box or a border layer.
"""
debug.info(2,"Creating VLSI layout for {}".format(name))
debug.info(4,"Creating VLSI layout for {}".format(name))
cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(gds_filename)

View File

@ -20,6 +20,10 @@ class functional(simulation):
def __init__(self, sram, spfile, corner):
simulation.__init__(self, sram, spfile, corner)
# Seed the characterizer with a constant seed for unit tests
if OPTS.is_unit_test:
random.seed(12345)
self.set_corner(corner)
self.set_spice_constants()

View File

@ -3,7 +3,6 @@ from design import design
import debug
import math
import tech
import random
from .stimuli import *
from .trim_spice import *
from .charutils import *

View File

@ -1,4 +1,5 @@
from enum import Enum
from vector3d import vector3d
class direction(Enum):
NORTH = 1
@ -7,3 +8,60 @@ class direction(Enum):
WEST = 4
UP = 5
DOWN = 6
NORTHEAST = 7
NORTHWEST = 8
SOUTHEAST = 9
SOUTHWEST = 10
def get_offset(direct):
"""
Returns the vector offset for a given direction.
"""
if direct==direction.NORTH:
offset = vector3d(0,1,0)
elif direct==direction.SOUTH:
offset = vector3d(0,-1,0)
elif direct==direction.EAST:
offset = vector3d(1,0,0)
elif direct==direction.WEST:
offset = vector3d(-1,0,0)
elif direct==direction.UP:
offset = vector3d(0,0,1)
elif direct==direction.DOWN:
offset = vector3d(0,0,-1)
elif direct==direction.NORTHEAST:
offset = vector3d(1,1,0)
elif direct==direction.NORTHWEST:
offset = vector3d(-1,1,0)
elif direct==direction.SOUTHEAST:
offset = vector3d(1,-1,0)
elif direct==direction.SOUTHWEST:
offset = vector3d(-1,-1,0)
else:
debug.error("Invalid direction {}".format(direct))
return offset
def cardinal_directions(up_down_too=False):
temp_dirs = [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST]
if up_down_too:
temp_dirs.extend([direction.UP, direction.DOWN])
return temp_dirs
def cardinal_offsets(up_down_too=False):
return [direction.get_offset(d) for d in direction.cardinal_directions(up_down_too)]
def all_directions():
return [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST,
direction.NORTHEAST, direction.NORTHWEST, direction.SOUTHEAST, direction.SOUTHWEST]
def all_offsets():
return [direction.get_offset(d) for d in direction.all_directions()]
def all_neighbors(cell):
return [cell+x for x in direction.all_offsets()]
def cardinal_neighbors(cell):
return [cell+x for x in direction.cardinal_offsets()]

View File

@ -22,6 +22,11 @@ class grid_cell:
self.source=False
self.target=False
def get_cost(self):
# We can display the cost of the frontier
if self.min_cost > 0:
return self.min_cost
def get_type(self):
if self.blocked:
@ -36,8 +41,4 @@ class grid_cell:
if self.path:
return "P"
# We can display the cost of the frontier
if self.min_cost > 0:
return self.min_cost
return None

View File

@ -150,7 +150,7 @@ class grid_path:
return cost
def expand_dirs(self,up_down_too=True):
def expand_dirs(self):
"""
Expand from the end in each of the four cardinal directions plus up
or down but not expanding to blocked cells. Expands in all
@ -162,9 +162,7 @@ class grid_path:
"""
neighbors = []
for d in list(direction):
if not up_down_too and (d==direction.UP or d==direction.DOWN):
continue
for d in direction.cardinal_directions(True):
n = self.neighbor(d)
if n:
neighbors.append(n)
@ -172,20 +170,7 @@ class grid_path:
return neighbors
def neighbor(self, d):
if d==direction.EAST:
offset = vector3d(1,0,0)
elif d==direction.WEST:
offset = vector3d(-1,0,0)
elif d==direction.NORTH:
offset = vector3d(0,1,0)
elif d==direction.SOUTH:
offset = vector3d(0,-1,0)
elif d==direction.UP:
offset = vector3d(0,0,1)
elif d==direction.DOWN:
offset = vector3d(0,0,-1)
else:
debug.error("Invalid direction {}".format(d),-1)
offset = direction.get_offset(d)
newwave = [point + offset for point in self.pathlist[-1]]

View File

@ -6,31 +6,20 @@ import debug
from direction import direction
from vector3d import vector3d
def increment_set(curset, direct):
"""
Return the cells incremented in given direction
"""
if direct==direction.NORTH:
offset = vector3d(0,1,0)
elif direct==direction.SOUTH:
offset = vector3d(0,-1,0)
elif direct==direction.EAST:
offset = vector3d(1,0,0)
elif direct==direction.WEST:
offset = vector3d(-1,0,0)
elif direct==direction.UP:
offset = vector3d(0,0,1)
elif direct==direction.DOWN:
offset = vector3d(0,0,-1)
else:
debug.error("Invalid direction {}".format(dirct))
newset = set()
for c in curset:
newc = c+offset
newset.add(newc)
return newset
def increment_set(curset, direct):
"""
Return the cells incremented in given direction
"""
offset = direction.get_offset(direct)
newset = set()
for c in curset:
newc = c+offset
newset.add(newc)
return newset
def remove_border(curset, direct):
"""
@ -38,7 +27,7 @@ def remove_border(curset, direct):
"""
border = get_border(curset, direct)
curset.difference_update(border)
def get_upper_right(curset):
ur = None
@ -55,48 +44,48 @@ def get_lower_left(curset):
return ll
def get_border( curset, direct):
"""
Return the furthest cell(s) in a given direction.
"""
# find direction-most cell(s)
maxc = []
if direct==direction.NORTH:
for c in curset:
if len(maxc)==0 or c.y>maxc[0].y:
maxc = [c]
elif c.y==maxc[0].y:
maxc.append(c)
elif direct==direct.SOUTH:
for c in curset:
if len(maxc)==0 or c.y<maxc[0].y:
maxc = [c]
elif c.y==maxc[0].y:
maxc.append(c)
elif direct==direct.EAST:
for c in curset:
if len(maxc)==0 or c.x>maxc[0].x:
maxc = [c]
elif c.x==maxc[0].x:
maxc.append(c)
elif direct==direct.WEST:
for c in curset:
if len(maxc)==0 or c.x<maxc[0].x:
maxc = [c]
elif c.x==maxc[0].x:
maxc.append(c)
"""
Return the furthest cell(s) in a given direction.
"""
# find direction-most cell(s)
maxc = []
if direct==direction.NORTH:
for c in curset:
if len(maxc)==0 or c.y>maxc[0].y:
maxc = [c]
elif c.y==maxc[0].y:
maxc.append(c)
elif direct==direct.SOUTH:
for c in curset:
if len(maxc)==0 or c.y<maxc[0].y:
maxc = [c]
elif c.y==maxc[0].y:
maxc.append(c)
elif direct==direct.EAST:
for c in curset:
if len(maxc)==0 or c.x>maxc[0].x:
maxc = [c]
elif c.x==maxc[0].x:
maxc.append(c)
elif direct==direct.WEST:
for c in curset:
if len(maxc)==0 or c.x<maxc[0].x:
maxc = [c]
elif c.x==maxc[0].x:
maxc.append(c)
newset = set(maxc)
return newset
newset = set(maxc)
return newset
def expand_border(curset, direct):
"""
Expand the current set of sells in a given direction.
Only return the contiguous cells.
"""
border_set = get_border(curset, direct)
next_border_set = increment_set(border_set, direct)
return next_border_set
"""
Expand the current set of sells in a given direction.
Only return the contiguous cells.
"""
border_set = get_border(curset, direct)
next_border_set = increment_set(border_set, direct)
return next_border_set
def expand_borders(curset):
"""
@ -106,6 +95,47 @@ def expand_borders(curset):
south_set=expand_border(curset,direction.SOUTH)
east_set=expand_border(curset,direction.EAST)
west_set=expand_border(curset,direction.WEST)
return(north_set, east_set, south_set, west_set)
def inflate_cell(cell, distance):
"""
Expand the current cell in all directions and return the set.
"""
newset = set(cell)
if distance==0:
return(newset)
# recursively call this based on the distance
for offset in direction.all_offsets():
# FIXME: If distance is large this will be inefficient, but it is like 1 or 2
newset.update(inflate_cell(cell+offset,distance-1))
return newset
def inflate_set(curset, distance):
"""
Expand the set in all directions by the given number of grids.
"""
if distance<=0:
return curset
newset = curset.copy()
# Add all my neighbors
for c in curset:
newset.update(direction.all_neighbors(c))
# Recurse with less depth
return inflate_set(newset,distance-1)
def flatten_set(curset):
"""
Flatten until we have a set of vector3d objects.
"""
newset = set()
for c in curset:
if isinstance(c,vector3d):
newset.add(c)
else:
newset.update(flatten_set(c))
return newset

View File

@ -0,0 +1,657 @@
from direction import direction
from pin_layout import pin_layout
from vector3d import vector3d
from vector import vector
import grid_utils
from tech import drc
import debug
class pin_group:
"""
A class to represent a group of rectangular design pin.
It requires a router to define the track widths and blockages which
determine how pin shapes get mapped to tracks.
It is initially constructed with a single set of (touching) pins.
"""
def __init__(self, name, pin_set, router):
self.name = name
# Flag for when it is routed
self.routed = False
# Flag for when it is enclosed
self.enclosed = False
# Remove any redundant pins (i.e. contained in other pins)
irredundant_pin_set = self.remove_redundant_shapes(list(pin_set))
# This is a list because we can have a pin group of disconnected sets of pins
# and these are represented by separate lists
self.pins = [set(irredundant_pin_set)]
self.router = router
# These are the corresponding pin grids for each pin group.
self.grids = set()
# These are the secondary grids that could or could not be part of the pin
self.secondary_grids = set()
# The corresponding set of partially blocked grids for each pin group.
# These are blockages for other nets but unblocked for routing this group.
# These are also blockages if we used a simple enclosure to route to a rail.
self.blockages = set()
# This is a set of pin_layout shapes to cover the grids
self.enclosures = set()
def __str__(self):
""" override print function output """
total_string = "(pg {} ".format(self.name)
pin_string = "\n pins={}".format(self.pins)
total_string += pin_string
grids_string = "\n grids={}".format(self.grids)
total_string += grids_string
grids_string = "\n secondary={}".format(self.secondary_grids)
total_string += grids_string
if self.enclosed:
enlosure_string = "\n enclose={}".format(self.enclosures)
total_string += enclosure_string
total_string += ")"
return total_string
def __repr__(self):
""" override repr function output """
return str(self)
def size(self):
return len(self.grids)
def set_routed(self, value=True):
self.routed = value
def is_routed(self):
return self.routed
def pins_enclosed(self):
"""
Check if all of the pin shapes are enclosed.
Does not check if the DRC is correct, but just touching.
"""
for pin_list in self.pins:
pin_is_enclosed=False
for pin in pin_list:
if pin_is_enclosed:
break
for encosure in self.enclosures:
if pin.overlaps(enclosure):
pin_is_enclosed=True
break
else:
return False
return True
def remove_redundant_shapes(self, pin_list):
"""
Remove any pin layout that is contained within another.
Returns a new list without modifying pin_list.
"""
local_debug = False
if local_debug:
debug.info(0,"INITIAL: {}".format(pin_list))
# Make a copy of the list to start
new_pin_list = pin_list.copy()
remove_indices = set()
# This is n^2, but the number is small
for index1,pin1 in enumerate(pin_list):
# If we remove this pin, it can't contain other pins
if index1 in remove_indices:
continue
for index2,pin2 in enumerate(pin_list):
# Can't contain yourself, but compare the indices and not the pins
# so you can remove duplicate copies.
if index1==index2:
continue
# If we already removed it, can't remove it again...
if index2 in remove_indices:
continue
if pin1.contains(pin2):
if local_debug:
debug.info(0,"{0} contains {1}".format(pin1,pin2))
remove_indices.add(index2)
# Remove them in decreasing order to not invalidate the indices
for i in sorted(remove_indices, reverse=True):
del new_pin_list[i]
if local_debug:
debug.info(0,"FINAL : {}".format(new_pin_list))
return new_pin_list
# FIXME: This relies on some technology parameters from router which is not clean.
def compute_enclosures(self):
"""
Find the minimum rectangle enclosures of the given tracks.
"""
# Enumerate every possible enclosure
pin_list = []
for seed in self.grids:
(ll, ur) = self.enclose_pin_grids(seed, direction.NORTH, direction.EAST)
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure)
(ll, ur) = self.enclose_pin_grids(seed, direction.EAST, direction.NORTH)
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure)
# Now simplify the enclosure list
new_pin_list = self.remove_redundant_shapes(pin_list)
return new_pin_list
def compute_connector(self, pin, enclosure):
"""
Compute a shape to connect the pin to the enclosure shape.
This assumes the shape will be the dimension of the pin.
"""
if pin.xoverlaps(enclosure):
# Is it vertical overlap, extend pin shape to enclosure
plc = pin.lc()
prc = pin.rc()
elc = enclosure.lc()
erc = enclosure.rc()
ymin = min(plc.y,elc.y)
ymax = max(plc.y,elc.y)
ll = vector(plc.x, ymin)
ur = vector(prc.x, ymax)
p = pin_layout(pin.name, [ll, ur], pin.layer)
elif pin.yoverlaps(enclosure):
# Is it horizontal overlap, extend pin shape to enclosure
pbc = pin.bc()
puc = pin.uc()
ebc = enclosure.bc()
euc = enclosure.uc()
xmin = min(pbc.x,ebc.x)
xmax = max(pbc.x,ebc.x)
ll = vector(xmin, pbc.y)
ur = vector(xmax, puc.y)
p = pin_layout(pin.name, [ll, ur], pin.layer)
else:
# Neither, so we must do a corner-to corner
pc = pin.center()
ec = enclosure.center()
xmin = min(pc.x, ec.x)
xmax = max(pc.x, ec.x)
ymin = min(pc.y, ec.y)
ymax = max(pc.y, ec.y)
ll = vector(xmin, ymin)
ur = vector(xmax, ymax)
p = pin_layout(pin.name, [ll, ur], pin.layer)
return p
def find_above_connector(self, pin, enclosures):
"""
Find the enclosure that is to above the pin
and make a connector to it's upper edge.
"""
# Create the list of shapes that contain the pin edge
edge_list = []
for shape in enclosures:
if shape.xcontains(pin):
edge_list.append(shape)
# Sort them by their bottom edge
edge_list.sort(key=lambda x: x.by(), reverse=True)
# Find the bottom edge that is next to the pin's top edge
above_item = None
for item in edge_list:
if item.by()>=pin.uy():
above_item = item
else:
break
# There was nothing
if above_item==None:
return None
# If it already overlaps, no connector needed
if above_item.overlaps(pin):
return None
# Otherwise, make a connector to the item
p = self.compute_connector(pin, above_item)
return p
def find_below_connector(self, pin, enclosures):
"""
Find the enclosure that is below the pin
and make a connector to it's upper edge.
"""
# Create the list of shapes that contain the pin edge
edge_list = []
for shape in enclosures:
if shape.xcontains(pin):
edge_list.append(shape)
# Sort them by their upper edge
edge_list.sort(key=lambda x: x.uy())
# Find the upper edge that is next to the pin's bottom edge
bottom_item = None
for item in edge_list:
if item.uy()<=pin.by():
bottom_item = item
else:
break
# There was nothing to the left
if bottom_item==None:
return None
# If it already overlaps, no connector needed
if bottom_item.overlaps(pin):
return None
# Otherwise, make a connector to the item
p = self.compute_connector(pin, bottom_item)
return p
def find_left_connector(self, pin, enclosures):
"""
Find the enclosure that is to the left of the pin
and make a connector to it's right edge.
"""
# Create the list of shapes that contain the pin edge
edge_list = []
for shape in enclosures:
if shape.ycontains(pin):
edge_list.append(shape)
# Sort them by their right edge
edge_list.sort(key=lambda x: x.rx())
# Find the right edge that is to the pin's left edge
left_item = None
for item in edge_list:
if item.rx()<=pin.lx():
left_item = item
else:
break
# There was nothing to the left
if left_item==None:
return None
# If it already overlaps, no connector needed
if left_item.overlaps(pin):
return None
# Otherwise, make a connector to the item
p = self.compute_connector(pin, left_item)
return p
def find_right_connector(self, pin, enclosures):
"""
Find the enclosure that is to the right of the pin
and make a connector to it's left edge.
"""
# Create the list of shapes that contain the pin edge
edge_list = []
for shape in enclosures:
if shape.ycontains(pin):
edge_list.append(shape)
# Sort them by their right edge
edge_list.sort(key=lambda x: x.lx(), reverse=True)
# Find the left edge that is next to the pin's right edge
right_item = None
for item in edge_list:
if item.lx()>=pin.rx():
right_item = item
else:
break
# There was nothing to the right
if right_item==None:
return None
# If it already overlaps, no connector needed
if right_item.overlaps(pin):
return None
# Otherwise, make a connector to the item
p = self.compute_connector(pin, right_item)
return p
def find_smallest_connector(self, pin_list, shape_list):
"""
Compute all of the connectors between the overlapping pins and enclosure shape list..
Return the smallest.
"""
smallest = None
for pin in pin_list:
for enclosure in shape_list:
new_enclosure = self.compute_connector(pin, enclosure)
if smallest == None or new_enclosure.area()<smallest.area():
smallest = new_enclosure
return smallest
def find_smallest_overlapping(self, pin_list, shape_list):
"""
Find the smallest area shape in shape_list that overlaps with any
pin in pin_list by a min width.
"""
smallest_shape = None
for pin in pin_list:
overlap_shape = self.find_smallest_overlapping_pin(pin,shape_list)
if overlap_shape:
overlap_length = pin.overlap_length(overlap_shape)
if smallest_shape == None or overlap_shape.area()<smallest_shape.area():
smallest_shape = overlap_shape
return smallest_shape
def find_smallest_overlapping_pin(self, pin, shape_list):
"""
Find the smallest area shape in shape_list that overlaps with any
pin in pin_list by a min width.
"""
smallest_shape = None
zindex=self.router.get_zindex(pin.layer_num)
(min_width,min_space) = self.router.get_layer_width_space(zindex)
# Now compare it with every other shape to check how much they overlap
for other in shape_list:
overlap_length = pin.overlap_length(other)
if overlap_length > min_width:
if smallest_shape == None or other.area()<smallest_shape.area():
smallest_shape = other
return smallest_shape
def overlap_any_shape(self, pin_list, shape_list):
"""
Does the given pin overlap any of the shapes in the pin list.
"""
for pin in pin_list:
for other in shape_list:
if pin.overlaps(other):
return True
return False
def max_pin_layout(self, pin_list):
"""
Return the max area pin_layout
"""
biggest = pin_list[0]
for pin in pin_list:
if pin.area() > biggest.area():
biggest = pin
return pin
def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST):
"""
This encloses a single pin component with a rectangle
starting with the seed and expanding right until blocked
and then up until blocked.
dir1 and dir2 should be two orthogonal directions.
"""
offset1= direction.get_offset(dir1)
offset2= direction.get_offset(dir2)
# We may have started with an empty set
if not self.grids:
return None
# Start with the ll and make the widest row
row = [ll]
# Move in dir1 while we can
while True:
next_cell = row[-1] + offset1
# Can't move if not in the pin shape
if next_cell in self.grids and next_cell not in self.router.blocked_grids:
row.append(next_cell)
else:
break
# Move in dir2 while we can
while True:
next_row = [x+offset2 for x in row]
for cell in next_row:
# Can't move if any cell is not in the pin shape
if cell not in self.grids or cell in self.router.blocked_grids:
break
else:
row = next_row
# Skips the second break
continue
# Breaks from the nested break
break
# Add a shape from ll to ur
ur = row[-1]
return (ll,ur)
def enclose_pin(self):
"""
If there is one set of connected pin shapes,
this will find the smallest rectangle enclosure that overlaps with any pin.
If there is not, it simply returns all the enclosures.
"""
self.enclosed = True
# Compute the enclosure pin_layout list of the set of tracks
self.enclosures = self.compute_enclosures()
for pin_list in self.pins:
for pin in pin_list:
# If it is contained, it won't need a connector
if pin.contained_by_any(self.enclosures):
continue
left_connector = self.find_left_connector(pin, self.enclosures)
right_connector = self.find_right_connector(pin, self.enclosures)
above_connector = self.find_above_connector(pin, self.enclosures)
below_connector = self.find_below_connector(pin, self.enclosures)
for connector in [left_connector, right_connector, above_connector, below_connector]:
if connector:
self.enclosures.append(connector)
# Now, make sure each pin touches an enclosure. If not, add a connector.
# This could only happen when there was no enclosure in any cardinal direction from a pin
for pin_list in self.pins:
if not self.overlap_any_shape(pin_list, self.enclosures):
connector = self.find_smallest_connector(pin_list, self.enclosures)
debug.check(connector!=None, "Could not find a connector for {} with {}".format(pin_list, self.enclosures))
self.enclosures.append(connector)
debug.info(3,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name,
self.pins,
self.grids,
self.enclosures))
def combine_groups(self, pg1, pg2):
"""
Combine two pin groups into one.
"""
self.pins = [*pg1.pins, *pg2.pins] # Join the two lists of pins
self.grids = pg1.grids | pg2.grids # OR the set of grid locations
self.secondary_grids = pg1.secondary_grids | pg2.secondary_grids
def add_enclosure(self, cell):
"""
Add the enclosure shape to the given cell.
"""
for enclosure in self.enclosures:
debug.info(2,"Adding enclosure {0} {1}".format(self.name, enclosure))
cell.add_rect(layer=enclosure.layer,
offset=enclosure.ll(),
width=enclosure.width(),
height=enclosure.height())
def perimeter_grids(self):
"""
Return a list of the grids on the perimeter.
This assumes that we have a single contiguous shape.
"""
perimeter_set = set()
cardinal_offsets = direction.cardinal_offsets()
for g1 in self.grids:
neighbor_grids = [g1 + offset for offset in cardinal_offsets]
neighbor_count = sum([x in self.grids for x in neighbor_grids])
# If we aren't completely enclosed, we are on the perimeter
if neighbor_count < 4:
perimeter_set.add(g1)
return perimeter_set
def adjacent(self, other):
"""
Chck if the two pin groups have at least one adjacent pin grid.
"""
# We could optimize this to just check the boundaries
for g1 in self.perimeter_grids():
for g2 in other.perimeter_grids():
if g1.adjacent(g2):
return True
return False
def adjacent_grids(self, other, separation):
"""
Determine the sets of grids that are within a separation distance
of any grid in the other set.
"""
# We could optimize this to just check the boundaries
g1_grids = set()
g2_grids = set()
for g1 in self.grids:
for g2 in other.grids:
if g1.distance(g2) <= separation:
g1_grids.add(g1)
g2_grids.add(g2)
return g1_grids,g2_grids
def convert_pin(self):
"""
Convert the list of pin shapes into sets of routing grids.
The secondary set of grids are "optional" pin shapes that could be
should be either blocked or part of the pin.
"""
pin_set = set()
blockage_set = set()
for pin_list in self.pins:
for pin in pin_list:
debug.info(2," Converting {0}".format(pin))
# Determine which tracks the pin overlaps
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin)
pin_set.update(pin_in_tracks)
# Blockages will be a super-set of pins since it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin)
blockage_set.update(blockage_in_tracks)
# If we have a blockage, we must remove the grids
# Remember, this excludes the pin blockages already
shared_set = pin_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing pins {}".format(shared_set))
pin_set.difference_update(self.router.blocked_grids)
shared_set = blockage_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing blocks {}".format(shared_set))
blockage_set.difference_update(self.router.blocked_grids)
# At least one of the groups must have some valid tracks
if (len(pin_set)==0 and len(blockage_set)==0):
self.write_debug_gds("blocked_pin.gds")
debug.error("Unable to find unblocked pin on grid.")
# We need to route each of the components, so don't combine the groups
self.grids = pin_set | blockage_set
# Remember the secondary grids for removing adjacent pins in wide metal spacing
self.secondary_grids = blockage_set - pin_set
debug.info(2," pins {}".format(self.grids))
debug.info(2," secondary {}".format(self.secondary_grids))
def recurse_simple_overlap_enclosure(self, start_set, direct):
"""
Recursive function to return set of tracks that connects to
the actual supply rail wire in a given direction (or terminating
when any track is no longer in the supply rail.
"""
next_set = grid_utils.expand_border(start_set, direct)
supply_tracks = self.router.supply_rail_tracks[self.name]
supply_wire_tracks = self.router.supply_rail_wire_tracks[self.name]
supply_overlap = next_set & supply_tracks
wire_overlap = next_set & supply_wire_tracks
# If the rail overlap is the same, we are done, since we connected to the actual wire
if len(wire_overlap)==len(start_set):
new_set = start_set | wire_overlap
# If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
elif len(supply_overlap)==len(start_set):
recurse_set = self.recurse_simple_overlap_enclosure(supply_overlap, direct)
new_set = start_set | supply_overlap | recurse_set
else:
# If we got no next set, we are done, can't expand!
new_set = set()
return new_set
def create_simple_overlap_enclosure(self, start_set):
"""
This takes a set of tracks that overlap a supply rail and creates an enclosure
that is ensured to overlap the supply rail wire.
It then adds rectangle(s) for the enclosure.
"""
additional_set = set()
# Check the layer of any element in the pin to determine which direction to route it
e = next(iter(start_set))
new_set = start_set.copy()
if e.z==0:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.NORTH)
if not new_set:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.SOUTH)
else:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.EAST)
if not new_set:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.WEST)
# Expand the pin grid set to include some extra grids that connect the supply rail
self.grids.update(new_set)
# Add the inflated set so we don't get wide metal spacing issues (if it exists)
self.blockages.update(grid_utils.inflate_set(new_set,self.router.supply_rail_space_width))
# Add the polygon enclosures and set this pin group as routed
self.set_routed()
self.enclosures = self.compute_enclosures()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
from tech import drc,layer
from contact import contact
from pin_group import pin_group
import debug
class router_tech:
"""
This is a class to hold the router tech constants.
"""
def __init__(self, layers):
"""
Allows us to change the layers that we are routing on. First layer
is always horizontal, middle is via, and last is always
vertical.
"""
self.layers = layers
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
# This is the minimum routed track spacing
via_connect = contact(self.layers, (1, 1))
self.max_via_size = max(via_connect.width,via_connect.height)
self.vert_layer_minwidth = drc("minwidth_{0}".format(self.vert_layer_name))
self.vert_layer_spacing = drc(str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name))
self.vert_layer_number = layer[self.vert_layer_name]
self.horiz_layer_minwidth = drc("minwidth_{0}".format(self.horiz_layer_name))
self.horiz_layer_spacing = drc(str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name))
self.horiz_layer_number = layer[self.horiz_layer_name]
self.horiz_track_width = self.max_via_size + self.horiz_layer_spacing
self.vert_track_width = self.max_via_size + self.vert_layer_spacing
# We'll keep horizontal and vertical tracks the same for simplicity.
self.track_width = max(self.horiz_track_width,self.vert_track_width)
debug.info(1,"Track width: "+str(self.track_width))
self.track_widths = [self.track_width] * 2
self.track_factor = [1/self.track_width] * 2
debug.info(1,"Track factor: {0}".format(self.track_factor))
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_width - self.horiz_layer_spacing, 1, self.track_width - self.vert_layer_spacing]
def get_zindex(self,layer_num):
if layer_num==self.horiz_layer_number:
return 0
else:
return 1
def get_layer(self, zindex):
if zindex==1:
return self.vert_layer_name
elif zindex==0:
return self.horiz_layer_name
else:
debug.error("Invalid zindex {}".format(zindex),-1)
def get_layer_width_space(self, zindex, width=0, length=0):
"""
Return the width and spacing of a given layer
and wire of a given width and length.
"""
if zindex==1:
layer_name = self.vert_layer_name
elif zindex==0:
layer_name = self.horiz_layer_name
else:
debug.error("Invalid zindex for track", -1)
min_width = drc("minwidth_{0}".format(layer_name), width, length)
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length)
return (min_width,min_spacing)

View File

@ -1,9 +1,10 @@
import gdsMill
import tech
from contact import contact
import math
import debug
from globals import OPTS
from contact import contact
from pin_group import pin_group
from pin_layout import pin_layout
from vector3d import vector3d
from router import router
@ -40,6 +41,7 @@ class supply_router(router):
# Power rail width in grid units.
self.rail_track_width = 2
def create_routing_grid(self):
"""
@ -68,9 +70,12 @@ class supply_router(router):
# but this is simplest for now.
self.create_routing_grid()
# Compute the grid dimensions
self.compute_supply_rail_dimensions()
# Get the pin shapes
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
#self.write_debug_gds("pin_enclosures.gds",stop_program=False)
#self.write_debug_gds("pin_enclosures.gds",stop_program=True)
# Add the supply rails in a mesh network and connect H/V with vias
# Block everything
@ -83,100 +88,51 @@ class supply_router(router):
# Determine the rail locations
self.route_supply_rails(self.vdd_name,1)
#self.write_debug_gds("debug_rails.gds",stop_program=True)
remaining_vdd_pin_indices = self.route_simple_overlaps(vdd_name)
remaining_gnd_pin_indices = self.route_simple_overlaps(gnd_name)
#self.write_debug_gds("debug_simple_route.gds",stop_program=True)
self.route_simple_overlaps(vdd_name)
self.route_simple_overlaps(gnd_name)
#self.write_debug_gds("debug_simple_route.gds",stop_program=False)
# Route the supply pins to the supply rails
# Route vdd first since we want it to be shorter
self.route_pins_to_rails(vdd_name, remaining_vdd_pin_indices)
self.route_pins_to_rails(gnd_name, remaining_gnd_pin_indices)
self.route_pins_to_rails(vdd_name)
self.route_pins_to_rails(gnd_name)
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
#self.write_debug_gds("final.gds")
#self.write_debug_gds("final.gds",False)
return True
def route_simple_overlaps(self, pin_name):
"""
This checks for simple cases where a pin component already overlaps a supply rail.
It will add an enclosure to ensure the overlap in wide DRC rule cases.
"""
num_components = self.num_pin_components(pin_name)
remaining_pins = []
debug.info(1,"Routing simple overlap pins for {0}".format(pin_name))
# These are the wire tracks
wire_tracks = self.supply_rail_wire_tracks[pin_name]
# These are the wire and space tracks
supply_tracks = self.supply_rail_tracks[pin_name]
for index in range(num_components):
pin_in_tracks = self.pin_grids[pin_name][index]
common_set = supply_tracks & pin_in_tracks
if len(common_set)==0:
# if no overlap, add it to the complex route pins
remaining_pins.append(index)
else:
self.create_simple_overlap_enclosure(pin_name, common_set)
return remaining_pins
def recurse_simple_overlap_enclosure(self, pin_name, start_set, direct):
"""
Recursive function to return set of tracks that connects to
the actual supply rail wire in a given direction (or terminating
when any track is no longer in the supply rail.
"""
next_set = grid_utils.expand_border(start_set, direct)
supply_tracks = self.supply_rail_tracks[pin_name]
supply_wire_tracks = self.supply_rail_wire_tracks[pin_name]
supply_overlap = next_set & supply_tracks
wire_overlap = next_set & supply_wire_tracks
# If the rail overlap is the same, we are done, since we connected to the actual wire
if len(wire_overlap)==len(start_set):
new_set = start_set | wire_overlap
# If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
elif len(supply_overlap)==len(start_set):
recurse_set = self.recurse_simple_overlap_enclosure(pin_name, supply_overlap, direct)
new_set = start_set | supply_overlap | recurse_set
else:
# If we got no next set, we are done, can't expand!
new_set = set()
for pg in self.pin_groups[pin_name]:
if pg.is_routed():
continue
return new_set
# First, check if we just overlap, if so, we are done.
overlap_grids = wire_tracks & pg.grids
if len(overlap_grids)>0:
pg.set_routed()
continue
# Else, if we overlap some of the space track, we can patch it with an enclosure
common_set = supply_tracks & pg.grids
if len(common_set)>0:
pg.create_simple_overlap_enclosure(common_set)
pg.add_enclosure(self.cell)
def create_simple_overlap_enclosure(self, pin_name, start_set):
"""
This takes a set of tracks that overlap a supply rail and creates an enclosure
that is ensured to overlap the supply rail wire.
It then adds rectangle(s) for the enclosure.
"""
additional_set = set()
# Check the layer of any element in the pin to determine which direction to route it
e = next(iter(start_set))
new_set = start_set.copy()
if e.z==0:
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.NORTH)
if not new_set:
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.SOUTH)
else:
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.EAST)
if not new_set:
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST)
enclosure_list = self.compute_enclosures(new_set)
for pin in enclosure_list:
debug.info(2,"Adding simple overlap enclosure {0} {1}".format(pin_name, pin))
self.cell.add_rect(layer=pin.layer,
offset=pin.ll(),
width=pin.width(),
height=pin.height())
@ -228,9 +184,8 @@ class supply_router(router):
# the overlap area for placement of a via
overlap = new_r1 & new_r2
if len(overlap) >= self.supply_rail_wire_width**2:
debug.info(2,"Via overlap {0} {1} {2}".format(len(overlap),self.supply_rail_wire_width**2,overlap))
connections.add(i1)
connections.add(i2)
debug.info(3,"Via overlap {0} {1} {2}".format(len(overlap),self.supply_rail_wire_width**2,overlap))
connections.update([i1,i2])
via_areas.append(overlap)
# Go through and add the vias at the center of the intersection
@ -241,11 +196,12 @@ class supply_router(router):
self.add_via(center,self.rail_track_width)
# Determien which indices were not connected to anything above
all_indices = set([x for x in range(len(self.supply_rails[name]))])
missing_indices = all_indices ^ connections
missing_indices = set([x for x in range(len(self.supply_rails[name]))])
missing_indices.difference_update(connections)
# Go through and remove those disconnected indices
# (No via was added, so that doesn't need to be removed)
for rail_index in missing_indices:
for rail_index in sorted(missing_indices, reverse=True):
ll = grid_utils.get_lower_left(all_rails[rail_index])
ur = grid_utils.get_upper_right(all_rails[rail_index])
debug.info(1,"Removing disconnected supply rail {0} .. {1}".format(ll,ur))
@ -331,11 +287,12 @@ class supply_router(router):
# While we can keep expanding east in this horizontal track
while wave and wave[0].x < self.max_xoffset:
added_rail = self.find_supply_rail(name, wave, direction.EAST)
if added_rail:
wave = added_rail.neighbor(direction.EAST)
if not added_rail:
# Just seed with the next one
wave = [x+vector3d(1,0,0) for x in wave]
else:
wave = None
# Seed with the neighbor of the end of the last rail
wave = added_rail.neighbor(direction.EAST)
# Vertical supply rails
max_offset = self.rg.ur.x
@ -345,10 +302,12 @@ class supply_router(router):
# While we can keep expanding north in this vertical track
while wave and wave[0].y < self.max_yoffset:
added_rail = self.find_supply_rail(name, wave, direction.NORTH)
if added_rail:
wave = added_rail.neighbor(direction.NORTH)
if not added_rail:
# Just seed with the next one
wave = [x+vector3d(0,1,0) for x in wave]
else:
wave = None
# Seed with the neighbor of the end of the last rail
wave = added_rail.neighbor(direction.NORTH)
def find_supply_rail(self, name, seed_wave, direct):
"""
@ -356,15 +315,18 @@ class supply_router(router):
to contain a via, and, if so, add it.
"""
start_wave = self.find_supply_rail_start(name, seed_wave, direct)
# This means there were no more unblocked grids in the row/col
if not start_wave:
return None
wave_path = self.probe_supply_rail(name, start_wave, direct)
if self.approve_supply_rail(name, wave_path):
return wave_path
else:
return None
self.approve_supply_rail(name, wave_path)
# Return the rail whether we approved it or not,
# as it will be used to find the next start location
return wave_path
def find_supply_rail_start(self, name, seed_wave, direct):
"""
@ -432,9 +394,6 @@ class supply_router(router):
Must be done with lower left at 0,0
"""
# Compute the grid dimensions
self.compute_supply_rail_dimensions()
# Compute the grid locations of the supply rails
self.compute_supply_rails(name, supply_number)
@ -460,23 +419,27 @@ class supply_router(router):
self.supply_rail_wire_tracks[pin_name] = wire_set
def route_pins_to_rails(self, pin_name, remaining_component_indices):
def route_pins_to_rails(self, pin_name):
"""
This will route each of the remaining pin components to the supply rails.
After it is done, the cells are added to the pin blockage list.
"""
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
debug.info(1,"Pin {0} has {1} remaining components to route.".format(pin_name,
len(remaining_component_indices)))
remaining_components))
recent_paths = []
# For every component
for index in remaining_component_indices:
for index,pg in enumerate(self.pin_groups[pin_name]):
if pg.is_routed():
continue
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
# Clear everything in the routing grid.
self.rg.reinit()
# This is inefficient since it is non-incremental, but it was
# easier to debug.
self.prepare_blockages(pin_name)
# Add the single component of the pin as the source
@ -487,16 +450,9 @@ class supply_router(router):
# Don't add the other pins, but we could?
self.add_supply_rail_target(pin_name)
# Add the previous paths as targets too
#self.add_path_target(recent_paths)
#print(self.rg.target)
# Actually run the A* router
if not self.run_router(detour_scale=5):
self.write_debug_gds()
recent_paths.append(self.paths[-1])
def add_supply_rail_target(self, pin_name):

View File

@ -163,3 +163,21 @@ class vector3d():
""" Min of both values """
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
def distance(self, other):
""" Return the planar distance between two values """
return abs(self.x-other.x)+abs(self.y-other.y)
def adjacent(self, other):
""" Is the one grid adjacent in any planar direction to the other """
if self == other + vector3d(1,0,0):
return True
elif self == other + vector3d(-1,0,0):
return True
elif self == other + vector3d(0,1,0):
return True
elif self == other + vector3d(0,-1,0):
return True
else:
return False

View File

@ -116,7 +116,7 @@ def check_print_output(file_name):
return(count)
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -39,7 +39,7 @@ def setup_files():
return (gds_dir, gds_files)
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -59,7 +59,7 @@ def setup_files():
return (gds_dir, sp_dir, allnames)
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -43,7 +43,7 @@ class contact_test(openram_test):
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -84,7 +84,7 @@ class path_test(openram_test):
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -25,7 +25,7 @@ class ptx_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -25,7 +25,7 @@ class ptx_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -27,7 +27,7 @@ class ptx_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -27,7 +27,7 @@ class ptx_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -27,7 +27,7 @@ class ptx_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -27,7 +27,7 @@ class ptx_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -121,7 +121,7 @@ class wire_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -94,7 +94,7 @@ class pbitcell_test(openram_test):
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -25,7 +25,7 @@ class pinv_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -24,7 +24,7 @@ class pinv_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -23,7 +23,7 @@ class pinv_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -25,7 +25,7 @@ class pinv_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -23,7 +23,7 @@ class pinvbuf_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -27,7 +27,7 @@ class pnand2_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -27,7 +27,7 @@ class pnand3_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -26,7 +26,7 @@ class pnor2_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -39,7 +39,7 @@ class precharge_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -37,7 +37,7 @@ class replica_pbitcell_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -41,7 +41,7 @@ class single_level_column_mux_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -29,7 +29,7 @@ class bitcell_1rw_1r_array_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -25,7 +25,7 @@ class array_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -44,7 +44,7 @@ class pbitcell_array_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -69,7 +69,7 @@ class hierarchical_decoder_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -35,7 +35,7 @@ class hierarchical_predecode2x4_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -35,7 +35,7 @@ class hierarchical_predecode3x8_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -54,7 +54,7 @@ class single_level_column_mux_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -39,7 +39,7 @@ class precharge_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -37,7 +37,7 @@ class wordline_driver_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -42,7 +42,7 @@ class sense_amp_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -42,7 +42,7 @@ class write_driver_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -31,7 +31,7 @@ class dff_array_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -31,7 +31,7 @@ class dff_buf_array_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -23,7 +23,7 @@ class dff_buf_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -31,7 +31,7 @@ class dff_inv_array_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -23,7 +23,7 @@ class dff_inv_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -27,7 +27,7 @@ class tri_gate_array_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -23,7 +23,7 @@ class delay_chain_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -70,7 +70,7 @@ class replica_bitline_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -53,7 +53,7 @@ class control_logic_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -40,7 +40,7 @@ class bank_select_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -49,7 +49,7 @@ class multi_bank_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -54,7 +54,7 @@ class multi_bank_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -137,7 +137,7 @@ class psingle_bank_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -48,7 +48,7 @@ class single_bank_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -128,7 +128,7 @@ class sram_1bank_test(openram_test):
"""
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 20_sram_1bank_2mux_test")
#@unittest.skip("SKIPPING 20_sram_1bank_2mux_test")
class sram_1bank_2mux_test(openram_test):
def runTest(self):
@ -29,7 +29,7 @@ class sram_1bank_2mux_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 20_sram_1bank_2mux_test")
#@unittest.skip("SKIPPING 20_sram_1bank_4mux_test")
class sram_1bank_4mux_test(openram_test):
def runTest(self):
@ -29,7 +29,7 @@ class sram_1bank_4mux_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 20_sram_1bank_8mux_test")
#@unittest.skip("SKIPPING 20_sram_1bank_8mux_test")
class sram_1bank_8mux_test(openram_test):
def runTest(self):
@ -29,7 +29,7 @@ class sram_1bank_8mux_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -11,7 +11,8 @@ import globals
from globals import OPTS
import debug
class sram_1bank_test(openram_test):
#@unittest.skip("SKIPPING 20_sram_1bank_nomux_test")
class sram_1bank_nomux_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
@ -28,7 +29,7 @@ class sram_1bank_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -48,7 +48,7 @@ class sram_2bank_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -47,7 +47,7 @@ class sram_4bank_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -81,7 +81,7 @@ class timing_sram_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -52,7 +52,7 @@ class timing_setup_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -81,7 +81,7 @@ class timing_sram_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -53,7 +53,7 @@ class timing_setup_test(openram_test):
reload(characterizer)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -49,7 +49,7 @@ class psram_1bank_2mux_func_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test")
#@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test")
class psram_1bank_4mux_func_test(openram_test):
def runTest(self):
@ -49,7 +49,7 @@ class psram_1bank_4mux_func_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -37,6 +37,7 @@ class psram_1bank_8mux_func_test(openram_test):
c.words_per_row,
c.num_banks))
s = sram(c, name="sram")
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
@ -48,7 +49,7 @@ class psram_1bank_8mux_func_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -49,7 +49,7 @@ class psram_1bank_nomux_func_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -47,7 +47,7 @@ class sram_1bank_2mux_func_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 22_sram_1bank_4mux_func_test")
#@unittest.skip("SKIPPING 22_sram_1bank_4mux_func_test")
class sram_1bank_4mux_func_test(openram_test):
def runTest(self):
@ -47,7 +47,7 @@ class sram_1bank_4mux_func_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 22_sram_1bank_8mux_func_test")
#@unittest.skip("SKIPPING 22_sram_1bank_8mux_func_test")
class sram_1bank_8mux_func_test(openram_test):
def runTest(self):
@ -38,6 +38,7 @@ class sram_1bank_8mux_func_test(openram_test):
c.words_per_row,
c.num_banks))
s = sram(c, name="sram")
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
@ -49,7 +50,7 @@ class sram_1bank_8mux_func_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -39,7 +39,7 @@ class sram_1bank_nomux_func_test(openram_test):
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run()
@ -47,7 +47,7 @@ class sram_1bank_nomux_func_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -44,7 +44,7 @@ class lib_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -55,7 +55,7 @@ class lib_test(openram_test):
reload(characterizer)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -54,7 +54,7 @@ class lib_test(openram_test):
reload(characterizer)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -42,7 +42,7 @@ class lef_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -38,7 +38,7 @@ class verilog_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -306,7 +306,7 @@ class sram_func_test(openram_test):
sti_file.file.close()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -73,7 +73,7 @@ class worst_case_timing_sram_test(openram_test):
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -83,7 +83,7 @@ class openram_test(openram_test):
globals.end_openram()
# instantiate a copy of the class to actually run the test
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]

View File

@ -172,9 +172,9 @@ layerDefinitions(
( align drawing )
( hardFence drawing )
( softFence drawing )
( text drawing )
( text drawing1 )
( text drawing2 )
( comment drawing )
( comment drawing1 )
( comment drawing2 )
( border drawing )
( device drawing )
( device label )
@ -379,9 +379,9 @@ layerDefinitions(
( align drawing align t t t t nil )
( hardFence drawing hardFence t t t t nil )
( softFence drawing softFence t t t t nil )
( text drawing text t t t t t )
( text drawing1 text1 t t t t nil )
( text drawing2 text2 t t t t nil )
( comment drawing comment t t t t t )
( comment drawing1 comment1 t t t t nil )
( comment drawing2 comment2 t t t t nil )
( border drawing border t t t t nil )
( device drawing device t t t t nil )
( device label deviceLbl t t t t nil )

View File

@ -27,4 +27,4 @@ via8 drawing 26 0
metal9 drawing 27 0
via9 drawing 28 0
metal10 drawing 29 0
text drawing 239 0
comment drawing 239 0