diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 74b02f5f..cbc1d268 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -167,7 +167,7 @@ class instance(geometry): debug.info(4, "creating instance: " + self.name) - def get_blockages(self, layer, top=False): + def get_blockages(self, lpp, top=False): """ Retrieve blockages of all modules in this instance. Apply the transform of the instance placement to give absolute blockages.""" angle = math.radians(float(self.rotate)) @@ -191,11 +191,11 @@ class instance(geometry): if self.mod.is_library_cell: # Writes library cell blockages as shapes instead of a large metal blockage blockages = [] - blockages = self.mod.gds.getBlockages(layer) + blockages = self.mod.gds.getBlockages(lpp) for b in blockages: new_blockages.append(self.transform_coords(b,self.offset, mirr, angle)) else: - blockages = self.mod.get_blockages(layer) + blockages = self.mod.get_blockages(lpp) for b in blockages: new_blockages.append(self.transform_coords(b,self.offset, mirr, angle)) return new_blockages @@ -266,11 +266,12 @@ class instance(geometry): class path(geometry): """Represents a Path""" - def __init__(self, layerNumber, coordinates, path_width): + def __init__(self, lpp, coordinates, path_width): """Initializes a path for the specified layer""" geometry.__init__(self) self.name = "path" - self.layerNumber = layerNumber + self.layerNumber = lpp[0] + self.layerPurpose = lpp[1] self.coordinates = map(lambda x: [x[0], x[1]], coordinates) self.coordinates = vector(self.coordinates).snap_to_grid() self.path_width = path_width @@ -283,7 +284,7 @@ class path(geometry): """Writes the path to GDS""" debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates) new_layout.addPath(layerNumber=self.layerNumber, - purposeNumber=0, + purposeNumber=self.layerPurpose, coordinates=self.coordinates, width=self.path_width) @@ -303,12 +304,13 @@ class path(geometry): class label(geometry): """Represents a text label""" - def __init__(self, text, layerNumber, offset, zoom=-1): + def __init__(self, text, lpp, offset, zoom=-1): """Initializes a text label for specified layer""" geometry.__init__(self) self.name = "label" self.text = text - self.layerNumber = layerNumber + self.layerNumber = lpp[0] + self.layerPurpose = lpp[1] self.offset = vector(offset).snap_to_grid() if zoom<0: @@ -325,7 +327,7 @@ class label(geometry): debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text) new_layout.addText(text=self.text, layerNumber=self.layerNumber, - purposeNumber=0, + purposeNumber=self.layerPurpose, offsetInMicrons=self.offset, magnification=self.zoom, rotate=None) @@ -346,11 +348,12 @@ class label(geometry): class rectangle(geometry): """Represents a rectangular shape""" - def __init__(self, layerNumber, offset, width, height): + def __init__(self, lpp, offset, width, height): """Initializes a rectangular shape for specified layer""" geometry.__init__(self) self.name = "rect" - self.layerNumber = layerNumber + self.layerNumber = lpp[0] + self.layerPurpose = lpp[1] self.offset = vector(offset).snap_to_grid() self.size = vector(width, height).snap_to_grid() self.width = round_to_grid(self.size.x) @@ -374,7 +377,7 @@ class rectangle(geometry): 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, + purposeNumber=self.layerPurpose, offsetInMicrons=self.offset, width=self.width, height=self.height, diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 2fea5c61..000e16ee 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -150,9 +150,9 @@ class layout(): if not height: height=drc["minwidth_{}".format(layer)] # negative layers indicate "unused" layers in a given technology - layer_num = techlayer[layer] - if layer_num >= 0: - self.objs.append(geometry.rectangle(layer_num, offset, width, height)) + lpp = techlayer[layer] + if lpp[0] >= 0: + self.objs.append(geometry.rectangle(lpp, offset, width, height)) return self.objs[-1] return None @@ -165,10 +165,10 @@ class layout(): if not height: height=drc["minwidth_{}".format(layer)] # negative layers indicate "unused" layers in a given technology - layer_num = techlayer[layer] + lpp = techlayer[layer] corrected_offset = offset - vector(0.5*width,0.5*height) - if layer_num >= 0: - self.objs.append(geometry.rectangle(layer_num, corrected_offset, width, height)) + if lpp[0] >= 0: + self.objs.append(geometry.rectangle(lpp, corrected_offset, width, height)) return self.objs[-1] return None @@ -334,9 +334,9 @@ class layout(): """Adds a text label on the given layer,offset, and zoom level""" # negative layers indicate "unused" layers in a given technology debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset)) - layer_num = techlayer[layer] - if layer_num >= 0: - self.objs.append(geometry.label(text, layer_num, offset, zoom)) + lpp = techlayer[layer] + if lpp[0] >= 0: + self.objs.append(geometry.label(text, lpp, offset, zoom)) return self.objs[-1] return None @@ -347,9 +347,9 @@ class layout(): import wire_path # NOTE: (UNTESTED) add_path(...) is currently not used # negative layers indicate "unused" layers in a given technology - #layer_num = techlayer[layer] - #if layer_num >= 0: - # self.objs.append(geometry.path(layer_num, coordinates, width)) + #lpp = techlayer[layer] + #if lpp[0] >= 0: + # self.objs.append(geometry.path(lpp, coordinates, width)) wire_path.wire_path(obj=self, layer=layer, @@ -539,21 +539,21 @@ class layout(): Do not write the pins since they aren't obstructions. """ if type(layer)==str: - layer_num = techlayer[layer] + lpp = techlayer[layer] else: - layer_num = layer + lpp = layer blockages = [] for i in self.objs: - blockages += i.get_blockages(layer_num) + blockages += i.get_blockages(lpp) for i in self.insts: - blockages += i.get_blockages(layer_num) + blockages += i.get_blockages(lpp) # Must add pin blockages to non-top cells if not top_level: - blockages += self.get_pin_blockages(layer_num) + blockages += self.get_pin_blockages(lpp) return blockages - def get_pin_blockages(self, layer_num): + def get_pin_blockages(self, lpp): """ Return the pin shapes as blockages for non-top-level blocks. """ # FIXME: We don't have a body contact in ptx, so just ignore it for now import copy @@ -565,33 +565,57 @@ class layout(): for pin_name in pin_names: pin_list = self.get_pins(pin_name) for pin in pin_list: - if pin.layer_num==layer_num: + if pin.same_lpp(pin.lpp, lpp): blockages += [pin.rect] return blockages def create_horizontal_pin_bus(self, layer, pitch, offset, names, length): """ Create a horizontal bus of pins. """ - return self.create_bus(layer,pitch,offset,names,length,vertical=False,make_pins=True) + return self.create_bus(layer, + pitch, + offset, + names, + length, + vertical=False, + make_pins=True) def create_vertical_pin_bus(self, layer, pitch, offset, names, length): """ Create a horizontal bus of pins. """ - return self.create_bus(layer,pitch,offset,names,length,vertical=True,make_pins=True) + return self.create_bus(layer, + pitch, + offset, + names, + length, + vertical=True, + make_pins=True) def create_vertical_bus(self, layer, pitch, offset, names, length): """ Create a horizontal bus. """ - return self.create_bus(layer,pitch,offset,names,length,vertical=True,make_pins=False) + return self.create_bus(layer, + pitch, + offset, + names, + length, + vertical=True, + make_pins=False) def create_horizontal_bus(self, layer, pitch, offset, names, length): """ Create a horizontal bus. """ - return self.create_bus(layer,pitch,offset,names,length,vertical=False,make_pins=False) + return self.create_bus(layer, + pitch, + offset, + names, + length, + vertical=False, + make_pins=False) def create_bus(self, layer, pitch, offset, names, length, vertical, make_pins): - """ + """ Create a horizontal or vertical bus. It can be either just rectangles, or actual layout pins. It returns an map of line center line positions indexed by name. - The other coordinate is a 0 since the bus provides a range. + The other coordinate is a 0 since the bus provides a range. TODO: combine with channel router. """ diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 2d389119..f5d25263 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -11,42 +11,55 @@ from vector import vector from tech import layer import math + class pin_layout: """ A class to represent a rectangular design pin. It is limited to a single shape. """ - def __init__(self, name, rect, layer_name_num): + def __init__(self, name, rect, layer_name_pp): self.name = name # repack the rect as a vector, just in case - if type(rect[0])==vector: + if type(rect[0]) == vector: self.rect = rect else: - self.rect = [vector(rect[0]),vector(rect[1])] + 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.") + 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)] + # if it's a string, use the name + if type(layer_name_pp) == str: + self.layer = layer_name_pp + # else it is required to be a lpp else: - self.layer=layer_name_num - self.layer_num = layer[self.layer] + for (layer_name, lpp) in layer.items(): + if self.same_lpp(layer_name_pp, lpp): + self.layer = layer_name + break + else: + debug.error("Couldn't find layer {}".format(layer_name_pp), -1) + + self.lpp = layer[self.layer] def __str__(self): """ override print function output """ - return "({} layer={} ll={} ur={})".format(self.name,self.layer,self.rect[0],self.rect[1]) + return "({} layer={} ll={} ur={})".format(self.name, + self.layer, + self.rect[0], + self.rect[1]) def __repr__(self): - """ - override repr function output (don't include + """ + override repr function output (don't include name since pin shapes could have same shape but diff name e.g. blockage vs A) """ - return "(layer={} ll={} ur={})".format(self.layer,self.rect[0],self.rect[1]) + return "(layer={} ll={} ur={})".format(self.layer, + self.rect[0], + self.rect[1]) def __hash__(self): """ Implement the hash function for sets etc. """ @@ -65,15 +78,15 @@ class pin_layout: def __eq__(self, other): """ Check if these are the same pins for duplicate checks """ if isinstance(other, self.__class__): - return (self.layer==other.layer and self.rect == other.rect) + return (self.lpp == other.lpp and self.rect == other.rect) else: - return False + return False def bbox(self, pin_list): """ Given a list of layout pins, create a bounding box layout. """ - (ll, ur) = self.rect + (ll, ur) = self.rect min_x = ll.x max_x = ur.x min_y = ll.y @@ -85,17 +98,17 @@ class pin_layout: min_y = min(min_y, pin.ll().y) max_y = max(max_y, pin.ur().y) - self.rect = [vector(min_x,min_y),vector(max_x,max_y)] + self.rect = [vector(min_x, min_y), vector(max_x, max_y)] def inflate(self, spacing=None): - """ - Inflate the rectangle by the spacing (or other rule) - and return the new rectangle. + """ + Inflate the rectangle by the spacing (or other rule) + and return the new rectangle. """ if not spacing: spacing = 0.5*drc("{0}_to_{0}".format(self.layer)) - (ll,ur) = self.rect + (ll, ur) = self.rect spacing = vector(spacing, spacing) newll = ll - spacing newur = ur + spacing @@ -104,20 +117,20 @@ class pin_layout: def intersection(self, other): """ Check if a shape overlaps with a rectangle """ - (ll,ur) = self.rect - (oll,our) = other.rect + (ll, ur) = self.rect + (oll, our) = other.rect min_x = max(ll.x, oll.x) max_x = min(ll.x, oll.x) min_y = max(ll.y, oll.y) max_y = min(ll.y, oll.y) - return [vector(min_x,min_y),vector(max_x,max_y)] + return [vector(min_x, min_y), vector(max_x, max_y)] def xoverlaps(self, other): """ Check if shape has x overlap """ - (ll,ur) = self.rect - (oll,our) = other.rect + (ll, ur) = self.rect + (oll, our) = other.rect x_overlaps = False # check if self is within other x range if (ll.x >= oll.x and ll.x <= our.x) or (ur.x >= oll.x and ur.x <= our.x): @@ -130,8 +143,8 @@ class pin_layout: def yoverlaps(self, other): """ Check if shape has x overlap """ - (ll,ur) = self.rect - (oll,our) = other.rect + (ll, ur) = self.rect + (oll, our) = other.rect y_overlaps = False # check if self is within other y range @@ -145,15 +158,15 @@ class pin_layout: def xcontains(self, other): """ Check if shape contains the x overlap """ - (ll,ur) = self.rect - (oll,our) = other.rect + (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 + (ll, ur) = self.rect + (oll, our) = other.rect return (oll.y >= ll.y and our.y <= ur.y) @@ -164,7 +177,7 @@ class pin_layout: return True # Can only overlap on the same layer - if self.layer != other.layer: + if not self.same_lpp(self.lpp, other.lpp): return False if not self.xcontains(other): @@ -182,11 +195,10 @@ class pin_layout: return True return False - def overlaps(self, other): """ Check if a shape overlaps with a rectangle """ # Can only overlap on the same layer - if self.layer != other.layer: + if not self.same_lpp(self.lpp, other.lpp): return False x_overlaps = self.xoverlaps(other) @@ -208,40 +220,45 @@ class pin_layout: def normalize(self): """ Re-find the LL and UR points after a transform """ - (first,second)=self.rect - ll = vector(min(first[0],second[0]),min(first[1],second[1])) - ur = vector(max(first[0],second[0]),max(first[1],second[1])) - self.rect=[ll,ur] + (first, second) = self.rect + ll = vector(min(first[0], second[0]), min(first[1], second[1])) + ur = vector(max(first[0], second[0]), max(first[1], second[1])) + self.rect=[ll, ur] - def transform(self,offset,mirror,rotate): - """ 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. """ - (ll,ur) = self.rect - 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) + def transform(self, offset, mirror, rotate): + """ + 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. + """ + (ll, ur) = self.rect + 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.rect=[offset+ll,offset+ur] + self.rect = [offset + ll, offset + ur] self.normalize() def center(self): - return vector(0.5*(self.rect[0].x+self.rect[1].x),0.5*(self.rect[0].y+self.rect[1].y)) + return vector(0.5*(self.rect[0].x+self.rect[1].x), + 0.5*(self.rect[0].y+self.rect[1].y)) def cx(self): """ Center x """ @@ -258,17 +275,17 @@ class pin_layout: def ul(self): """ Upper left point """ - return vector(self.rect[0].x,self.rect[1].y) + return vector(self.rect[0].x, self.rect[1].y) def lr(self): """ Lower right point """ - return vector(self.rect[1].x,self.rect[0].y) + return vector(self.rect[1].x, self.rect[0].y) def ur(self): """ Upper right point """ return self.rect[1] - # The possible y edge values + # The possible y edge values def uy(self): """ Upper y value """ return self.rect[1].y @@ -287,67 +304,71 @@ class pin_layout: """ Right x value """ return self.rect[1].x - # The edge centers def rc(self): """ Right center point """ - return vector(self.rect[1].x,0.5*(self.rect[0].y+self.rect[1].y)) + return vector(self.rect[1].x, + 0.5*(self.rect[0].y+self.rect[1].y)) def lc(self): """ Left center point """ - return vector(self.rect[0].x,0.5*(self.rect[0].y+self.rect[1].y)) + return vector(self.rect[0].x, + 0.5*(self.rect[0].y+self.rect[1].y)) def uc(self): """ Upper center point """ - return vector(0.5*(self.rect[0].x+self.rect[1].x),self.rect[1].y) + return vector(0.5*(self.rect[0].x+self.rect[1].x), + self.rect[1].y) def bc(self): """ Bottom center point """ - return vector(0.5*(self.rect[0].x+self.rect[1].x),self.rect[0].y) - + return vector(0.5*(self.rect[0].x+self.rect[1].x), + self.rect[0].y) def gds_write_file(self, newLayout): """Writes the pin shape and label to GDS""" - debug.info(4, "writing pin (" + str(self.layer) + "):" - + str(self.width()) + "x" + str(self.height()) + " @ " + str(self.ll())) - newLayout.addBox(layerNumber=layer[self.layer], - purposeNumber=0, + debug.info(4, "writing pin (" + str(self.layer) + "):" + + str(self.width()) + "x" + + str(self.height()) + " @ " + str(self.ll())) + (layer_num, purpose) = layer[self.layer] + newLayout.addBox(layerNumber=layer_num, + purposeNumber=purpose, offsetInMicrons=self.ll(), width=self.width(), height=self.height(), center=False) # Add the tet in the middle of the pin. - # This fixes some pin label offsetting when GDS gets imported into Magic. + # This fixes some pin label offsetting when GDS gets + # imported into Magic. newLayout.addText(text=self.name, - layerNumber=layer[self.layer], - purposeNumber=0, + layerNumber=layer_num, + purposeNumber=purpose, offsetInMicrons=self.center(), 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 + (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)) + # 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) + 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] + if dx >= 0 and dy >= 0: + return [dx, dy] else: - return [0,0] + return [0, 0] def distance(self, other): - """ + """ Calculate the distance to another pin layout. """ - (r1_ll,r1_ur) = self.rect - (r2_ll,r2_ur) = other.rect + (r1_ll, r1_ur) = self.rect + (r2_ll, r2_ur) = other.rect def dist(x1, y1, x2, y2): return math.sqrt((x2-x1)**2 + (y2-y1)**2) @@ -368,7 +389,7 @@ class pin_layout: elif left: return r1_ll.x - r2_ur.x elif right: - return r2_ll.x - r1.ur.x + return r2_ll.x - r1_ur.x elif bottom: return r1_ll.y - r2_ur.y elif top: @@ -377,9 +398,8 @@ class pin_layout: # rectangles intersect return 0 - def overlap_length(self, other): - """ + """ Calculate the intersection segment and determine its length """ @@ -391,21 +411,21 @@ class pin_layout: 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)) + 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 + """ + Calculate the intersection segment of two rectangles (if any) """ - (r1_ll,r1_ur) = self.rect - (r2_ll,r2_ur) = other.rect + (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) @@ -414,6 +434,7 @@ class pin_layout: 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) @@ -423,14 +444,14 @@ class pin_layout: # 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]) + 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]) + 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 @@ -452,18 +473,18 @@ class pin_layout: q.x >= min(p.x, r.x) and \ q.y <= max(p.y, r.y) and \ q.y >= min(p.y, r.y): - return True + 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 + (a, b) = s1 + (c, d) = s2 # Line AB represented as a1x + b1y = c1 a1 = b.y - a.y b1 = a.x - b.x @@ -476,12 +497,22 @@ class pin_layout: determinant = a1*b2 - a2*b1 - if determinant!=0: + if determinant != 0: x = (b2*c1 - b1*c2)/determinant y = (a1*c2 - a2*c1)/determinant - r = vector(x,y).snap_to_grid() + r = vector(x, y).snap_to_grid() if self.on_segment(a, r, b) and self.on_segment(c, r, d): return r return None + + def same_lpp(self, lpp1, lpp2): + """ + Check if the layers and purposes are the same. + Ignore if purpose is a None. + """ + if lpp1[1] == None or lpp2[1] == None: + return lpp1[0] == lpp2[0] + + return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1] diff --git a/compiler/base/utils.py b/compiler/base/utils.py index 61e12096..f02b2b85 100644 --- a/compiler/base/utils.py +++ b/compiler/base/utils.py @@ -5,7 +5,6 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import os import gdsMill import tech import math @@ -16,6 +15,7 @@ from pin_layout import pin_layout OPTS = globals.OPTS + def ceil(decimal): """ Performs a ceiling function on the decimal place specified by the DRC grid. @@ -23,29 +23,35 @@ def ceil(decimal): grid = tech.drc["grid"] return math.ceil(decimal * 1 / grid) / (1 / grid) + def round_to_grid(number): """ Rounds an arbitrary number to the grid. """ - grid = tech.drc["grid"] + grid = tech.drc["grid"] # this gets the nearest integer value number_grid = int(round(round((number / grid), 2), 0)) number_off = number_grid * grid return number_off + def snap_to_grid(offset): """ Changes the coodrinate to match the grid settings """ - return [round_to_grid(offset[0]),round_to_grid(offset[1])] + return [round_to_grid(offset[0]), + round_to_grid(offset[1])] + def pin_center(boundary): """ This returns the center of a pin shape in the vlsiLayout border format. """ - return [0.5 * (boundary[0] + boundary[2]), 0.5 * (boundary[1] + boundary[3])] + return [0.5 * (boundary[0] + boundary[2]), + 0.5 * (boundary[1] + boundary[3])] -def auto_measure_libcell(pin_list, name, units, layer): + +def auto_measure_libcell(pin_list, name, units, lpp): """ Open a GDS file and find the pins in pin_list as text on a given layer. Return these as a set of properties including the cell width/height too. @@ -56,43 +62,42 @@ def auto_measure_libcell(pin_list, name, units, layer): reader.loadFromFile(cell_gds) cell = {} - measure_result = cell_vlsi.getLayoutBorder(layer) - if measure_result == None: + measure_result = cell_vlsi.getLayoutBorder(lpp[0]) + if measure_result: measure_result = cell_vlsi.measureSize(name) [cell["width"], cell["height"]] = measure_result for pin in pin_list: - (name,layer,boundary)=cell_vlsi.getPinShapeByLabel(str(pin)) + (name, lpp, boundary) = cell_vlsi.getPinShapeByLabel(str(pin)) cell[str(pin)] = pin_center(boundary) return cell - -def get_gds_size(name, gds_filename, units, layer): +def get_gds_size(name, gds_filename, units, lpp): """ Open a GDS file and return the size from either the bounding box or a border layer. """ - debug.info(4,"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) - cell = {} - measure_result = cell_vlsi.getLayoutBorder(layer) - if measure_result == None: - debug.info(2,"Layout border failed. Trying to measure size for {}".format(name)) + measure_result = cell_vlsi.getLayoutBorder(lpp) + if not measure_result: + debug.info(2, "Layout border failed. Trying to measure size for {}".format(name)) measure_result = cell_vlsi.measureSize(name) # returns width,height return measure_result -def get_libcell_size(name, units, layer): + +def get_libcell_size(name, units, lpp): """ Open a GDS file and return the library cell size from either the bounding box or a border layer. """ cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" - return(get_gds_size(name, cell_gds, units, layer)) + return(get_gds_size(name, cell_gds, units, lpp)) def get_gds_pins(pin_names, name, gds_filename, units): @@ -106,15 +111,18 @@ def get_gds_pins(pin_names, name, gds_filename, units): cell = {} for pin_name in pin_names: - cell[str(pin_name)]=[] - pin_list=cell_vlsi.getPinShape(str(pin_name)) + cell[str(pin_name)] = [] + pin_list = cell_vlsi.getPinShape(str(pin_name)) for pin_shape in pin_list: - (layer,boundary)=pin_shape - rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] - # this is a list because other cells/designs may have must-connect pins - cell[str(pin_name)].append(pin_layout(pin_name, rect, layer)) + (lpp, boundary) = pin_shape + rect = [vector(boundary[0], boundary[1]), + vector(boundary[2], boundary[3])] + # this is a list because other cells/designs + # may have must-connect pins + cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp)) return cell + def get_libcell_pins(pin_list, name, units): """ Open a GDS file and find the pins in pin_list as text on a given layer. diff --git a/compiler/debug.py b/compiler/debug.py index 15876f22..a902bca0 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -26,6 +26,9 @@ def check(check, str): log("ERROR: file {0}: line {1}: {2}\n".format( os.path.basename(filename), line_number, str)) + if globals.OPTS.debug_level > 0: + import pdb + pdb.set_trace() assert 0 @@ -37,6 +40,9 @@ def error(str, return_value=0): log("ERROR: file {0}: line {1}: {2}\n".format( os.path.basename(filename), line_number, str)) + if globals.OPTS.debug_level > 0: + import pdb + pdb.set_trace() assert return_value == 0 diff --git a/compiler/gdsMill/gdsMill/gds2reader.py b/compiler/gdsMill/gdsMill/gds2reader.py index 85fc0c66..7e519c36 100644 --- a/compiler/gdsMill/gdsMill/gds2reader.py +++ b/compiler/gdsMill/gdsMill/gds2reader.py @@ -686,10 +686,6 @@ class Gds2reader: if idBits==('\x07','\x00'): break; #we've reached the end of the structure elif(idBits==('\x06','\x06')): structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip() -# print(''.[x for x in structName if ord(x) < 128]) -# stripped = (c for c in structName if 0 < ord(c) < 127) -# structName = "".join(stripped) -# print(self.stripNonASCII(structName)) ##FIXME: trimming by Tom g. ##could be an issue here with string trimming! thisStructure.name = structName if(findStructName==thisStructure.name): wantedStruct=1 @@ -767,10 +763,6 @@ class Gds2reader: if idBits==('\x07','\x00'): break; #we've reached the end of the structure elif(idBits==('\x06','\x06')): structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip() -# print(''.[x for x in structName if ord(x) < 128]) -# stripped = (c for c in structName if 0 < ord(c) < 127) -# structName = "".join(stripped) -# print(self.stripNonASCIIx(structName)) ##FIXME: trimming by Tom g. ##could be an issue here with string trimming! thisStructure.name = structName if(self.debugToTerminal==1): print("\tStructure Name: "+structName) diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index f4248ebd..eec1870c 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -19,7 +19,8 @@ class VlsiLayout: self.layerNumbersInUse = [] self.debug = False if name: - self.rootStructureName=name + #take the root structure and copy it to a new structure with the new name + self.rootStructureName=self.padText(name) #create the ROOT structure self.structures[self.rootStructureName] = GdsStructure() self.structures[self.rootStructureName].name = name @@ -82,13 +83,9 @@ class VlsiLayout: return coordinatesRotate def rename(self,newName): - #make sure the newName is a multiple of 2 characters - if(len(newName)%2 == 1): - #pad with a zero - newName = newName + '\x00' #take the root structure and copy it to a new structure with the new name self.structures[newName] = self.structures[self.rootStructureName] - self.structures[newName].name = newName + self.structures[newName].name = self.padText(newName) #and delete the old root del self.structures[self.rootStructureName] self.rootStructureName = newName @@ -159,13 +156,14 @@ class VlsiLayout: debug.check(len(structureNames)==1,"Multiple possible root structures in the layout: {}".format(str(structureNames))) self.rootStructureName = structureNames[0] + def traverseTheHierarchy(self, startingStructureName=None, delegateFunction = None, transformPath = [], rotateAngle = 0, transFlags = [0,0,0], coordinates = (0,0)): #since this is a recursive function, must deal with the default #parameters explicitly if startingStructureName == None: startingStructureName = self.rootStructureName - + #set up the rotation matrix if(rotateAngle == None or rotateAngle == ""): angle = 0 @@ -193,17 +191,21 @@ class VlsiLayout: delegateFunction(startingStructureName, transformPath) #starting with a particular structure, we will recursively traverse the tree #********might have to set the recursion level deeper for big layouts! - if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others? - #if so, go through each and call this function again - #if not, return back to the caller (caller can be this function) - for sref in self.structures[startingStructureName].srefs: - #here, we are going to modify the sref coordinates based on the parent objects rotation - self.traverseTheHierarchy(startingStructureName = sref.sName, - delegateFunction = delegateFunction, - transformPath = transformPath, - rotateAngle = sref.rotateAngle, - transFlags = sref.transFlags, - coordinates = sref.coordinates) + try: + if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others? + #if so, go through each and call this function again + #if not, return back to the caller (caller can be this function) + for sref in self.structures[startingStructureName].srefs: + #here, we are going to modify the sref coordinates based on the parent objects rotation + self.traverseTheHierarchy(startingStructureName = sref.sName, + delegateFunction = delegateFunction, + transformPath = transformPath, + rotateAngle = sref.rotateAngle, + transFlags = sref.transFlags, + coordinates = sref.coordinates) + except KeyError: + debug.error("Could not find structure {} in GDS file.".format(startingStructureName),-1) + #MUST HANDLE AREFs HERE AS WELL #when we return, drop the last transform from the transformPath del transformPath[-1] @@ -211,11 +213,11 @@ class VlsiLayout: def initialize(self): self.deduceHierarchy() - #self.traverseTheHierarchy() + # self.traverseTheHierarchy() self.populateCoordinateMap() for layerNumber in self.layerNumbersInUse: - self.processLabelPins(layerNumber) + self.processLabelPins((layerNumber, None)) def populateCoordinateMap(self): @@ -243,21 +245,24 @@ class VlsiLayout: self.xyTree.append((startingStructureName,origin,uVector,vVector)) self.traverseTheHierarchy(delegateFunction = addToXyTree) - def microns(self,userUnits): + def microns(self, userUnits): """Utility function to convert user units to microns""" userUnit = self.units[1]/self.units[0] - userUnitsPerMicron = userUnit / (userunit) + userUnitsPerMicron = userUnit / userunit layoutUnitsPerMicron = userUnitsPerMicron / self.units[0] return userUnits / layoutUnitsPerMicron - def userUnits(self,microns): + def userUnits(self, microns): """Utility function to convert microns to user units""" userUnit = self.units[1]/self.units[0] - #userUnitsPerMicron = userUnit / 1e-6 + # userUnitsPerMicron = userUnit / 1e-6 userUnitsPerMicron = userUnit / (userUnit) layoutUnitsPerMicron = userUnitsPerMicron / self.units[0] - #print("userUnit:",userUnit,"userUnitsPerMicron",userUnitsPerMicron,"layoutUnitsPerMicron",layoutUnitsPerMicron,[microns,microns*layoutUnitsPerMicron]) - return round(microns*layoutUnitsPerMicron,0) + # print("userUnit:",userUnit, + # "userUnitsPerMicron",userUnitsPerMicron, + # "layoutUnitsPerMicron",layoutUnitsPerMicron, + # [microns,microns*layoutUnitsPerMicron]) + return round(microns*layoutUnitsPerMicron, 0) def changeRoot(self,newRoot, create=False): """ @@ -384,7 +389,7 @@ class VlsiLayout: #add the sref to the root structure self.structures[self.rootStructureName].boundaries.append(boundaryToAdd) - def addPath(self, layerNumber=0, purposeNumber = None, coordinates=[(0,0)], width=1.0): + def addPath(self, layerNumber=0, purposeNumber=None, coordinates=[(0,0)], width=1.0): """ Method to add a path to a layout """ @@ -396,24 +401,22 @@ class VlsiLayout: cY = self.userUnits(coordinate[1]) layoutUnitCoordinates.append((cX,cY)) pathToAdd = GdsPath() - pathToAdd.drawingLayer=layerNumber + pathToAdd.drawingLayer = layerNumber pathToAdd.purposeLayer = purposeNumber - pathToAdd.pathWidth=widthInLayoutUnits - pathToAdd.coordinates=layoutUnitCoordinates + pathToAdd.pathWidth = widthInLayoutUnits + pathToAdd.coordinates = layoutUnitCoordinates #add the sref to the root structure self.structures[self.rootStructureName].paths.append(pathToAdd) - def addText(self, text, layerNumber=0, purposeNumber = None, offsetInMicrons=(0,0), magnification=0.1, rotate = None): + def addText(self, text, layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), magnification=0.1, rotate = None): offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1])) textToAdd = GdsText() textToAdd.drawingLayer = layerNumber textToAdd.purposeLayer = purposeNumber textToAdd.dataType = 0 textToAdd.coordinates = [offsetInLayoutUnits] - textToAdd.transFlags = [0,0,0] - if(len(text)%2 == 1): - text = text + '\x00' - textToAdd.textString = text + textToAdd.transFlags = [0,0,0] + textToAdd.textString = self.padText(text) #textToAdd.transFlags[1] = 1 textToAdd.magFactor = magnification if rotate: @@ -421,7 +424,13 @@ class VlsiLayout: textToAdd.rotateAngle = rotate #add the sref to the root structure self.structures[self.rootStructureName].texts.append(textToAdd) - + + def padText(self, text): + if(len(text)%2 == 1): + return text + '\x00' + else: + return text + def isBounded(self,testPoint,startPoint,endPoint): #these arguments are touples of (x,y) coordinates if testPoint == None: @@ -587,41 +596,50 @@ class VlsiLayout: passFailIndex += 1 print("Done\n\n") - def getLayoutBorder(self,borderlayer): - cellSizeMicron=None + def getLayoutBorder(self, lpp): + cellSizeMicron = None for boundary in self.structures[self.rootStructureName].boundaries: - if boundary.drawingLayer==borderlayer: + if sameLPP((boundary.drawingLayer, boundary.purposeLayer), + lpp): if self.debug: - debug.info(1,"Find border "+str(boundary.coordinates)) - left_bottom=boundary.coordinates[0] - right_top=boundary.coordinates[2] - cellSize=[right_top[0]-left_bottom[0],right_top[1]-left_bottom[1]] - cellSizeMicron=[cellSize[0]*self.units[0],cellSize[1]*self.units[0]] - if not(cellSizeMicron): - print("Error: "+str(self.rootStructureName)+".cell_size information not found yet") + debug.info(1, "Find border "+str(boundary.coordinates)) + left_bottom = boundary.coordinates[0] + right_top = boundary.coordinates[2] + cellSize = [right_top[0]-left_bottom[0], + right_top[1]-left_bottom[1]] + cellSizeMicron = [cellSize[0]*self.units[0], + cellSize[1]*self.units[0]] + debug.check(cellSizeMicron, + "Error: "+str(self.rootStructureName)+".cell_size information not found yet") + return cellSizeMicron - def measureSize(self,startStructure): - self.rootStructureName=startStructure + def measureSize(self, startStructure): + self.rootStructureName = self.padText(startStructure) self.populateCoordinateMap() cellBoundary = [None, None, None, None] for TreeUnit in self.xyTree: - cellBoundary=self.measureSizeInStructure(TreeUnit,cellBoundary) - cellSize=[cellBoundary[2]-cellBoundary[0],cellBoundary[3]-cellBoundary[1]] - cellSizeMicron=[cellSize[0]*self.units[0],cellSize[1]*self.units[0]] + cellBoundary = self.measureSizeInStructure(TreeUnit, cellBoundary) + cellSize = [cellBoundary[2]-cellBoundary[0], + cellBoundary[3]-cellBoundary[1]] + cellSizeMicron = [cellSize[0]*self.units[0], + cellSize[1]*self.units[0]] return cellSizeMicron - def measureBoundary(self,startStructure): - self.rootStructureName=startStructure + def measureBoundary(self, startStructure): + self.rootStructureName = self.padText(startStructure) self.populateCoordinateMap() cellBoundary = [None, None, None, None] for TreeUnit in self.xyTree: - cellBoundary=self.measureSizeInStructure(TreeUnit,cellBoundary) - return [[self.units[0]*cellBoundary[0],self.units[0]*cellBoundary[1]], - [self.units[0]*cellBoundary[2],self.units[0]*cellBoundary[3]]] + cellBoundary = self.measureSizeInStructure(TreeUnit, cellBoundary) + return [[self.units[0]*cellBoundary[0], + self.units[0]*cellBoundary[1]], + [self.units[0]*cellBoundary[2], + self.units[0]*cellBoundary[3]]] - def measureSizeInStructure(self,structure,cellBoundary): - (structureName,structureOrigin,structureuVector,structurevVector)=structure + def measureSizeInStructure(self, structure, cellBoundary): + (structureName, structureOrigin, + structureuVector, structurevVector) = structure for boundary in self.structures[str(structureName)].boundaries: left_bottom=boundary.coordinates[0] right_top=boundary.coordinates[2] @@ -648,14 +666,14 @@ class VlsiLayout: cellBoundary[3]=right_top_Y return cellBoundary - - def getTexts(self, layer): + def getTexts(self, lpp): """ Get all of the labels on a given layer only at the root level. """ text_list = [] for Text in self.structures[self.rootStructureName].texts: - if Text.drawingLayer == layer: + if sameLPP((Text.drawingLayer, Text.purposeLayer), + lpp): text_list.append(Text) return text_list @@ -671,9 +689,9 @@ class VlsiLayout: max_pin = None max_area = 0 for pin in pin_list: - (layer,boundary) = pin + (layer, boundary) = pin new_area = boundaryArea(boundary) - if max_pin == None or new_area>max_area: + if not max_pin or new_area > max_area: max_pin = pin max_area = new_area max_pins.append(max_pin) @@ -690,32 +708,33 @@ class VlsiLayout: pin_map = self.pins[pin_name] for pin_list in pin_map: for pin in pin_list: - (pin_layer, boundary) = pin + (pin_layer, boundary) = pin shape_list.append(pin) return shape_list - - def processLabelPins(self, layer): + def processLabelPins(self, lpp): """ Find all text labels and create a map to a list of shapes that they enclose on the given layer. """ # Get the labels on a layer in the root level - labels = self.getTexts(layer) + labels = self.getTexts(lpp) + # Get all of the shapes on the layer at all levels # and transform them to the current level - shapes = self.getAllShapes(layer) + shapes = self.getAllShapes(lpp) for label in labels: label_coordinate = label.coordinates[0] user_coordinate = [x*self.units[0] for x in label_coordinate] pin_shapes = [] for boundary in shapes: - if self.labelInRectangle(user_coordinate,boundary): - pin_shapes.append((layer, boundary)) + if self.labelInRectangle(user_coordinate, boundary): + pin_shapes.append((lpp, boundary)) label_text = label.textString + # Remove the padding if it exists if label_text[-1] == "\x00": label_text = label_text[0:-1] @@ -725,81 +744,97 @@ class VlsiLayout: except KeyError: self.pins[label_text] = [] self.pins[label_text].append(pin_shapes) - - def getBlockages(self,layer): + def getBlockages(self, lpp): """ - Return all blockages on a given layer in [coordinate 1, coordinate 2,...] format and + Return all blockages on a given layer in + [coordinate 1, coordinate 2,...] format and user units. """ blockages = [] - shapes = self.getAllShapes(layer) + shapes = self.getAllShapes(lpp) for boundary in shapes: vectors = [] - for i in range(0,len(boundary),2): - vectors.append(vector(boundary[i],boundary[i+1])) + for i in range(0, len(boundary), 2): + vectors.append(vector(boundary[i], boundary[i+1])) blockages.append(vectors) - return blockages + + return blockages - def getAllShapes(self,layer): + def getAllShapes(self, lpp): """ - Return all shapes on a given layer in [llx, lly, urx, ury] format and user units for rectangles - and [coordinate 1, coordinate 2,...] format and user units for polygons. + Return all shapes on a given layer in [llx, lly, urx, ury] + format and user units for rectangles + and [coordinate 1, coordinate 2,...] format and user + units for polygons. """ boundaries = set() for TreeUnit in self.xyTree: - #print(TreeUnit[0]) - boundaries.update(self.getShapesInStructure(layer,TreeUnit)) + # print(TreeUnit[0]) + boundaries.update(self.getShapesInStructure(lpp, TreeUnit)) # Convert to user units user_boundaries = [] for boundary in boundaries: boundaries_list = [] - for i in range(0,len(boundary)): + for i in range(0, len(boundary)): boundaries_list.append(boundary[i]*self.units[0]) user_boundaries.append(boundaries_list) return user_boundaries - - def getShapesInStructure(self,layer,structure): - """ - Go through all the shapes in a structure and return the list of shapes in - the form [llx, lly, urx, ury] for rectangles and [coordinate 1, coordinate 2,...] for polygons. + def getShapesInStructure(self, lpp, structure): """ - (structureName,structureOrigin,structureuVector,structurevVector)=structure - #print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose()) + Go through all the shapes in a structure and + return the list of shapes in + the form [llx, lly, urx, ury] for rectangles + and [coordinate 1, coordinate 2,...] for polygons. + """ + (structureName, structureOrigin, + structureuVector, structurevVector) = structure + # print(structureName, + # "u", structureuVector.transpose(), + # "v",structurevVector.transpose(), + # "o",structureOrigin.transpose()) boundaries = [] for boundary in self.structures[str(structureName)].boundaries: - if layer==boundary.drawingLayer: - if len(boundary.coordinates)!=5: + if sameLPP((boundary.drawingLayer, boundary.purposeLayer), + lpp): + if len(boundary.coordinates) != 5: # if shape is a polygon (used in DFF) boundaryPolygon = [] # Polygon is a list of coordinates going ccw - for coord in range(0,len(boundary.coordinates)): + for coord in range(0, len(boundary.coordinates)): boundaryPolygon.append(boundary.coordinates[coord][0]) boundaryPolygon.append(boundary.coordinates[coord][1]) # perform the rotation - boundaryPolygon=self.transformPolygon(boundaryPolygon,structureuVector,structurevVector) - # add the offset + boundaryPolygon = self.transformPolygon(boundaryPolygon, + structureuVector, + structurevVector) + # add the offset polygon = [] - for i in range(0,len(boundaryPolygon),2): - polygon.append(boundaryPolygon[i]+structureOrigin[0].item()) - polygon.append(boundaryPolygon[i+1]+structureOrigin[1].item()) + for i in range(0, len(boundaryPolygon), 2): + polygon.append(boundaryPolygon[i] + structureOrigin[0].item()) + polygon.append(boundaryPolygon[i+1] + structureOrigin[1].item()) # make it a tuple polygon = tuple(polygon) boundaries.append(polygon) else: # else shape is a rectangle - left_bottom=boundary.coordinates[0] - right_top=boundary.coordinates[2] + left_bottom = boundary.coordinates[0] + right_top = boundary.coordinates[2] # Rectangle is [leftx, bottomy, rightx, topy]. - boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]] + boundaryRect = [left_bottom[0], left_bottom[1], + right_top[0], right_top[1]] # perform the rotation - boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector) + boundaryRect = self.transformRectangle(boundaryRect, + structureuVector, + structurevVector) # add the offset and make it a tuple - boundaryRect=(boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(), - boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()) + boundaryRect = (boundaryRect[0]+structureOrigin[0].item(), + boundaryRect[1]+structureOrigin[1].item(), + boundaryRect[2]+structureOrigin[0].item(), + boundaryRect[3]+structureOrigin[1].item()) boundaries.append(boundaryRect) return boundaries @@ -861,6 +896,17 @@ class VlsiLayout: else: return False + +def sameLPP(lpp1, lpp2): + """ + Check if the layers and purposes are the same. + Ignore if purpose is a None. + """ + if lpp1[1] == None or lpp2[1] == None: + return lpp1[0] == lpp2[0] + + return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1] + def boundaryArea(A): """ diff --git a/compiler/globals.py b/compiler/globals.py index e08e381f..59d34999 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -6,8 +6,8 @@ # All rights reserved. # """ -This is called globals.py, but it actually parses all the arguments and performs -the global OpenRAM setup as well. +This is called globals.py, but it actually parses all the arguments +and performs the global OpenRAM setup as well. """ import os import debug @@ -19,12 +19,13 @@ import re import copy import importlib -VERSION = "1.1.0" +VERSION = "1.1.3" NAME = "OpenRAM v{}".format(VERSION) USAGE = "openram.py [options] \nUse -h for help.\n" OPTS = options.options() -CHECKPOINT_OPTS=None +CHECKPOINT_OPTS = None + def parse_args(): """ Parse the optional arguments for OpenRAM """ @@ -32,27 +33,55 @@ def parse_args(): global OPTS option_list = { - optparse.make_option("-b", "--backannotated", action="store_true", dest="use_pex", + optparse.make_option("-b", + "--backannotated", + action="store_true", + dest="use_pex", help="Back annotate simulation"), - optparse.make_option("-o", "--output", dest="output_name", - help="Base output file name(s) prefix", metavar="FILE"), - optparse.make_option("-p", "--outpath", dest="output_path", + optparse.make_option("-o", + "--output", + dest="output_name", + help="Base output file name(s) prefix", + metavar="FILE"), + optparse.make_option("-p", "--outpath", + dest="output_path", help="Output file(s) location"), - optparse.make_option("-i", "--inlinecheck", action="store_true", - help="Enable inline LVS/DRC checks", dest="inline_lvsdrc"), - optparse.make_option("-n", "--nocheck", action="store_false", - help="Disable all LVS/DRC checks", dest="check_lvsdrc"), - optparse.make_option("-v", "--verbose", action="count", dest="debug_level", + optparse.make_option("-i", + "--inlinecheck", + action="store_true", + help="Enable inline LVS/DRC checks", + dest="inline_lvsdrc"), + optparse.make_option("-n", "--nocheck", + action="store_false", + help="Disable all LVS/DRC checks", + dest="check_lvsdrc"), + optparse.make_option("-v", + "--verbose", + action="count", + dest="debug_level", help="Increase the verbosity level"), - optparse.make_option("-t", "--tech", dest="tech_name", + optparse.make_option("-t", + "--tech", + dest="tech_name", help="Technology name"), - optparse.make_option("-s", "--spice", dest="spice_name", + optparse.make_option("-s", + "--spice", + dest="spice_name", help="Spice simulator executable name"), - optparse.make_option("-r", "--remove_netlist_trimming", action="store_false", dest="trim_netlist", + optparse.make_option("-r", + "--remove_netlist_trimming", + action="store_false", + dest="trim_netlist", help="Disable removal of noncritical memory cells during characterization"), - optparse.make_option("-c", "--characterize", action="store_false", dest="analytical_delay", + optparse.make_option("-c", + "--characterize", + action="store_false", + dest="analytical_delay", help="Perform characterization to calculate delays (default is analytical models)"), - optparse.make_option("-d", "--dontpurge", action="store_false", dest="purge_temp", + optparse.make_option("-d", + "--dontpurge", + action="store_false", + dest="purge_temp", help="Don't purge the contents of the temp directory after a successful run") # -h --help is implicit. } @@ -73,6 +102,7 @@ def parse_args(): return (options, args) + def print_banner(): """ Conditionally print the banner to stdout """ global OPTS @@ -117,13 +147,13 @@ def check_versions(): except: OPTS.coverage = 0 + def init_openram(config_file, is_unit_test=True): - """Initialize the technology, paths, simulators, etc.""" + """ Initialize the technology, paths, simulators, etc. """ - check_versions() - debug.info(1,"Initializing OpenRAM...") + debug.info(1, "Initializing OpenRAM...") setup_paths() @@ -146,10 +176,11 @@ def init_openram(config_file, is_unit_test=True): # This is a hack. If we are running a unit test and have checkpointed # the options, load them rather than reading the config file. # This way, the configuration is reloaded at the start of every unit test. - # If a unit test fails, we don't have to worry about restoring the old config values + # If a unit test fails, + # we don't have to worry about restoring the old config values # that may have been tested. if is_unit_test and CHECKPOINT_OPTS: - OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy() + OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy() return # Import these to find the executables for checkpointing @@ -159,7 +190,8 @@ def init_openram(config_file, is_unit_test=True): # after each unit test if not CHECKPOINT_OPTS: CHECKPOINT_OPTS = copy.copy(OPTS) - + + def setup_bitcell(): """ Determine the correct custom or parameterized bitcell for the design. @@ -169,30 +201,29 @@ def setup_bitcell(): # If we have non-1rw ports, # and the user didn't over-ride the bitcell manually, # figure out the right bitcell to use - if (OPTS.bitcell=="bitcell"): + if (OPTS.bitcell == "bitcell"): - if (OPTS.num_rw_ports==1 and OPTS.num_w_ports==0 and OPTS.num_r_ports==0): + if (OPTS.num_rw_ports == 1 and OPTS.num_w_ports == 0 and OPTS.num_r_ports == 0): OPTS.bitcell = "bitcell" OPTS.replica_bitcell = "replica_bitcell" OPTS.dummy_bitcell = "dummy_bitcell" else: ports = "" - if OPTS.num_rw_ports>0: + if OPTS.num_rw_ports > 0: ports += "{}rw_".format(OPTS.num_rw_ports) - if OPTS.num_w_ports>0: + if OPTS.num_w_ports > 0: ports += "{}w_".format(OPTS.num_w_ports) - if OPTS.num_r_ports>0: + if OPTS.num_r_ports > 0: ports += "{}r".format(OPTS.num_r_ports) OPTS.bitcell = "bitcell_"+ports OPTS.replica_bitcell = "replica_bitcell_"+ports OPTS.dummy_bitcell = "dummy_bitcell_"+ports else: - OPTS.replica_bitcell = "replica_" + OPTS.bitcell - OPTS.replica_bitcell = "dummy_" + OPTS.bitcell + OPTS.replica_bitcell = "replica_" + OPTS.bitcell + OPTS.replica_bitcell = "dummy_" + OPTS.bitcell # See if bitcell exists - from importlib import find_loader try: __import__(OPTS.bitcell) __import__(OPTS.replica_bitcell) @@ -206,7 +237,7 @@ def setup_bitcell(): OPTS.replica_bitcell = "dummy_pbitcell" if not OPTS.is_unit_test: debug.warning("Using the parameterized bitcell which may have suboptimal density.") - debug.info(1,"Using bitcell: {}".format(OPTS.bitcell)) + debug.info(1, "Using bitcell: {}".format(OPTS.bitcell)) def get_tool(tool_type, preferences, default_name=None): @@ -215,63 +246,73 @@ def get_tool(tool_type, preferences, default_name=None): one selected and its full path. If default is specified, find that one only and error otherwise. """ - debug.info(2,"Finding {} tool...".format(tool_type)) + debug.info(2, "Finding {} tool...".format(tool_type)) if default_name: - exe_name=find_exe(default_name) + exe_name = find_exe(default_name) if exe_name == None: - debug.error("{0} not found. Cannot find {1} tool.".format(default_name,tool_type),2) + debug.error("{0} not found. Cannot find {1} tool.".format(default_name, + tool_type), + 2) else: - debug.info(1, "Using {0}: {1}".format(tool_type,exe_name)) - return(default_name,exe_name) + debug.info(1, "Using {0}: {1}".format(tool_type, exe_name)) + return(default_name, exe_name) else: for name in preferences: exe_name = find_exe(name) if exe_name != None: - debug.info(1, "Using {0}: {1}".format(tool_type,exe_name)) - return(name,exe_name) + debug.info(1, "Using {0}: {1}".format(tool_type, exe_name)) + return(name, exe_name) else: - debug.info(1, "Could not find {0}, trying next {1} tool.".format(name,tool_type)) + debug.info(1, + "Could not find {0}, trying next {1} tool.".format(name, + tool_type)) else: - return(None,"") + return(None, "") def read_config(config_file, is_unit_test=True): - """ + """ Read the configuration file that defines a few parameters. The config file is just a Python file that defines some config options. This will only actually get read the first time. Subsequent reads will just restore the previous copy (ask mrg) """ global OPTS - - # Create a full path relative to current dir unless it is already an abs path + + # it is already not an abs path, make it one if not os.path.isabs(config_file): config_file = os.getcwd() + "/" + config_file + # Make it a python file if the base name was only given config_file = re.sub(r'\.py$', "", config_file) + + # Expand the user if it is used config_file = os.path.expanduser(config_file) - OPTS.config_file = config_file - # Add the path to the system path so we can import things in the other directory + + OPTS.config_file = config_file + ".py" + # Add the path to the system path + # so we can import things in the other directory dir_name = os.path.dirname(config_file) - file_name = os.path.basename(config_file) + module_name = os.path.basename(config_file) + # Prepend the path to avoid if we are using the example config - sys.path.insert(0,dir_name) + sys.path.insert(0, dir_name) # Import the configuration file of which modules to use debug.info(1, "Configuration file is " + config_file + ".py") try: - config = importlib.import_module(file_name) + config = importlib.import_module(module_name) except: debug.error("Unable to read configuration file: {0}".format(config_file),2) - for k,v in config.__dict__.items(): + for k, v in config.__dict__.items(): # The command line will over-ride the config file # except in the case of the tech name! This is because the tech name # is sometimes used to specify the config file itself (e.g. unit tests) # Note that if we re-read a config file, nothing will get read again! - if not k in OPTS.__dict__ or k=="tech_name": - OPTS.__dict__[k]=v + if k not in OPTS.__dict__ or k == "tech_name": + OPTS.__dict__[k] = v # Massage the output path to be an absolute one if not OPTS.output_path.endswith('/'): @@ -281,20 +322,20 @@ def read_config(config_file, is_unit_test=True): debug.info(1, "Output saved in " + OPTS.output_path) # Remember if we are running unit tests to reduce output - OPTS.is_unit_test=is_unit_test + OPTS.is_unit_test = is_unit_test # If we are only generating a netlist, we can't do DRC/LVS if OPTS.netlist_only: - OPTS.check_lvsdrc=False + OPTS.check_lvsdrc = False # If config didn't set output name, make a reasonable default. if (OPTS.output_name == ""): ports = "" - if OPTS.num_rw_ports>0: + if OPTS.num_rw_ports > 0: ports += "{}rw_".format(OPTS.num_rw_ports) - if OPTS.num_w_ports>0: + if OPTS.num_w_ports > 0: ports += "{}w_".format(OPTS.num_w_ports) - if OPTS.num_r_ports>0: + if OPTS.num_r_ports > 0: ports += "{}r_".format(OPTS.num_r_ports) OPTS.output_name = "sram_{0}b_{1}_{2}{3}".format(OPTS.word_size, OPTS.num_words, @@ -302,8 +343,6 @@ def read_config(config_file, is_unit_test=True): OPTS.tech_name) - - def end_openram(): """ Clean up openram for a proper exit """ cleanup_paths() @@ -312,9 +351,7 @@ def end_openram(): import verify verify.print_drc_stats() verify.print_lvs_stats() - verify.print_pex_stats() - - + verify.print_pex_stats() def cleanup_paths(): @@ -323,40 +360,44 @@ def cleanup_paths(): """ global OPTS if not OPTS.purge_temp: - debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp)) + debug.info(0, + "Preserving temp directory: {}".format(OPTS.openram_temp)) return elif os.path.exists(OPTS.openram_temp): - debug.info(1,"Purging temp directory: {}".format(OPTS.openram_temp)) - # This annoyingly means you have to re-cd into the directory each debug iteration - #shutil.rmtree(OPTS.openram_temp, ignore_errors=True) + debug.info(1, + "Purging temp directory: {}".format(OPTS.openram_temp)) + # This annoyingly means you have to re-cd into + # the directory each debug iteration + # shutil.rmtree(OPTS.openram_temp, ignore_errors=True) contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)] for i in contents: if os.path.isfile(i) or os.path.islink(i): os.remove(i) else: shutil.rmtree(i) - def setup_paths(): """ Set up the non-tech related paths. """ - debug.info(2,"Setting up paths...") + debug.info(2, "Setting up paths...") global OPTS try: OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) except: - debug.error("$OPENRAM_HOME is not properly defined.",1) - debug.check(os.path.isdir(OPENRAM_HOME),"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME)) + debug.error("$OPENRAM_HOME is not properly defined.", 1) + debug.check(os.path.isdir(OPENRAM_HOME), + "$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME)) # Add all of the subdirs to the python path - # These subdirs are modules and don't need to be added: characterizer, verify + # These subdirs are modules and don't need + # to be added: characterizer, verify subdirlist = [ item for item in os.listdir(OPENRAM_HOME) if os.path.isdir(os.path.join(OPENRAM_HOME, item)) ] for subdir in subdirlist: - full_path = "{0}/{1}".format(OPENRAM_HOME,subdir) + full_path = "{0}/{1}".format(OPENRAM_HOME, subdir) debug.check(os.path.isdir(full_path), - "$OPENRAM_HOME/{0} does not exist: {1}".format(subdir,full_path)) + "$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path)) sys.path.append("{0}".format(full_path)) if not OPTS.openram_temp.endswith('/'): @@ -364,13 +405,16 @@ def setup_paths(): debug.info(1, "Temporary files saved in " + OPTS.openram_temp) - def is_exe(fpath): """ Return true if the given is an executable file that exists. """ return os.path.exists(fpath) and os.access(fpath, os.X_OK) + def find_exe(check_exe): - """ Check if the binary exists in any path dir and return the full path. """ + """ + Check if the binary exists in any path dir + and return the full path. + """ # Check if the preferred spice option exists in the path for path in os.environ["PATH"].split(os.pathsep): exe = os.path.join(path, check_exe) @@ -379,12 +423,14 @@ def find_exe(check_exe): return exe return None + def init_paths(): """ Create the temp and output directory if it doesn't exist """ # make the directory if it doesn't exist try: - debug.info(1,"Creating temp directory: {}".format(OPTS.openram_temp)) + debug.info(1, + "Creating temp directory: {}".format(OPTS.openram_temp)) os.makedirs(OPTS.openram_temp, 0o750) except OSError as e: if e.errno == 17: # errno.EEXIST @@ -398,8 +444,9 @@ def init_paths(): if e.errno == 17: # errno.EEXIST os.chmod(OPTS.output_path, 0o750) except: - debug.error("Unable to make output directory.",-1) + debug.error("Unable to make output directory.", -1) + def set_default_corner(): """ Set the default corner. """ @@ -416,17 +463,19 @@ def import_tech(): """ Dynamically adds the tech directory to the path and imports it. """ global OPTS - debug.info(2,"Importing technology: " + OPTS.tech_name) + debug.info(2, + "Importing technology: " + OPTS.tech_name) # environment variable should point to the technology dir try: OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH")) except: - debug.error("$OPENRAM_TECH environment variable is not defined.",1) + debug.error("$OPENRAM_TECH environment variable is not defined.", 1) # Add all of the paths for tech_path in OPENRAM_TECH.split(":"): - debug.check(os.path.isdir(tech_path),"$OPENRAM_TECH does not exist: {0}".format(tech_path)) + debug.check(os.path.isdir(tech_path), + "$OPENRAM_TECH does not exist: {0}".format(tech_path)) sys.path.append(tech_path) debug.info(1, "Adding technology path: {}".format(tech_path)) @@ -438,7 +487,6 @@ def import_tech(): OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/" - # Add the tech directory tech_path = OPTS.openram_tech sys.path.append(tech_path) @@ -453,22 +501,25 @@ def print_time(name, now_time, last_time=None, indentation=2): global OPTS # Don't print during testing - if not OPTS.is_unit_test or OPTS.debug_level>0: + if not OPTS.is_unit_test or OPTS.debug_level > 0: if last_time: time = str(round((now_time-last_time).total_seconds(),1)) + " seconds" else: time = now_time.strftime('%m/%d/%Y %H:%M:%S') - debug.print_raw("{0} {1}: {2}".format("*"*indentation,name,time)) + debug.print_raw("{0} {1}: {2}".format("*"*indentation, name, time)) def report_status(): - """ Check for valid arguments and report the info about the SRAM being generated """ + """ + Check for valid arguments and report the + info about the SRAM being generated + """ global OPTS # Check if all arguments are integers for bits, size, banks - if type(OPTS.word_size)!=int: + if type(OPTS.word_size) != int: debug.error("{0} is not an integer in config file.".format(OPTS.word_size)) - if type(OPTS.num_words)!=int: + if type(OPTS.num_words) != int: debug.error("{0} is not an integer in config file.".format(OPTS.sram_size)) if type(OPTS.write_size) is not int and OPTS.write_size is not None: debug.error("{0} is not an integer in config file.".format(OPTS.write_size)) @@ -478,30 +529,29 @@ def report_status(): if OPTS.write_size is not None: if (OPTS.word_size % OPTS.write_size != 0): debug.error("Write size needs to be an integer multiple of word size.") - # If write size is more than half of the word size, then it doesn't need a write mask. It would be writing + # If write size is more than half of the word size, + # then it doesn't need a write mask. It would be writing # the whole word. if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size/2): debug.error("Write size needs to be between 1 bit and {0} bits/2.".format(OPTS.word_size)) - - if not OPTS.tech_name: debug.error("Tech name must be specified in config file.") debug.print_raw("Technology: {0}".format(OPTS.tech_name)) total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks debug.print_raw("Total size: {} bits".format(total_size)) - if total_size>=2**14: + if total_size >= 2**14: debug.warning("Requesting such a large memory size ({0}) will have a large run-time. ".format(total_size) + "Consider using multiple smaller banks.") debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, - OPTS.num_words, - OPTS.num_banks)) + OPTS.num_words, + OPTS.num_banks)) if (OPTS.write_size != OPTS.word_size): debug.print_raw("Write size: {}".format(OPTS.write_size)) debug.print_raw("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports, - OPTS.num_r_ports, - OPTS.num_w_ports)) + OPTS.num_r_ports, + OPTS.num_w_ports)) if OPTS.netlist_only: debug.print_raw("Netlist only mode (no physical design is being done, netlist_only=False to disable).") @@ -518,7 +568,7 @@ def report_status(): if OPTS.analytical_delay: debug.print_raw("Characterization is disabled (using analytical delay models) (analytical_delay=False to simulate).") else: - if OPTS.spice_name!="": + if OPTS.spice_name != "": debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name)) if OPTS.trim_netlist: debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).") diff --git a/compiler/modules/dff.py b/compiler/modules/dff.py index 3cb1bcf1..8871872d 100644 --- a/compiler/modules/dff.py +++ b/compiler/modules/dff.py @@ -5,13 +5,11 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import globals import design -from math import log -import design -from tech import GDS,layer,spice,parameter +from tech import GDS, layer, spice, parameter import utils + class dff(design.design): """ Memory address flip-flop @@ -19,7 +17,9 @@ class dff(design.design): pin_names = ["D", "Q", "clk", "vdd", "gnd"] type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] - (width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"]) + (width, height) = utils.get_libcell_size("dff", + GDS["unit"], + layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"]) def __init__(self, name="dff"): diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 0e70db55..4648519a 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -10,6 +10,7 @@ import debug import design from math import log from math import sqrt +from math import ceil import math import contact from sram_factory import factory @@ -31,7 +32,7 @@ class hierarchical_decoder(design.design): self.cell_height = height self.rows = rows - self.num_inputs = int(math.log(self.rows, 2)) + self.num_inputs = math.ceil(math.log(self.rows, 2)) (self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs) self.create_netlist() @@ -338,14 +339,15 @@ class hierarchical_decoder(design.design): for i in range(len(self.predec_groups[0])): for j in range(len(self.predec_groups[1])): row = len(self.predec_groups[0])*j + i - name = self.NAND_FORMAT.format(row) - self.nand_inst.append(self.add_inst(name=name, - mod=self.nand2)) - pins =["out_{0}".format(i), - "out_{0}".format(j + len(self.predec_groups[0])), - "Z_{0}".format(row), - "vdd", "gnd"] - self.connect_inst(pins) + if (row < self.rows): + name = self.NAND_FORMAT.format(row) + self.nand_inst.append(self.add_inst(name=name, + mod=self.nand2)) + pins =["out_{0}".format(i), + "out_{0}".format(j + len(self.predec_groups[0])), + "Z_{0}".format(row), + "vdd", "gnd"] + self.connect_inst(pins) # Row Decoder NAND GATE array for address inputs >5. @@ -356,16 +358,17 @@ class hierarchical_decoder(design.design): row = (len(self.predec_groups[0])*len(self.predec_groups[1])) * k \ + len(self.predec_groups[0])*j + i - name = self.NAND_FORMAT.format(row) - self.nand_inst.append(self.add_inst(name=name, - mod=self.nand3)) + if (row < self.rows): + name = self.NAND_FORMAT.format(row) + self.nand_inst.append(self.add_inst(name=name, + mod=self.nand3)) - pins = ["out_{0}".format(i), - "out_{0}".format(j + len(self.predec_groups[0])), - "out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])), - "Z_{0}".format(row), - "vdd", "gnd"] - self.connect_inst(pins) + pins = ["out_{0}".format(i), + "out_{0}".format(j + len(self.predec_groups[0])), + "out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])), + "Z_{0}".format(row), + "vdd", "gnd"] + self.connect_inst(pins) def create_decoder_inv_array(self): @@ -527,10 +530,11 @@ class hierarchical_decoder(design.design): for index_B in self.predec_groups[1]: for index_A in self.predec_groups[0]: # FIXME: convert to connect_bus? - predecode_name = "predecode_{}".format(index_A) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A")) - predecode_name = "predecode_{}".format(index_B) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B")) + if (row_index < self.rows): + predecode_name = "predecode_{}".format(index_A) + self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A")) + predecode_name = "predecode_{}".format(index_B) + self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B")) row_index = row_index + 1 elif (self.num_inputs > 5): @@ -538,12 +542,13 @@ class hierarchical_decoder(design.design): for index_B in self.predec_groups[1]: for index_A in self.predec_groups[0]: # FIXME: convert to connect_bus? - predecode_name = "predecode_{}".format(index_A) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A")) - predecode_name = "predecode_{}".format(index_B) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B")) - predecode_name = "predecode_{}".format(index_C) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("C")) + if (row_index < self.rows): + predecode_name = "predecode_{}".format(index_A) + self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A")) + predecode_name = "predecode_{}".format(index_B) + self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B")) + predecode_name = "predecode_{}".format(index_C) + self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("C")) row_index = row_index + 1 def route_vdd_gnd(self): diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index b1292560..fbd800b2 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -5,17 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from tech import drc, parameter import debug import design import contact -from math import log -from math import sqrt -import math from vector import vector from sram_factory import factory from globals import OPTS + class wordline_driver(design.design): """ Creates a Wordline Driver @@ -58,26 +55,20 @@ class wordline_driver(design.design): self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") - def add_modules(self): - # This is just used for measurements, - # so don't add the module - self.inv = factory.create(module_type="pdriver", fanout=self.cols, neg_polarity=True) self.add_mod(self.inv) - self.inv_no_output = factory.create(module_type="pinv", - route_output=False) - self.add_mod(self.inv_no_output) - self.nand2 = factory.create(module_type="pnand2") self.add_mod(self.nand2) - def route_vdd_gnd(self): - """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ + """ + Add a pin for each row of vdd/gnd which + are must-connects next level up. + """ # Find the x offsets for where the vias/pins should be placed a_xoffset = self.nand_inst[0].rx() @@ -86,7 +77,9 @@ class wordline_driver(design.design): # this will result in duplicate polygons for rails, but who cares # use the inverter offset even though it will be the nand's too - (gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num) + (gate_offset, y_dir) = self.get_gate_offset(0, + self.inv.height, + num) # Route both supplies for name in ["vdd", "gnd"]: @@ -97,11 +90,9 @@ class wordline_driver(design.design): pin_pos = vector(xoffset, supply_pin.cy()) self.add_power_pin(name, pin_pos) - - def create_drivers(self): - self.nand_inst = [] - self.inv2_inst = [] + self.nand_inst = [] + self.inv2_inst = [] for row in range(self.rows): name_nand = "wl_driver_nand{}".format(row) name_inv2 = "wl_driver_inv{}".format(row) @@ -119,8 +110,7 @@ class wordline_driver(design.design): self.connect_inst(["wl_bar_{0}".format(row), "wl_{0}".format(row), "vdd", "gnd"]) - - + def place_drivers(self): nand2_xoffset = 2*self.m1_width + 5*self.m1_space inv2_xoffset = nand2_xoffset + self.nand2.width @@ -136,8 +126,8 @@ class wordline_driver(design.design): y_offset = self.inv.height*row inst_mirror = "R0" - nand2_offset=[nand2_xoffset, y_offset] - inv2_offset=[inv2_xoffset, y_offset] + nand2_offset = [nand2_xoffset, y_offset] + inv2_offset = [inv2_xoffset, y_offset] # add nand 2 self.nand_inst[row].place(offset=nand2_offset, @@ -146,17 +136,16 @@ class wordline_driver(design.design): self.inv2_inst[row].place(offset=inv2_offset, mirror=inst_mirror) - def route_layout(self): """ Route all of the signals """ # Wordline enable connection - en_pin=self.add_layout_pin(text="en", - layer="metal2", - offset=[self.m1_width + 2*self.m1_space,0], - width=self.m2_width, - height=self.height) - + en_offset = [self.m1_width + 2 * self.m1_space, 0] + en_pin = self.add_layout_pin(text="en", + layer="metal2", + offset=en_offset, + width=self.m2_width, + height=self.height) for row in range(self.rows): nand_inst = self.nand_inst[row] @@ -165,7 +154,7 @@ class wordline_driver(design.design): # en connection a_pin = nand_inst.get_pin("A") a_pos = a_pin.lc() - clk_offset = vector(en_pin.bc().x,a_pos.y) + clk_offset = vector(en_pin.bc().x, a_pos.y) self.add_segment_center(layer="metal1", start=clk_offset, end=a_pos) @@ -175,7 +164,7 @@ class wordline_driver(design.design): # Nand2 out to 2nd inv zr_pos = nand_inst.get_pin("Z").rc() al_pos = inv2_inst.get_pin("A").lc() - # ensure the bend is in the middle + # ensure the bend is in the middle mid1_pos = vector(0.5*(zr_pos.x+al_pos.x), zr_pos.y) mid2_pos = vector(0.5*(zr_pos.x+al_pos.x), al_pos.y) self.add_path("metal1", [zr_pos, mid1_pos, mid2_pos, al_pos]) @@ -183,10 +172,14 @@ class wordline_driver(design.design): # connect the decoder input pin to nand2 B b_pin = nand_inst.get_pin("B") b_pos = b_pin.lc() - # needs to move down since B nand input is nearly aligned with A inv input - up_or_down = self.m2_space if row%2 else -self.m2_space - input_offset = vector(0,b_pos.y + up_or_down) - mid_via_offset = vector(clk_offset.x,input_offset.y) + vector(0.5*self.m2_width+self.m2_space+0.5*contact.m1m2.width,0) + # needs to move down since B nand input is + # nearly aligned with A inv input + up_or_down = self.m2_space if row % 2 else -self.m2_space + input_offset = vector(0, b_pos.y + up_or_down) + base_offset = vector(clk_offset.x, input_offset.y) + contact_offset = vector(0.5 * self.m2_width + self.m2_space + 0.5 * contact.m1m2.width, 0) + mid_via_offset = base_offset + contact_offset + # must under the clk line in M1 self.add_layout_pin_segment_center(text="in_{0}".format(row), layer="metal1", @@ -194,24 +187,27 @@ class wordline_driver(design.design): end=mid_via_offset) self.add_via_center(layers=("metal1", "via1", "metal2"), offset=mid_via_offset, - directions=("V","V")) + directions=("V", "V")) # now connect to the nand2 B self.add_path("metal2", [mid_via_offset, b_pos]) + contact_offset = b_pos - vector(0.5 * contact.m1m2.height, 0) self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=b_pos - vector(0.5*contact.m1m2.height,0), - directions=("H","H")) - + offset=contact_offset, + directions=("H", "H")) # output each WL on the right wl_offset = inv2_inst.get_pin("Z").rc() self.add_layout_pin_segment_center(text="wl_{0}".format(row), layer="metal1", start=wl_offset, - end=wl_offset-vector(self.m1_width,0)) + end=wl_offset - vector(self.m1_width, 0)) def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): - """Follows the clk_buf to a wordline signal adding each stages stage effort to a list""" + """ + Follows the clk_buf to a wordline signal adding + each stages stage effort to a list. + """ stage_effort_list = [] stage1_cout = self.inv.get_cin() @@ -225,7 +221,10 @@ class wordline_driver(design.design): return stage_effort_list def get_wl_en_cin(self): - """Get the relative capacitance of all the enable connections in the bank""" - #The enable is connected to a nand2 for every row. + """ + Get the relative capacitance of all + the enable connections in the bank + """ + # The enable is connected to a nand2 for every row. total_cin = self.nand2.get_cin() * self.rows return total_cin diff --git a/compiler/pgates/pwrite_driver.py b/compiler/pgates/pwrite_driver.py new file mode 100644 index 00000000..a808737b --- /dev/null +++ b/compiler/pgates/pwrite_driver.py @@ -0,0 +1,304 @@ +# See LICENSE for licensing information. +# +#Copyright (c) 2019 Regents of the University of California and The Board +#of Regents for the Oklahoma Agricultural and Mechanical College +#(acting for and on behalf of Oklahoma State University) +#All rights reserved. +# +import design +from tech import drc, parameter, spice +import debug +import math +from tech import drc +from vector import vector +from globals import OPTS +from sram_factory import factory + +class pwrite_driver(design.design): + """ + The pwrite_driver is two tristate inverters that drive the bitlines. + The data input is first inverted before one tristate. + The inverted enable is also generated to control one tristate. + """ + def __init__(self, name, size=0): + debug.error("pwrite_driver not implemented yet.", -1) + debug.info(1, "creating pwrite_driver {}".format(name)) + design.design.__init__(self, name) + self.size = size + self.beta = parameter["beta"] + self.pmos_width = self.beta*self.size*parameter["min_tx_size"] + self.nmos_width = self.size*parameter["min_tx_size"] + + # The tech M2 pitch is based on old via orientations + self.m2_pitch = self.m2_space + self.m2_width + + # Width is matched to the bitcell, + # Height will be variable + self.bitcell = factory.create(module_type="bitcell") + self.width = self.bitcell.width + + # Creates the netlist and layout + # Since it has variable height, it is not a pgate. + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + self.DRC_LVS() + + + + def create_netlist(self): + self.add_pins() + self.add_modules() + self.create_insts() + + def create_layout(self): + self.place_modules() + self.route_wires() + self.route_supplies() + + + + def add_pins(self): + self.add_pin("din", "INPUT") + self.add_pin("bl", "OUTPUT") + self.add_pin("br", "OUTPUT") + self.add_pin("en", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + + def add_modules(self): + + # Tristate inverter + self.tri = factory.create(module_type="ptristate_inv", height="min") + self.add_mod(self.tri) + debug.check(self.tri.width 0, + "Did not find any enclosures.") - # Now simplify the enclosure list + # Now simplify the enclosure list new_pin_list = self.remove_redundant_shapes(pin_list) - - return new_pin_list + + debug.check(len(new_pin_list) > 0, + "Did not find any enclosures.") + return new_pin_list + def compute_connector(self, pin, enclosure): - """ - Compute a shape to connect the pin to the enclosure shape. + """ + 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): @@ -154,9 +166,9 @@ class pin_group: plc = pin.lc() prc = pin.rc() elc = enclosure.lc() - erc = enclosure.rc() - ymin = min(plc.y,elc.y) - ymax = max(plc.y,elc.y) + # 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) elif pin.yoverlaps(enclosure): @@ -164,9 +176,9 @@ class pin_group: pbc = pin.bc() puc = pin.uc() ebc = enclosure.bc() - euc = enclosure.uc() - xmin = min(pbc.x,ebc.x) - xmax = max(pbc.x,ebc.x) + # 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) else: @@ -180,7 +192,7 @@ class pin_group: ll = vector(xmin, ymin) ur = vector(xmax, ymax) - if ll.x==ur.x or ll.y==ur.y: + if ll.x == ur.x or ll.y == ur.y: return None p = pin_layout(pin.name, [ll, ur], pin.layer) return p @@ -195,20 +207,20 @@ class pin_group: 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(): + if item.by() >= pin.uy(): above_item = item else: break - # There was nothing - if above_item==None: + # There was nothing + if not above_item: return None # If it already overlaps, no connector needed if above_item.overlaps(pin): @@ -219,7 +231,7 @@ class pin_group: 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. """ @@ -228,31 +240,31 @@ class pin_group: 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(): + if item.uy() <= pin.by(): bottom_item = item else: break # There was nothing to the left - if bottom_item==None: + if not bottom_item: 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. """ @@ -261,31 +273,31 @@ class pin_group: 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(): + if item.rx() <= pin.lx(): left_item = item else: break # There was nothing to the left - if left_item==None: + if not left_item: 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. """ @@ -294,79 +306,79 @@ class pin_group: 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(): + if item.lx() >= pin.rx(): right_item = item else: break # There was nothing to the right - if right_item==None: + if not right_item: 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.. + 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() min_width: - if smallest_shape == None or other.area() biggest.area(): biggest = pin - + return pin def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST): @@ -398,19 +409,18 @@ class pin_group: dir1 and dir2 should be two orthogonal directions. """ - offset1= direction.get_offset(dir1) - offset2= direction.get_offset(dir2) + offset1 = direction.get_offset(dir1) + offset2 = direction.get_offset(dir2) # We may have started with an empty set - if not self.grids: - return None + debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.") # 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 + # 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: @@ -419,7 +429,7 @@ class pin_group: 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 + # 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: @@ -431,74 +441,87 @@ class pin_group: # Add a shape from ll to ur ur = row[-1] - return (ll,ur) + 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 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() # Find a connector to every pin and add it to the enclosures for pin in self.pins: - + # If it is contained, it won't need a connector if pin.contained_by_any(self.enclosures): continue # Find a connector in the cardinal directions - # If there is overlap, but it isn't contained, these could all be None - # These could also be none if the pin is diagonal from the enclosure + # If there is overlap, but it isn't contained, + # these could all be None + # These could also be none if the pin is + # diagonal from the enclosure 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) - connector_list = [left_connector, right_connector, above_connector, below_connector] - filtered_list = list(filter(lambda x: x!=None, connector_list)) - if (len(filtered_list)>0): + connector_list = [left_connector, + right_connector, + above_connector, + below_connector] + filtered_list = list(filter(lambda x: x != None, connector_list)) + if (len(filtered_list) > 0): import copy - bbox_connector = copy.copy(pin) + bbox_connector = copy.copy(pin) bbox_connector.bbox(filtered_list) self.enclosures.append(bbox_connector) - # Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector. - # This could only happen when there was no enclosure in any cardinal direction from a pin + # Now, make sure each pin touches an enclosure. + # If not, add another (diagonal) connector. + # This could only happen when there was no enclosure + # in any cardinal direction from a pin if not self.overlap_any_shape(self.pins, self.enclosures): - connector = self.find_smallest_connector(self.pins, self.enclosures) - if connector==None: - debug.error("Could not find a connector for {} with {}".format(self.pins, self.enclosures)) + connector = self.find_smallest_connector(self.pins, + self.enclosures) + if not connector: + debug.error("Could not find a connector for {} with {}".format(self.pins, + self.enclosures)) self.router.write_debug_gds("no_connector.gds") + import pdb; pdb.set_trace() self.enclosures.append(connector) - - # At this point, the pins are overlapping, but there might be more than one! + + # At this point, the pins are overlapping, + # but there might be more than one! overlap_set = set() for pin in self.pins: overlap_set.update(self.transitive_overlap(pin, self.enclosures)) - # Use the new enclosures and recompute the grids that correspond to them - if len(overlap_set)0: - debug.info(2,"Removing pins {}".format(shared_set)) + if len(shared_set) > 0: + debug.info(2, "Removing pins {}".format(shared_set)) pin_set.difference_update(shared_set) shared_set = partial_set & self.router.blocked_grids - if len(shared_set)>0: - debug.info(2,"Removing pins {}".format(shared_set)) + if len(shared_set) > 0: + debug.info(2, "Removing pins {}".format(shared_set)) partial_set.difference_update(shared_set) shared_set = blockage_set & self.router.blocked_grids - if len(shared_set)>0: - debug.info(2,"Removing blocks {}".format(shared_set)) + if len(shared_set) > 0: + debug.info(2, "Removing blocks {}".format(shared_set)) blockage_set.difference_update(shared_set) - + # At least one of the groups must have some valid tracks - if (len(pin_set)==0 and len(partial_set)==0 and len(blockage_set)==0): - #debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) - + if (len(pin_set) == 0 and len(partial_set) == 0 and len(blockage_set) == 0): + # debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) + for pin in self.pins: debug.warning(" Expanding conversion {0}".format(pin)) - # Determine which tracks the pin overlaps - (sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1) + # Determine which tracks the pin overlaps + (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name, + pin, + expansion=1) pin_set.update(sufficient) partial_set.update(insufficient) - - if len(pin_set)==0 and len(partial_set)==0: - debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins)) + + if len(pin_set) == 0 and len(partial_set) == 0: + debug.error("Unable to find unblocked pin {} {}".format(self.name, + self.pins)) self.router.write_debug_gds("blocked_pin.gds") # Consider all the grids that would be blocked - self.grids = pin_set | partial_set - # Remember the secondary grids for removing adjacent pins - self.secondary_grids = partial_set + self.grids = pin_set | partial_set + if len(self.grids) < 0: + debug.error("Did not find any unblocked grids: {}".format(str(self.pins))) + self.router.write_debug_gds("blocked_pin.gds") + + # Remember the secondary grids for removing adjacent pins + self.secondary_grids = partial_set - debug.info(2," pins {}".format(self.grids)) - debug.info(2," secondary {}".format(self.secondary_grids)) - - - + debug.info(2, " pins {}".format(self.grids)) + debug.info(2, " secondary {}".format(self.secondary_grids)) diff --git a/compiler/router/router.py b/compiler/router/router.py index fd95def6..cacd5117 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -5,9 +5,9 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import sys + import gdsMill -from tech import drc,GDS +from tech import drc, GDS from tech import layer as techlayer import math import debug @@ -15,23 +15,23 @@ from router_tech import router_tech from pin_layout import pin_layout from pin_group import pin_group from vector import vector -from vector3d import vector3d -from globals import OPTS,print_time -from pprint import pformat +from vector3d import vector3d +from globals import OPTS, print_time import grid_utils from datetime import datetime + class router(router_tech): """ A router class to read an obstruction map from a gds and plan a route on a given layer. This is limited to two layer routes. It populates blockages on a grid class. """ - def __init__(self, layers, design, gds_filename=None, rail_track_width=1): """ This will instantiate a copy of the gds file or the module at (0,0) and - route on top of this. The blockages from the gds/module will be considered. + route on top of this. The blockages from the gds/module will be + considered. """ router_tech.__init__(self, layers, rail_track_width) @@ -39,7 +39,7 @@ class router(router_tech): # If didn't specify a gds blockage file, write it out to read the gds # This isn't efficient, but easy for now - #start_time = datetime.now() + # start_time = datetime.now() if not gds_filename: gds_filename = OPTS.openram_temp+"temp.gds" self.cell.gds_write(gds_filename) @@ -49,36 +49,41 @@ class router(router_tech): self.reader = gdsMill.Gds2reader(self.layout) self.reader.loadFromFile(gds_filename) self.top_name = self.layout.rootStructureName - #print_time("GDS read",datetime.now(), start_time) + # print_time("GDS read",datetime.now(), start_time) - ### The pin data structures + # The pin data structures # A map of pin names to a set of pin_layout structures # (i.e. pins with a given label) self.pins = {} - # This is a set of all pins (ignoring names) so that can quickly not create blockages for pins - # (They will be blocked when we are routing other nets based on their name.) + # This is a set of all pins (ignoring names) so that can quickly + # not create blockages for pins + # (They will be blocked when we are routing other + # nets based on their name.) self.all_pins = set() - # The labeled pins above categorized into pin groups that are touching/connected. + # The labeled pins above categorized into pin groups + # that are touching/connected. self.pin_groups = {} - ### The blockage data structures - # A list of metal shapes (using the same pin_layout structure) that are not pins but blockages. - self.blockages=[] + # The blockage data structures + # A list of metal shapes (using the same pin_layout structure) + # that are not pins but blockages. + self.blockages = [] # The corresponding set of blocked grids for above pin shapes self.blocked_grids = set() - ### The routed data structures + # The routed data structures # A list of paths that have been "routed" self.paths = [] # A list of path blockages (they might be expanded for wide metal DRC) self.path_blockages = [] - # The boundary will determine the limits to the size of the routing grid + # The boundary will determine the limits to the size + # of the routing grid self.boundary = self.layout.measureBoundary(self.top_name) # These must be un-indexed to get rid of the matrix type self.ll = vector(self.boundary[0][0], self.boundary[0][1]) - self.ur = vector(self.boundary[1][0], self.boundary[1][1]) + self.ur = vector(self.boundary[1][0], self.boundary[1][1]) def clear_pins(self): """ @@ -87,93 +92,93 @@ class router(router_tech): """ self.pins = {} self.all_pins = set() - self.pin_groups = {} + self.pin_groups = {} # DO NOT clear the blockages as these don't change self.rg.reinit() - - def set_top(self,top_name): + def set_top(self, top_name): """ If we want to route something besides the top-level cell.""" self.top_name = top_name - - def is_wave(self,path): + def is_wave(self, path): """ - Determines if this is a multi-track width wave (True) or a normal route (False) + Determines if this is a multi-track width wave (True) + # or a normal route (False) """ - return len(path[0])>1 + return len(path[0]) > 1 - - def retrieve_pins(self,pin_name): + def retrieve_pins(self, pin_name): """ Retrieve the pin shapes on metal 3 from the layout. """ - debug.info(2,"Retrieving pins for {}.".format(pin_name)) - shape_list=self.layout.getAllPinShapes(str(pin_name)) + debug.info(2, "Retrieving pins for {}.".format(pin_name)) + shape_list = self.layout.getAllPinShapes(str(pin_name)) pin_set = set() for shape in shape_list: - (layer,boundary)=shape + (layer, boundary) = shape # GDSMill boundaries are in (left, bottom, right, top) order # so repack and snap to the grid - ll = vector(boundary[0],boundary[1]).snap_to_grid() - ur = vector(boundary[2],boundary[3]).snap_to_grid() - rect = [ll,ur] + ll = vector(boundary[0], boundary[1]).snap_to_grid() + ur = vector(boundary[2], boundary[3]).snap_to_grid() + rect = [ll, ur] pin = pin_layout(pin_name, rect, layer) pin_set.add(pin) - debug.check(len(pin_set)>0,"Did not find any pin shapes for {0}.".format(str(pin_name))) + debug.check(len(pin_set) > 0, + "Did not find any pin shapes for {0}.".format(str(pin_name))) self.pins[pin_name] = pin_set self.all_pins.update(pin_set) for pin in self.pins[pin_name]: - debug.info(3,"Retrieved pin {}".format(str(pin))) - + debug.info(3, "Retrieved pin {}".format(str(pin))) def find_blockages(self): """ Iterate through all the layers and write the obstacles to the routing grid. - This doesn't consider whether the obstacles will be pins or not. They get reset later - if they are not actually a blockage. + This doesn't consider whether the obstacles will be pins or not. + They get reset later if they are not actually a blockage. """ - debug.info(1,"Finding blockages.") - for layer in [self.vert_layer_number,self.horiz_layer_number]: - self.retrieve_blockages(layer) + debug.info(1, "Finding blockages.") + for lpp in [self.vert_lpp, self.horiz_lpp]: + self.retrieve_blockages(lpp) def find_pins_and_blockages(self, pin_list): """ - Find the pins and blockages in the design + Find the pins and blockages in the design """ - # This finds the pin shapes and sorts them into "groups" that are connected - # This must come before the blockages, so we can not count the pins themselves + # This finds the pin shapes and sorts them into "groups" that + # are connected. This must come before the blockages, so we + # can not count the pins themselves # as blockages. start_time = datetime.now() for pin_name in pin_list: self.retrieve_pins(pin_name) - print_time("Retrieving pins",datetime.now(), start_time, 4) + print_time("Retrieving pins", datetime.now(), start_time, 4) start_time = datetime.now() for pin_name in pin_list: self.analyze_pins(pin_name) - print_time("Analyzing pins",datetime.now(), start_time, 4) + print_time("Analyzing pins", datetime.now(), start_time, 4) # This will get all shapes as blockages and convert to grid units # This ignores shapes that were pins start_time = datetime.now() self.find_blockages() - print_time("Finding blockages",datetime.now(), start_time, 4) + print_time("Finding blockages", datetime.now(), start_time, 4) # Convert the blockages to grid units start_time = datetime.now() self.convert_blockages() - print_time("Converting blockages",datetime.now(), start_time, 4) + print_time("Converting blockages", datetime.now(), start_time, 4) # This will convert the pins to grid units - # It must be done after blockages to ensure no DRCs between expanded pins and blocked grids + # It must be done after blockages to ensure no DRCs + # between expanded pins and blocked grids start_time = datetime.now() for pin in pin_list: self.convert_pins(pin) - print_time("Converting pins",datetime.now(), start_time, 4) + print_time("Converting pins", datetime.now(), start_time, 4) # Combine adjacent pins into pin groups to reduce run-time # by reducing the number of maze routes. @@ -184,17 +189,18 @@ class router(router_tech): # print_time("Combining adjacent pins",datetime.now(), start_time, 4) - # Separate any adjacent grids of differing net names that overlap + # Separate any adjacent grids of differing net names + # that overlap # Must be done before enclosing pins start_time = datetime.now() self.separate_adjacent_pins(0) - print_time("Separating adjacent pins",datetime.now(), start_time, 4) + print_time("Separating adjacent pins", datetime.now(), start_time, 4) - # Enclose the continguous grid units in a metal rectangle to fix some DRCs + # Enclose the continguous grid units in a metal + # rectangle to fix some DRCs start_time = datetime.now() self.enclose_pins() - print_time("Enclosing pins",datetime.now(), start_time, 4) - + print_time("Enclosing pins", datetime.now(), start_time, 4) # MRG: Removing this code for now. The later compute enclosure code # assumes that all pins are touching and this may produce sets of pins @@ -249,57 +255,63 @@ class router(router_tech): # # Use the new pin group! # self.pin_groups[pin_name] = new_pin_groups # removed_pairs = old_size - len(new_pin_groups) - # debug.info(1, "Combined {0} pin groups for {1}".format(removed_pairs,pin_name)) + # debug.info(1, + # "Combined {0} pin groups for {1}".format(removed_pairs,pin_name)) # return removed_pairs - def separate_adjacent_pins(self, separation): """ - This will try to separate all grid pins by the supplied number of separation - tracks (default is to prevent adjacency). + This will try to separate all grid pins by the supplied + number of separation tracks (default is to prevent adjacency). """ # Commented out to debug with SCMOS - #if separation==0: - # return + # if separation==0: + # return pin_names = self.pin_groups.keys() - for i,pin_name1 in enumerate(pin_names): - for j,pin_name2 in enumerate(pin_names): - if i==j: + for i, pin_name1 in enumerate(pin_names): + for j, pin_name2 in enumerate(pin_names): + if i == j: continue - if i>j: + if i > j: return self.separate_adjacent_pin(pin_name1, pin_name2, separation) def separate_adjacent_pin(self, pin_name1, pin_name2, separation): """ - Go through all of the pin groups and check if any other pin group is + Go through all of the pin groups and check if any other pin group is within a separation of it. If so, reduce the pin group grid to not include the adjacent grid. Try to do this intelligently to keep th pins enclosed. """ - debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2)) + debug.info(1, + "Comparing {0} and {1} adjacency".format(pin_name1, + pin_name2)) removed_grids = 0 - for index1,pg1 in enumerate(self.pin_groups[pin_name1]): - for index2,pg2 in enumerate(self.pin_groups[pin_name2]): + for index1, pg1 in enumerate(self.pin_groups[pin_name1]): + for index2, pg2 in enumerate(self.pin_groups[pin_name2]): adj_grids = pg1.adjacent_grids(pg2, separation) removed_grids += len(adj_grids) # These should have the same length, so... - if len(adj_grids)>0: - debug.info(3,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids)) + if len(adj_grids) > 0: + debug.info(3, + "Adjacent grids {0} {1} adj={2}".format(index1, + index2, + adj_grids)) self.remove_adjacent_grid(pg1, pg2, adj_grids) - debug.info(1,"Removed {} adjacent grids.".format(removed_grids)) + debug.info(1, "Removed {} adjacent grids.".format(removed_grids)) def remove_adjacent_grid(self, pg1, pg2, adj_grids): """ Remove one of the adjacent grids in a heuristic manner. - This will try to keep the groups similar sized by removing from the bigger group. + This will try to keep the groups similar sized by + removing from the bigger group. """ - if pg1.size()>pg2.size(): + if pg1.size() > pg2.size(): bigger = pg1 smaller = pg2 else: @@ -309,54 +321,58 @@ class router(router_tech): for adj in adj_grids: - # If the adjacent grids are a subset of the secondary grids (i.e. not necessary) - # remove them from each + # If the adjacent grids are a subset of the secondary + # grids (i.e. not necessary) remove them from each if adj in bigger.secondary_grids: - debug.info(3,"Removing {} from bigger secondary {}".format(adj, bigger)) + debug.info(3,"Removing {} from bigger secondary {}".format(adj, + bigger)) bigger.grids.remove(adj) bigger.secondary_grids.remove(adj) self.blocked_grids.add(adj) elif adj in smaller.secondary_grids: - debug.info(3,"Removing {} from smaller secondary {}".format(adj, smaller)) + debug.info(3,"Removing {} from smaller secondary {}".format(adj, + smaller)) smaller.grids.remove(adj) smaller.secondary_grids.remove(adj) self.blocked_grids.add(adj) else: - # If we couldn't remove from a secondary grid, we must remove from the primary + # If we couldn't remove from a secondary grid, + # we must remove from the primary # grid of at least one pin if adj in bigger.grids: - debug.info(3,"Removing {} from bigger primary {}".format(adj, bigger)) + debug.info(3,"Removing {} from bigger primary {}".format(adj, + bigger)) bigger.grids.remove(adj) elif adj in smaller.grids: - debug.info(3,"Removing {} from smaller primary {}".format(adj, smaller)) + debug.info(3,"Removing {} from smaller primary {}".format(adj, + smaller)) smaller.grids.remove(adj) - - - def prepare_blockages(self, pin_name): """ Reset and add all of the blockages in the design. Names is a list of pins to add as a blockage. """ - debug.info(3,"Preparing blockages.") + debug.info(3, "Preparing blockages.") # Start fresh. Not the best for run-time, but simpler. self.clear_blockages() # This adds the initial blockges of the design - #print("BLOCKING:",self.blocked_grids) - self.set_blockages(self.blocked_grids,True) + #print("BLOCKING:", self.blocked_grids) + self.set_blockages(self.blocked_grids, True) - # Block all of the supply rails (some will be unblocked if they're a target) + # Block all of the supply rails + # (some will be unblocked if they're a target) self.set_supply_rail_blocked(True) - # Block all of the pin components (some will be unblocked if they're a source/target) + # Block all of the pin components + # (some will be unblocked if they're a source/target) # Also block the previous routes for name in self.pin_groups: blockage_grids = {y for x in self.pin_groups[name] for y in x.grids} - self.set_blockages(blockage_grids,True) + self.set_blockages(blockage_grids, True) blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages} - self.set_blockages(blockage_grids,True) + self.set_blockages(blockage_grids, True) # FIXME: These duplicate a bit of work # These are the paths that have already been routed. @@ -366,22 +382,20 @@ class router(router_tech): # directly to a rail, but unblock all the source components so we can # route over them blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids} - self.set_blockages(blockage_grids,False) - + self.set_blockages(blockage_grids, False) def convert_shape_to_units(self, shape): - """ - Scale a shape (two vector list) to user units + """ + Scale a shape (two vector list) to user units """ unit_factor = [GDS["unit"][0]] * 2 - ll=shape[0].scale(unit_factor) - ur=shape[1].scale(unit_factor) - return [ll,ur] - + ll = shape[0].scale(unit_factor) + ur = shape[1].scale(unit_factor) + return [ll, ur] def min_max_coord(self, coord): - """ - Find the lowest and highest corner of a Rectangle + """ + Find the lowest and highest corner of a Rectangle """ coordinate = [] minx = min(coord[0][0], coord[1][0], coord[2][0], coord[3][0]) @@ -392,24 +406,24 @@ class router(router_tech): coordinate += [vector(maxx, maxy)] return coordinate - def get_inertia(self,p0,p1): - """ - Sets the direction based on the previous direction we came from. + def get_inertia(self, p0, p1): + """ + Sets the direction based on the previous direction we came from. """ # direction (index) of movement - if p0.x!=p1.x: + if p0.x != p1.x: return 0 - elif p0.y!=p1.y: + elif p0.y != p1.y: return 1 else: # z direction return 2 def clear_blockages(self): - """ + """ Clear all blockages on the grid. """ - debug.info(3,"Clearing all blockages") + debug.info(3, "Clearing all blockages") self.rg.clear_blockages() def set_blockages(self, blockages, value=True): @@ -417,137 +431,142 @@ class router(router_tech): self.rg.set_blocked(blockages, value) def get_blockage_tracks(self, ll, ur, z): - debug.info(3,"Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) + debug.info(3, "Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) block_list = [] - for x in range(int(ll[0]),int(ur[0])+1): - for y in range(int(ll[1]),int(ur[1])+1): - block_list.append(vector3d(x,y,z)) + for x in range(int(ll[0]), int(ur[0])+1): + for y in range(int(ll[1]), int(ur[1])+1): + block_list.append(vector3d(x, y, z)) return set(block_list) def convert_blockage(self, blockage): - """ - Convert a pin layout blockage shape to routing grid tracks. + """ + Convert a pin layout blockage shape to routing grid tracks. """ # Inflate the blockage by half a spacing rule - [ll,ur]=self.convert_blockage_to_tracks(blockage.inflate()) - zlayer = self.get_zindex(blockage.layer_num) + [ll, ur] = self.convert_blockage_to_tracks(blockage.inflate()) + zlayer = self.get_zindex(blockage.lpp) blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer) return blockage_tracks def convert_blockages(self): """ Convert blockages to grid tracks. """ - debug.info(1,"Converting blockages.") + debug.info(1, "Converting blockages.") for blockage in self.blockages: - debug.info(3,"Converting blockage {}".format(str(blockage))) + debug.info(3, "Converting blockage {}".format(str(blockage))) blockage_list = self.convert_blockage(blockage) self.blocked_grids.update(blockage_list) - - def retrieve_blockages(self, layer_num): + def retrieve_blockages(self, lpp): """ Recursive find boundaries as blockages to the routing grid. """ - shapes = self.layout.getAllShapes(layer_num) + shapes = self.layout.getAllShapes(lpp) for boundary in shapes: - ll = vector(boundary[0],boundary[1]) - ur = vector(boundary[2],boundary[3]) - rect = [ll,ur] - new_pin = pin_layout("blockage{}".format(len(self.blockages)),rect,layer_num) + ll = vector(boundary[0], boundary[1]) + ur = vector(boundary[2], boundary[3]) + rect = [ll, ur] + new_pin = pin_layout("blockage{}".format(len(self.blockages)), + rect, + lpp) - # If there is a rectangle that is the same in the pins, it isn't a blockage! + # If there is a rectangle that is the same in the pins, + # it isn't a blockage! if new_pin not in self.all_pins: self.blockages.append(new_pin) - def convert_point_to_units(self, p): """ Convert a path set of tracks to center line path. """ pt = vector3d(p) - pt = pt.scale(self.track_widths[0],self.track_widths[1],1) + pt = pt.scale(self.track_widths[0], self.track_widths[1], 1) return pt def convert_wave_to_units(self, wave): - """ - Convert a wave to a set of center points + """ + Convert a wave to a set of center points """ return [self.convert_point_to_units(i) for i in wave] - def convert_blockage_to_tracks(self, shape): - """ + """ Convert a rectangular blockage shape into track units. """ - (ll,ur) = shape + (ll, ur) = shape ll = snap_to_grid(ll) ur = snap_to_grid(ur) # to scale coordinates to tracks - debug.info(3,"Converting [ {0} , {1} ]".format(ll,ur)) - old_ll = ll - old_ur = ur - ll=ll.scale(self.track_factor) - ur=ur.scale(self.track_factor) + debug.info(3, "Converting [ {0} , {1} ]".format(ll, ur)) + ll = ll.scale(self.track_factor) + ur = ur.scale(self.track_factor) # We can round since we are using inflated shapes # and the track points are at the center ll = ll.round() ur = ur.round() - return [ll,ur] + return [ll, ur] def convert_pin_to_tracks(self, pin_name, pin, expansion=0): - """ - Convert a rectangular pin shape into a list of track locations,layers. - If no pins are "on-grid" (i.e. sufficient overlap) it makes the one with most overlap if it is not blocked. - If expansion>0, expamine areas beyond the current pin when it is blocked. """ - (ll,ur) = pin.rect - debug.info(3,"Converting pin [ {0} , {1} ]".format(ll,ur)) + Convert a rectangular pin shape into a list of track locations,layers. + If no pins are "on-grid" (i.e. sufficient overlap) + it makes the one with most overlap if it is not blocked. + If expansion>0, expamine areas beyond the current pin + when it is blocked. + """ + (ll, ur) = pin.rect + debug.info(3, "Converting pin [ {0} , {1} ]".format(ll, ur)) # scale the size bigger to include neaby tracks - ll=ll.scale(self.track_factor).floor() - ur=ur.scale(self.track_factor).ceil() + ll = ll.scale(self.track_factor).floor() + ur = ur.scale(self.track_factor).ceil() # Keep tabs on tracks with sufficient and insufficient overlap sufficient_list = set() insufficient_list = set() - zindex=self.get_zindex(pin.layer_num) - for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion): - for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion): - (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex)) + zindex = self.get_zindex(pin.lpp) + for x in range(int(ll[0]) + expansion, int(ur[0]) + 1 + expansion): + for y in range(int(ll[1] + expansion), int(ur[1]) + 1 + expansion): + (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, + vector3d(x, + y, + zindex)) if full_overlap: sufficient_list.update([full_overlap]) if partial_overlap: insufficient_list.update([partial_overlap]) - debug.info(2,"Converting [ {0} , {1} ] full={2}".format(x,y, full_overlap)) + debug.info(2, + "Converting [ {0} , {1} ] full={2}".format(x, + y, + full_overlap)) # Return all grids with any potential overlap (sufficient or not) - return (sufficient_list,insufficient_list) - + return (sufficient_list, insufficient_list) def get_all_offgrid_pin(self, pin, insufficient_list): - """ + """ Find a list of all pins with some overlap. """ - #print("INSUFFICIENT LIST",insufficient_list) + # print("INSUFFICIENT LIST",insufficient_list) # Find the coordinate with the most overlap any_overlap = set() for coord in insufficient_list: full_pin = self.convert_track_to_pin(coord) # Compute the overlap with that rectangle - overlap_rect=pin.compute_overlap(full_pin) + overlap_rect = pin.compute_overlap(full_pin) # Determine the max x or y overlap max_overlap = max(overlap_rect) - if max_overlap>0: + if max_overlap > 0: any_overlap.update([coord]) return any_overlap def get_best_offgrid_pin(self, pin, insufficient_list): - """ + """ Find a list of the single pin with the most overlap. """ # Find the coordinate with the most overlap @@ -556,17 +575,17 @@ class router(router_tech): for coord in insufficient_list: full_pin = self.convert_track_to_pin(coord) # Compute the overlap with that rectangle - overlap_rect=pin.compute_overlap(full_pin) + overlap_rect = pin.compute_overlap(full_pin) # Determine the min x or y overlap min_overlap = min(overlap_rect) - if min_overlap>best_overlap: - best_overlap=min_overlap - best_coord=coord + if min_overlap > best_overlap: + best_overlap = min_overlap + best_coord = coord return set([best_coord]) def get_furthest_offgrid_pin(self, pin, insufficient_list): - """ + """ Get a grid cell that is the furthest from the blocked grids. """ @@ -575,14 +594,14 @@ class router(router_tech): best_dist = math.inf for coord in insufficient_list: min_dist = grid_utils.distance_set(coord, self.blocked_grids) - if min_dist 0: - debug.info(2," Overlap: {0} >? {1}".format(overlap_length,0)) - return (coord,None) + if overlap_length == math.inf or overlap_length > 0: + debug.info(2," Overlap: {0} >? {1}".format(overlap_length, 0)) + return (coord, None) # If it overlaps with the inflated pin, it is partial - elif inflated_overlap_length==math.inf or inflated_overlap_length > 0: - debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length,0)) - return (None,coord) + elif inflated_overlap_length == math.inf or inflated_overlap_length > 0: + debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length, 0)) + return (None, coord) else: - debug.info(2," No overlap: {0} {1}".format(overlap_length,0)) - return (None,None) - + debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0)) + return (None, None) def convert_track_to_pin(self, track): - """ + """ Convert a grid point into a rectangle shape that is centered track in the track and leaves half a DRC space in each direction. """ - # calculate lower left - x = track.x*self.track_width - 0.5*self.track_width + 0.5*self.track_space - y = track.y*self.track_width - 0.5*self.track_width + 0.5*self.track_space + # calculate lower left + x = track.x * self.track_width - 0.5 * self.track_width + 0.5 * self.track_space + y = track.y * self.track_width - 0.5 * self.track_width + 0.5 * self.track_space ll = snap_to_grid(vector(x,y)) # calculate upper right - x = track.x*self.track_width + 0.5*self.track_width - 0.5*self.track_space - y = track.y*self.track_width + 0.5*self.track_width - 0.5*self.track_space - ur = snap_to_grid(vector(x,y)) + x = track.x * self.track_width + 0.5 * self.track_width - 0.5 * self.track_space + y = track.y * self.track_width + 0.5 * self.track_width - 0.5 * self.track_space + ur = snap_to_grid(vector(x, y)) p = pin_layout("", [ll, ur], self.get_layer(track[2])) return p def convert_track_to_shape_pin(self, track): - """ - Convert a grid point into a rectangle shape that occupies the entire centered - track. + """ + Convert a grid point into a rectangle shape + that occupies the entire centered track. """ # to scale coordinates to tracks x = track[0]*self.track_width - 0.5*self.track_width y = track[1]*self.track_width - 0.5*self.track_width # offset lowest corner object to to (-track halo,-track halo) - ll = snap_to_grid(vector(x,y)) - ur = snap_to_grid(ll + vector(self.track_width,self.track_width)) + ll = snap_to_grid(vector(x, y)) + ur = snap_to_grid(ll + vector(self.track_width, self.track_width)) p = pin_layout("", [ll, ur], self.get_layer(track[2])) return p def convert_track_to_shape(self, track): - """ - Convert a grid point into a rectangle shape that occupies the entire centered - track. + """ + Convert a grid point into a rectangle shape + that occupies the entire centered track. """ # to scale coordinates to tracks try: x = track[0]*self.track_width - 0.5*self.track_width except TypeError: - print(track[0],type(track[0]),self.track_width,type(self.track_width)) + print(track[0], type(track[0]), self.track_width, type(self.track_width)) y = track[1]*self.track_width - 0.5*self.track_width # offset lowest corner object to to (-track halo,-track halo) - ll = snap_to_grid(vector(x,y)) - ur = snap_to_grid(ll + vector(self.track_width,self.track_width)) + ll = snap_to_grid(vector(x, y)) + ur = snap_to_grid(ll + vector(self.track_width, self.track_width)) - return [ll,ur] + return [ll, ur] def convert_track_to_inflated_pin(self, track): - """ - Convert a grid point into a rectangle shape that is inflated by a half DRC space. """ - # calculate lower left + Convert a grid point into a rectangle shape + that is inflated by a half DRC space. + """ + # calculate lower left x = track.x*self.track_width - 0.5*self.track_width - 0.5*self.track_space y = track.y*self.track_width - 0.5*self.track_width - 0.5*self.track_space ll = snap_to_grid(vector(x,y)) @@ -691,16 +717,17 @@ class router(router_tech): # calculate upper right x = track.x*self.track_width + 0.5*self.track_width + 0.5*self.track_space y = track.y*self.track_width + 0.5*self.track_width + 0.5*self.track_space - ur = snap_to_grid(vector(x,y)) + ur = snap_to_grid(vector(x, y)) p = pin_layout("", [ll, ur], self.get_layer(track[2])) return p def analyze_pins(self, pin_name): - """ - Analyze the shapes of a pin and combine them into pin_groups which are connected. """ - debug.info(2,"Analyzing pin groups for {}.".format(pin_name)) + Analyze the shapes of a pin and combine + them into pin_groups which are connected. + """ + debug.info(2, "Analyzing pin groups for {}.".format(pin_name)) pin_set = self.pins[pin_name] # This will be a list of pin tuples that overlap @@ -713,8 +740,8 @@ class router(router_tech): y_coordinates.sort(key=lambda x: x[0]) # Map the pins to the lower indices - bottom_index_map = {x[1]:i for i,x in enumerate(y_coordinates) if x[2]=="bottom"} - top_index_map = {x[1]:i for i,x in enumerate(y_coordinates) if x[2]=="bottom"} + bottom_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"} + # top_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"} # Sort the pin list by x coordinate pin_list = list(pin_set) @@ -725,10 +752,10 @@ class router(router_tech): # start at pin's lower y coordinate bottom_index = bottom_index_map[pin] compared_pins = set() - for i in range(bottom_index,len(y_coordinates)): + for i in range(bottom_index, len(y_coordinates)): compare_pin = y_coordinates[i][1] # Don't overlap yourself - if pin==compare_pin: + if pin == compare_pin: continue # Done when we encounter any shape above the pin if compare_pin.by() > pin.uy(): @@ -739,7 +766,7 @@ class router(router_tech): compared_pins.add(compare_pin) # If we overlap, add them to the list if pin.overlaps(compare_pin): - overlap_list.append((pin,compare_pin)) + overlap_list.append((pin, compare_pin)) # Initial unique group assignments group_id = {} @@ -749,48 +776,46 @@ class router(router_tech): gid += 1 for p in overlap_list: - (p1,p2) = p + (p1, p2) = p for pin in pin_list: if group_id[pin] == group_id[p2]: group_id[pin] = group_id[p1] - # For each pin add it to it's group group_map = {} for pin in pin_list: gid = group_id[pin] if gid not in group_map: - group_map[gid] = pin_group(name=pin_name, pin_set=[], router=self) + group_map[gid] = pin_group(name=pin_name, + pin_set=[], + router=self) # We always add it to the first set since they are touching group_map[gid].pins.add(pin) self.pin_groups[pin_name] = list(group_map.values()) - def convert_pins(self, pin_name): - """ + """ Convert the pin groups into pin tracks and blockage tracks. """ - debug.info(1,"Converting pins for {}.".format(pin_name)) + debug.info(1, "Converting pins for {}.".format(pin_name)) for pg in self.pin_groups[pin_name]: pg.convert_pin() - - def enclose_pins(self): """ This will find the biggest rectangle enclosing some grid squares and - put a rectangle over it. It does not enclose grid squares that are blocked - by other shapes. + put a rectangle over it. It does not enclose grid squares + that are blocked by other shapes. """ for pin_name in self.pin_groups: - debug.info(1,"Enclosing pins for {}".format(pin_name)) + debug.info(1, "Enclosing pins for {}".format(pin_name)) for pg in self.pin_groups[pin_name]: pg.enclose_pin() pg.add_enclosure(self.cell) def add_source(self, pin_name): - """ + """ This will mark the grids for all pin components as a source. Marking as source or target also clears blockage status. """ @@ -798,7 +823,7 @@ class router(router_tech): self.add_pin_component_source(pin_name, i) def add_target(self, pin_name): - """ + """ This will mark the grids for all pin components as a target. Marking as source or target also clears blockage status. """ @@ -806,44 +831,46 @@ class router(router_tech): self.add_pin_component_target(pin_name, i) def num_pin_components(self, pin_name): - """ + """ This returns how many disconnected pin components there are. """ return len(self.pin_groups[pin_name]) def add_pin_component_source(self, pin_name, index): - """ - This will mark only the pin tracks from the indexed pin component as a source. + """ + This will mark only the pin tracks + from the indexed pin component as a source. It also unsets it as a blockage. """ - debug.check(index1: + if len(self.layers) > 1: self.cell.add_route(layers=self.layers, coordinates=abs_path, layer_widths=self.layer_widths) @@ -908,83 +934,81 @@ class router(router_tech): def add_single_enclosure(self, track): """ - Add a metal enclosure that is the size of the routing grid minus a spacing on each side. + Add a metal enclosure that is the size of + the routing grid minus a spacing on each side. """ pin = self.convert_track_to_pin(track) - (ll,ur) = pin.rect + (ll, ur) = pin.rect self.cell.add_rect(layer=self.get_layer(track.z), offset=ll, width=ur.x-ll.x, height=ur.y-ll.y) - - - def add_via(self,loc,size=1): - """ + def add_via(self, loc, size=1): + """ Add a via centered at the current location """ - loc = self.convert_point_to_units(vector3d(loc[0],loc[1],0)) + loc = self.convert_point_to_units(vector3d(loc[0], loc[1], 0)) self.cell.add_via_center(layers=self.layers, - offset=vector(loc.x,loc.y), - size=(size,size)) + offset=vector(loc.x, loc.y), + size=(size, size)) def compute_pin_enclosure(self, ll, ur, zindex, name=""): """ Enclose the tracks from ll to ur in a single rectangle that meets - the track DRC rules. + the track DRC rules. """ layer = self.get_layer(zindex) - # This finds the pin shape enclosed by the track with DRC spacing on the sides + # This finds the pin shape enclosed by the + # track with DRC spacing on the sides pin = self.convert_track_to_pin(ll) - (abs_ll,unused) = pin.rect + (abs_ll, unused) = pin.rect pin = self.convert_track_to_pin(ur) - (unused,abs_ur) = pin.rect + (unused, abs_ur) = pin.rect pin = pin_layout(name, [abs_ll, abs_ur], layer) return pin - def contract_path(self,path): - """ + def contract_path(self, path): + """ Remove intermediate points in a rectilinear path or a wave. """ # Waves are always linear, so just return the first and last. if self.is_wave(path): - return [path[0],path[-1]] + return [path[0], path[-1]] # Make a list only of points that change inertia of the path newpath = [path[0]] - for i in range(1,len(path)-1): - prev_inertia=self.get_inertia(path[i-1][0],path[i][0]) - next_inertia=self.get_inertia(path[i][0],path[i+1][0]) + for i in range(1, len(path) - 1): + prev_inertia = self.get_inertia(path[i-1][0], path[i][0]) + next_inertia = self.get_inertia(path[i][0], path[i+1][0]) # if we switch directions, add the point, otherwise don't - if prev_inertia!=next_inertia: + if prev_inertia != next_inertia: newpath.append(path[i]) # always add the last path unless it was a single point - if len(path)>1: + if len(path) > 1: newpath.append(path[-1]) return newpath - - def run_router(self, detour_scale): """ - This assumes the blockages, source, and target are all set up. + This assumes the blockages, source, and target are all set up. """ # Double check source and taget are not same node, if so, we are done! - for k,v in self.rg.map.items(): + for k, v in self.rg.map.items(): if v.source and v.target: debug.error("Grid cell is source and target! {}".format(k)) return False # returns the path in tracks - (path,cost) = self.rg.route(detour_scale) + (path, cost) = self.rg.route(detour_scale) if path: - debug.info(1,"Found path: cost={0} ".format(cost)) - debug.info(1,str(path)) + debug.info(1, "Found path: cost={0} ".format(cost)) + debug.info(1, str(path)) self.paths.append(path) self.add_route(path) @@ -998,34 +1022,34 @@ class router(router_tech): return False return True - def annotate_pin_and_tracks(self, pin, tracks): """" Annotate some shapes for debug purposes """ - debug.info(0,"Annotating\n pin {0}\n tracks {1}".format(pin,tracks)) + debug.info(0, "Annotating\n pin {0}\n tracks {1}".format(pin, tracks)) for coord in tracks: - (ll,ur) = self.convert_track_to_shape(coord) + (ll, ur) = self.convert_track_to_shape(coord) self.cell.add_rect(layer="text", offset=ll, width=ur[0]-ll[0], height=ur[1]-ll[1]) - (ll,ur) = self.convert_track_to_pin(coord).rect + (ll, ur) = self.convert_track_to_pin(coord).rect self.cell.add_rect(layer="boundary", offset=ll, width=ur[0]-ll[0], height=ur[1]-ll[1]) - (ll,ur) = pin.rect + (ll, ur) = pin.rect self.cell.add_rect(layer="text", offset=ll, width=ur[0]-ll[0], height=ur[1]-ll[1]) def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True): - """ - Write out a GDS file with the routing grid and search information annotated on it. """ - debug.info(0,"Writing annotated router gds file to {}".format(gds_name)) + Write out a GDS file with the routing grid and + search information annotated on it. + """ + debug.info(0, "Writing annotated router gds file to {}".format(gds_name)) self.del_router_info() self.add_router_info() self.cell.gds_write(gds_name) @@ -1039,41 +1063,41 @@ class router(router_tech): Display grid information in the GDS file for a single grid cell. """ shape = self.convert_track_to_shape(g) - partial_track=vector(0,self.track_width/6.0) + partial_track = vector(0,self.track_width/6.0) self.cell.add_rect(layer="text", offset=shape[0], width=shape[1].x-shape[0].x, height=shape[1].y-shape[0].y) - t=self.rg.map[g].get_type() + t = self.rg.map[g].get_type() # midpoint offset - off=vector((shape[1].x+shape[0].x)/2, + off = vector((shape[1].x+shape[0].x)/2, (shape[1].y+shape[0].y)/2) - if t!=None: - if g[2]==1: + if t != None: + if g[2] == 1: # Upper layer is upper right label - type_off=off+partial_track + type_off = off + partial_track else: # Lower layer is lower left label - type_off=off-partial_track + type_off = off - partial_track self.cell.add_label(text=str(t), layer="text", offset=type_off) - t=self.rg.map[g].get_cost() - partial_track=vector(self.track_width/6.0,0) - if t!=None: - if g[2]==1: + t = self.rg.map[g].get_cost() + partial_track = vector(self.track_width/6.0, 0) + if t: + if g[2] == 1: # Upper layer is right label - type_off=off+partial_track + type_off = off + partial_track else: # Lower layer is left label - type_off=off-partial_track + type_off = off - partial_track self.cell.add_label(text=str(t), layer="text", offset=type_off) - self.cell.add_label(text="{0},{1}".format(g[0],g[1]), + self.cell.add_label(text="{0},{1}".format(g[0], g[1]), layer="text", offset=shape[0], zoom=0.05) @@ -1082,18 +1106,17 @@ class router(router_tech): """ Erase all of the comments on the current level. """ - debug.info(0,"Erasing router info") + debug.info(0, "Erasing router info") layer_num = techlayer["text"] self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num] - def add_router_info(self): """ - Write the routing grid and router cost, blockage, pins on - the boundary layer for debugging purposes. This can only be + Write the routing grid and router cost, blockage, pins on + the boundary layer for debugging purposes. This can only be called once or the labels will overlap. """ - debug.info(0,"Adding router info") + debug.info(0, "Adding router info") show_blockages = False show_blockage_grids = False @@ -1108,14 +1131,14 @@ class router(router_tech): if show_blockages: # Display the inflated blockage for blockage in self.blockages: - debug.info(1,"Adding {}".format(blockage)) - (ll,ur) = blockage.inflate() + debug.info(1, "Adding {}".format(blockage)) + (ll, ur) = blockage.inflate() self.cell.add_rect(layer="text", offset=ll, width=ur.x-ll.x, height=ur.y-ll.y) if show_blockage_grids: - self.set_blockages(self.blocked_grids,True) + self.set_blockages(self.blocked_grids, True) for g in self.rg.map: self.annotate_grid(g) @@ -1125,22 +1148,27 @@ class router(router_tech): if not pg.enclosed: continue for pin in pg.enclosures: - #print("enclosure: ",pin.name,pin.ll(),pin.width(),pin.height()) + # print("enclosure: ", + # pin.name, + # pin.ll(), + # pin.width(), + # pin.height()) self.cell.add_rect(layer="text", offset=pin.ll(), width=pin.width(), height=pin.height()) - -# FIXME: This should be replaced with vector.snap_to_grid at some point + +# FIXME: This should be replaced with vector.snap_to_grid at some point def snap_to_grid(offset): """ Changes the coodrinate to match the grid settings """ xoff = snap_val_to_grid(offset[0]) - yoff = snap_val_to_grid(offset[1]) + yoff = snap_val_to_grid(offset[1]) return vector(xoff, yoff) + def snap_val_to_grid(x): grid = drc("grid") xgrid = int(round(round((x / grid), 2), 0)) diff --git a/compiler/router/router_tech.py b/compiler/router/router_tech.py index 49df06fd..efae2708 100644 --- a/compiler/router/router_tech.py +++ b/compiler/router/router_tech.py @@ -5,13 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from tech import drc,layer +from tech import drc, layer from contact import contact -from pin_group import pin_group from vector import vector import debug import math + class router_tech: """ This is a class to hold the router tech constants. @@ -25,9 +25,9 @@ class router_tech: self.layers = layers self.rail_track_width = rail_track_width - if len(self.layers)==1: + if len(self.layers) == 1: self.horiz_layer_name = self.vert_layer_name = self.layers[0] - self.horiz_layer_number = self.vert_layer_number = layer[self.layers[0]] + self.horiz_lpp = self.vert_lpp = layer[self.layers[0]] (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) @@ -40,8 +40,8 @@ class router_tech: via_connect = contact(self.layers, (1, 1)) max_via_size = max(via_connect.width,via_connect.height) - self.horiz_layer_number = layer[self.horiz_layer_name] - self.vert_layer_number = layer[self.vert_layer_name] + self.horiz_lpp = layer[self.horiz_layer_name] + self.vert_lpp = layer[self.vert_layer_name] (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) @@ -68,8 +68,18 @@ class router_tech: # 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_wire, 1, self.track_wire] - def get_zindex(self,layer_num): - if layer_num==self.horiz_layer_number: + def same_lpp(self, lpp1, lpp2): + """ + Check if the layers and purposes are the same. + Ignore if purpose is a None. + """ + if lpp1[1] == None or lpp2[1] == None: + return lpp1[0] == lpp2[0] + + return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1] + + def get_zindex(self, lpp): + if self.same_lpp(lpp, self.horiz_lpp): return 0 else: return 1 diff --git a/compiler/router/supply_grid_router.py b/compiler/router/supply_grid_router.py index 5ddabc98..881e87b2 100644 --- a/compiler/router/supply_grid_router.py +++ b/compiler/router/supply_grid_router.py @@ -55,7 +55,7 @@ class supply_grid_router(router): self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width) def route(self, vdd_name="vdd", gnd_name="gnd"): - """ + """ Add power supply rails and connect all pins to these rails. """ debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name)) @@ -75,7 +75,6 @@ class supply_grid_router(router): start_time = datetime.now() self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) print_time("Finding pins and blockages",datetime.now(), start_time, 3) - # Add the supply rails in a mesh network and connect H/V with vias start_time = datetime.now() # Block everything diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index c4f41f77..dfde78f7 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -112,7 +112,7 @@ class sram(): # Write the config file start_time = datetime.datetime.now() from shutil import copyfile - copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py') + copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py') debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) print_time("Config", datetime.datetime.now(), start_time) diff --git a/compiler/tests/01_library_drc_test.py b/compiler/tests/01_library_drc_test.py index f8da685b..cfeb4ab2 100755 --- a/compiler/tests/01_library_drc_test.py +++ b/compiler/tests/01_library_drc_test.py @@ -17,7 +17,8 @@ import debug class library_drc_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import verify (gds_dir, gds_files) = setup_files() diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/02_library_lvs_test.py index ad150a2b..5f53753b 100755 --- a/compiler/tests/02_library_lvs_test.py +++ b/compiler/tests/02_library_lvs_test.py @@ -17,7 +17,8 @@ import debug class library_lvs_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import verify (gds_dir, sp_dir, allnames) = setup_files() diff --git a/compiler/tests/03_contact_test.py b/compiler/tests/03_contact_test.py index 3d7254c3..2e3f4f0f 100755 --- a/compiler/tests/03_contact_test.py +++ b/compiler/tests/03_contact_test.py @@ -18,7 +18,8 @@ import debug class contact_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) for layer_stack in [("metal1", "via1", "metal2"), ("poly", "contact", "metal1")]: stack_name = ":".join(map(str, layer_stack)) diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index 21001718..be210c8f 100755 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -17,7 +17,8 @@ import debug class path_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import wire_path import tech import design diff --git a/compiler/tests/03_ptx_1finger_nmos_test.py b/compiler/tests/03_ptx_1finger_nmos_test.py index f436d7d0..ae323d90 100755 --- a/compiler/tests/03_ptx_1finger_nmos_test.py +++ b/compiler/tests/03_ptx_1finger_nmos_test.py @@ -18,7 +18,8 @@ import debug class ptx_1finger_nmos_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import tech debug.info(2, "Checking min size NMOS with 1 finger") diff --git a/compiler/tests/03_ptx_1finger_pmos_test.py b/compiler/tests/03_ptx_1finger_pmos_test.py index ae8078e7..3bf3e293 100755 --- a/compiler/tests/03_ptx_1finger_pmos_test.py +++ b/compiler/tests/03_ptx_1finger_pmos_test.py @@ -18,7 +18,8 @@ import debug class ptx_1finger_pmos_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import tech debug.info(2, "Checking min size PMOS with 1 finger") diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py index c010a948..95700e8f 100755 --- a/compiler/tests/03_ptx_3finger_nmos_test.py +++ b/compiler/tests/03_ptx_3finger_nmos_test.py @@ -18,7 +18,8 @@ import debug class ptx_3finger_nmos_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import tech debug.info(2, "Checking three fingers NMOS") diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py index 85cca9e2..8c09cf9b 100755 --- a/compiler/tests/03_ptx_3finger_pmos_test.py +++ b/compiler/tests/03_ptx_3finger_pmos_test.py @@ -18,7 +18,8 @@ import debug class ptx_3finger_pmos_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import tech debug.info(2, "Checking three fingers PMOS") diff --git a/compiler/tests/03_ptx_4finger_nmos_test.py b/compiler/tests/03_ptx_4finger_nmos_test.py index 4a410d51..da9e438d 100755 --- a/compiler/tests/03_ptx_4finger_nmos_test.py +++ b/compiler/tests/03_ptx_4finger_nmos_test.py @@ -18,7 +18,8 @@ import debug class ptx_4finger_nmos_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import tech debug.info(2, "Checking three fingers NMOS") diff --git a/compiler/tests/03_ptx_4finger_pmos_test.py b/compiler/tests/03_ptx_4finger_pmos_test.py index 34fbaf9f..4fc60d5c 100755 --- a/compiler/tests/03_ptx_4finger_pmos_test.py +++ b/compiler/tests/03_ptx_4finger_pmos_test.py @@ -18,7 +18,8 @@ import debug class ptx_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import tech debug.info(2, "Checking three fingers PMOS") diff --git a/compiler/tests/03_wire_test.py b/compiler/tests/03_wire_test.py index 4ee360ce..2e2db319 100755 --- a/compiler/tests/03_wire_test.py +++ b/compiler/tests/03_wire_test.py @@ -17,7 +17,8 @@ import debug class wire_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import wire import tech import design diff --git a/compiler/tests/04_dummy_pbitcell_test.py b/compiler/tests/04_dummy_pbitcell_test.py index e8e3cc1c..b39e48ea 100755 --- a/compiler/tests/04_dummy_pbitcell_test.py +++ b/compiler/tests/04_dummy_pbitcell_test.py @@ -18,7 +18,8 @@ import debug class replica_pbitcell_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import dummy_pbitcell OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py index 42045b43..f7e5f304 100755 --- a/compiler/tests/04_pand2_test.py +++ b/compiler/tests/04_pand2_test.py @@ -18,7 +18,8 @@ import debug class pand2_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) global verify import verify diff --git a/compiler/tests/04_pand3_test.py b/compiler/tests/04_pand3_test.py index 4408f6e8..e58f1ee9 100755 --- a/compiler/tests/04_pand3_test.py +++ b/compiler/tests/04_pand3_test.py @@ -18,7 +18,8 @@ import debug class pand3_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) global verify import verify diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index 0f14c4c5..450c0263 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -19,7 +19,8 @@ from sram_factory import factory class pbitcell_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.num_rw_ports=1 OPTS.num_w_ports=1 diff --git a/compiler/tests/04_pbuf_test.py b/compiler/tests/04_pbuf_test.py index 35db8ccf..ffd06962 100755 --- a/compiler/tests/04_pbuf_test.py +++ b/compiler/tests/04_pbuf_test.py @@ -18,7 +18,8 @@ import debug class pbuf_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing inverter/buffer 4x 8x") a = factory.create(module_type="pbuf", size=8) diff --git a/compiler/tests/04_pdriver_test.py b/compiler/tests/04_pdriver_test.py index abaab4a0..e65b6fad 100755 --- a/compiler/tests/04_pdriver_test.py +++ b/compiler/tests/04_pdriver_test.py @@ -18,7 +18,8 @@ import debug class pdriver_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing inverter/buffer 4x 8x") # a tests the error message for specifying conflicting conditions diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py index 2ccce34a..ae3f480b 100755 --- a/compiler/tests/04_pinv_10x_test.py +++ b/compiler/tests/04_pinv_10x_test.py @@ -18,7 +18,8 @@ import debug class pinv_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Checking 8x inverter") tx = factory.create(module_type="pinv", size=8) diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py index 2f96020c..0b8c055a 100755 --- a/compiler/tests/04_pinv_1x_beta_test.py +++ b/compiler/tests/04_pinv_1x_beta_test.py @@ -18,7 +18,8 @@ import debug class pinv_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Checking 1x beta=3 size inverter") tx = factory.create(module_type="pinv", size=1, beta=3) diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py index 9b0f1bc6..e6c0bff2 100755 --- a/compiler/tests/04_pinv_1x_test.py +++ b/compiler/tests/04_pinv_1x_test.py @@ -18,7 +18,8 @@ import debug class pinv_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Checking 1x size inverter") tx = factory.create(module_type="pinv", size=1) diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py index d8a7598f..0a0e63ec 100755 --- a/compiler/tests/04_pinv_2x_test.py +++ b/compiler/tests/04_pinv_2x_test.py @@ -18,7 +18,8 @@ import debug class pinv_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Checking 2x size inverter") tx = factory.create(module_type="pinv", size=2) diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py index 86af0708..df7645d1 100755 --- a/compiler/tests/04_pinvbuf_test.py +++ b/compiler/tests/04_pinvbuf_test.py @@ -18,7 +18,8 @@ import debug class pinvbuf_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing inverter/buffer 4x 8x") a = factory.create(module_type="pinvbuf", size=8) diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index bc066cfc..f939738a 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -18,7 +18,8 @@ import debug class pnand2_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Checking 2-input nand gate") tx = factory.create(module_type="pnand2", size=1) diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index 8bf5098f..f1af19ac 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -18,7 +18,8 @@ import debug class pnand3_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Checking 3-input nand gate") tx = factory.create(module_type="pnand3", size=1) diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index 0e524506..ea0d6dbc 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -18,7 +18,8 @@ import debug class pnor2_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Checking 2-input nor gate") tx = factory.create(module_type="pnor2", size=1) diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 9b2addd5..1c12ad8b 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -18,7 +18,8 @@ import debug class precharge_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check precharge in single port debug.info(2, "Checking precharge for handmade bitcell") diff --git a/compiler/tests/04_pwrite_driver_test.py b/compiler/tests/04_pwrite_driver_test.py new file mode 100644 index 00000000..5e1bf621 --- /dev/null +++ b/compiler/tests/04_pwrite_driver_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import header, openram_test +import sys +import os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +@unittest.skip("SKIPPING 04_pwrite_driver_test") +class pwrite_driver_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + + debug.info(2, "Checking 1x pwrite_driver") + tx = factory.create(module_type="pwrite_driver", size=1) + self.local_check(tx) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py index 65ce5ecf..77336c61 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_test.py @@ -18,7 +18,8 @@ import debug class replica_pbitcell_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import replica_pbitcell OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index 3ecbbe9d..de5870fc 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -20,7 +20,8 @@ import debug class single_level_column_mux_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check single level column mux in single port debug.info(2, "Checking column mux") diff --git a/compiler/tests/05_bitcell_1rw_1r_array_test.py b/compiler/tests/05_bitcell_1rw_1r_array_test.py index 972fb8e6..3426f0c5 100755 --- a/compiler/tests/05_bitcell_1rw_1r_array_test.py +++ b/compiler/tests/05_bitcell_1rw_1r_array_test.py @@ -20,8 +20,8 @@ import debug class bitcell_1rw_1r_array_test(openram_test): def runTest(self): - - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.bitcell = "bitcell_1rw_1r" OPTS.replica_bitcell = "replica_bitcell_1rw_1r" diff --git a/compiler/tests/05_bitcell_array_test.py b/compiler/tests/05_bitcell_array_test.py index 6a561019..256ad526 100755 --- a/compiler/tests/05_bitcell_array_test.py +++ b/compiler/tests/05_bitcell_array_test.py @@ -20,7 +20,8 @@ import debug class array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing 4x4 array for 6t_cell") a = factory.create(module_type="bitcell_array", cols=4, rows=4) diff --git a/compiler/tests/05_dummy_array_test.py b/compiler/tests/05_dummy_array_test.py index de379a97..97ec8db5 100755 --- a/compiler/tests/05_dummy_array_test.py +++ b/compiler/tests/05_dummy_array_test.py @@ -16,7 +16,8 @@ import debug class dummy_row_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing dummy row for 6t_cell") a = factory.create(module_type="dummy_array", rows=1, cols=4) diff --git a/compiler/tests/05_pbitcell_array_test.py b/compiler/tests/05_pbitcell_array_test.py index 91bf7522..6c5e4729 100755 --- a/compiler/tests/05_pbitcell_array_test.py +++ b/compiler/tests/05_pbitcell_array_test.py @@ -19,7 +19,8 @@ import debug class pbitcell_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell") OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/05_replica_pbitcell_array_test.py b/compiler/tests/05_replica_pbitcell_array_test.py index 2bc4a0d2..34bdbee7 100755 --- a/compiler/tests/05_replica_pbitcell_array_test.py +++ b/compiler/tests/05_replica_pbitcell_array_test.py @@ -16,7 +16,8 @@ import debug class replica_bitcell_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.bitcell = "pbitcell" OPTS.replica_bitcell = "replica_pbitcell" diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index c349e889..9d8353f3 100755 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -18,7 +18,8 @@ import debug class hierarchical_decoder_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # Doesn't require hierarchical decoder # debug.info(1, "Testing 4 row sample for hierarchical_decoder") # a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4) @@ -34,14 +35,30 @@ class hierarchical_decoder_test(openram_test): a = factory.create(module_type="hierarchical_decoder", rows=16) self.local_check(a) + debug.info(1, "Testing 17 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", rows=17) + self.local_check(a) + + debug.info(1, "Testing 23 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", rows=23) + self.local_check(a) + debug.info(1, "Testing 32 row sample for hierarchical_decoder") a = factory.create(module_type="hierarchical_decoder", rows=32) self.local_check(a) + debug.info(1, "Testing 65 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", rows=65) + self.local_check(a) + debug.info(1, "Testing 128 row sample for hierarchical_decoder") a = factory.create(module_type="hierarchical_decoder", rows=128) self.local_check(a) + debug.info(1, "Testing 341 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", rows=341) + self.local_check(a) + debug.info(1, "Testing 512 row sample for hierarchical_decoder") a = factory.create(module_type="hierarchical_decoder", rows=512) self.local_check(a) @@ -57,14 +74,34 @@ class hierarchical_decoder_test(openram_test): a = factory.create(module_type="hierarchical_decoder", rows=16) self.local_check(a) + factory.reset() + debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)") + a = factory.create(module_type="hierarchical_decoder", rows=17) + self.local_check(a) + + factory.reset() + debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)") + a = factory.create(module_type="hierarchical_decoder", rows=23) + self.local_check(a) + debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", rows=32) self.local_check(a) + factory.reset() + debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)") + a = factory.create(module_type="hierarchical_decoder", rows=65) + self.local_check(a) + debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", rows=128) self.local_check(a) + factory.reset() + debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)") + a = factory.create(module_type="hierarchical_decoder", rows=341) + self.local_check(a) + debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", rows=512) self.local_check(a) diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index 0a5363ab..2e55f5e9 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -18,7 +18,8 @@ import debug class hierarchical_predecode2x4_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # checking hierarchical precode 2x4 for single port debug.info(1, "Testing sample for hierarchy_predecode2x4") diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index b2a8d438..da7573e1 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -18,7 +18,8 @@ import debug class hierarchical_predecode3x8_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # checking hierarchical precode 3x8 for single port debug.info(1, "Testing sample for hierarchy_predecode3x8") diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index c6cd7ed2..ff6c51eb 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -17,7 +17,8 @@ import debug class single_level_column_mux_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import single_level_column_mux_array # check single level column mux array in single port diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index ee29211b..d4f5591b 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -18,7 +18,8 @@ import debug class precharge_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check precharge array in single port debug.info(2, "Checking 3 column precharge") diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index 31415a6c..f64503f8 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -20,7 +20,8 @@ import debug class wordline_driver_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check wordline driver for single port debug.info(2, "Checking driver") diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index e35ea3c3..3baf51f0 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -18,7 +18,8 @@ import debug class sense_amp_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check sense amp array for single port debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index 20dacca6..16e280ed 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -18,7 +18,8 @@ import debug class write_driver_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check write driver array for single port debug.info(2, "Testing write_driver_array for columns=8, word_size=8") diff --git a/compiler/tests/10_write_driver_array_wmask_test.py b/compiler/tests/10_write_driver_array_wmask_test.py index d09286b5..743d331a 100755 --- a/compiler/tests/10_write_driver_array_wmask_test.py +++ b/compiler/tests/10_write_driver_array_wmask_test.py @@ -20,7 +20,8 @@ import debug class write_driver_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check write driver array for single port debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4") @@ -58,4 +59,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/10_write_mask_and_array_test.py b/compiler/tests/10_write_mask_and_array_test.py index 91155467..303ce2f4 100755 --- a/compiler/tests/10_write_mask_and_array_test.py +++ b/compiler/tests/10_write_mask_and_array_test.py @@ -20,7 +20,8 @@ import debug class write_mask_and_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) # check write driver array for single port debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4") diff --git a/compiler/tests/11_dff_array_test.py b/compiler/tests/11_dff_array_test.py index b843a6bb..9d8798c5 100755 --- a/compiler/tests/11_dff_array_test.py +++ b/compiler/tests/11_dff_array_test.py @@ -18,7 +18,8 @@ import debug class dff_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing dff_array for 3x3") a = factory.create(module_type="dff_array", rows=3, columns=3) diff --git a/compiler/tests/11_dff_buf_array_test.py b/compiler/tests/11_dff_buf_array_test.py index ec0e7742..6eb338a5 100755 --- a/compiler/tests/11_dff_buf_array_test.py +++ b/compiler/tests/11_dff_buf_array_test.py @@ -18,7 +18,8 @@ import debug class dff_buf_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing dff_buf_array for 3x3") a = factory.create(module_type="dff_buf_array", rows=3, columns=3) diff --git a/compiler/tests/11_dff_buf_test.py b/compiler/tests/11_dff_buf_test.py index 161deaa2..070cdb56 100755 --- a/compiler/tests/11_dff_buf_test.py +++ b/compiler/tests/11_dff_buf_test.py @@ -18,7 +18,8 @@ import debug class dff_buf_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing dff_buf 4x 8x") a = factory.create(module_type="dff_buf", inv1_size=4, inv2_size=8) diff --git a/compiler/tests/12_tri_gate_array_test.py b/compiler/tests/12_tri_gate_array_test.py index 0bd5f60c..813feda0 100755 --- a/compiler/tests/12_tri_gate_array_test.py +++ b/compiler/tests/12_tri_gate_array_test.py @@ -18,7 +18,8 @@ import debug class tri_gate_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(1, "Testing tri_gate_array for columns=8, word_size=8") a = factory.create(module_type="tri_gate_array", columns=8, word_size=8) diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py index 9dc8faeb..4b893a8a 100755 --- a/compiler/tests/13_delay_chain_test.py +++ b/compiler/tests/13_delay_chain_test.py @@ -18,7 +18,8 @@ import debug class delay_chain_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing delay_chain") a = factory.create(module_type="delay_chain", fanout_list=[4, 4, 4, 4]) diff --git a/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py b/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py index bae7edde..9fbdf497 100755 --- a/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py +++ b/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py @@ -16,7 +16,8 @@ import debug class replica_bitcell_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.bitcell = "bitcell_1rw_1r" OPTS.replica_bitcell = "replica_bitcell_1rw_1r" diff --git a/compiler/tests/14_replica_bitcell_array_test.py b/compiler/tests/14_replica_bitcell_array_test.py index 2b446758..19413cd5 100755 --- a/compiler/tests/14_replica_bitcell_array_test.py +++ b/compiler/tests/14_replica_bitcell_array_test.py @@ -16,7 +16,8 @@ import debug class replica_bitcell_array_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing 4x4 array for 6t_cell") a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0]) diff --git a/compiler/tests/14_replica_column_test.py b/compiler/tests/14_replica_column_test.py index c0db4d17..57c92e84 100755 --- a/compiler/tests/14_replica_column_test.py +++ b/compiler/tests/14_replica_column_test.py @@ -16,7 +16,8 @@ import debug class replica_column_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(2, "Testing replica column for 6t_cell") a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1) diff --git a/compiler/tests/16_control_logic_multiport_test.py b/compiler/tests/16_control_logic_multiport_test.py index 66c34d24..919e2335 100755 --- a/compiler/tests/16_control_logic_multiport_test.py +++ b/compiler/tests/16_control_logic_multiport_test.py @@ -22,7 +22,8 @@ import debug class control_logic_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import control_logic import tech diff --git a/compiler/tests/16_control_logic_test.py b/compiler/tests/16_control_logic_test.py index 92d5c94b..ecc6008a 100755 --- a/compiler/tests/16_control_logic_test.py +++ b/compiler/tests/16_control_logic_test.py @@ -18,7 +18,8 @@ import debug class control_logic_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import control_logic import tech diff --git a/compiler/tests/18_port_address_test.py b/compiler/tests/18_port_address_test.py index c8db6ec2..23f35540 100755 --- a/compiler/tests/18_port_address_test.py +++ b/compiler/tests/18_port_address_test.py @@ -16,7 +16,8 @@ import debug class port_address_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(1, "Port address 16 rows") a = factory.create("port_address", cols=16, rows=16) diff --git a/compiler/tests/18_port_data_test.py b/compiler/tests/18_port_data_test.py index e5f94329..71681056 100755 --- a/compiler/tests/18_port_data_test.py +++ b/compiler/tests/18_port_data_test.py @@ -16,7 +16,8 @@ import debug class port_data_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=4, diff --git a/compiler/tests/18_port_data_wmask_test.py b/compiler/tests/18_port_data_wmask_test.py index e9b70337..f670990e 100755 --- a/compiler/tests/18_port_data_wmask_test.py +++ b/compiler/tests/18_port_data_wmask_test.py @@ -18,7 +18,8 @@ import debug class port_data_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=16, diff --git a/compiler/tests/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py index e2f5a9a8..adb2523e 100755 --- a/compiler/tests/19_bank_select_test.py +++ b/compiler/tests/19_bank_select_test.py @@ -18,7 +18,8 @@ import debug class bank_select_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(1, "No column mux, rw control logic") a = factory.create(module_type="bank_select", port="rw") diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index 1816cd61..f4c622c7 100755 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -19,7 +19,8 @@ import debug class multi_bank_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=4, diff --git a/compiler/tests/19_pmulti_bank_test.py b/compiler/tests/19_pmulti_bank_test.py index 749460fa..7c3da444 100755 --- a/compiler/tests/19_pmulti_bank_test.py +++ b/compiler/tests/19_pmulti_bank_test.py @@ -19,7 +19,8 @@ import debug class multi_bank_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index 90e886f4..8c6ddb12 100755 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -19,7 +19,8 @@ import debug class psingle_bank_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/19_single_bank_1rw_1r_test.py b/compiler/tests/19_single_bank_1rw_1r_test.py index ab5ce041..b3e18407 100755 --- a/compiler/tests/19_single_bank_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_1rw_1r_test.py @@ -18,7 +18,8 @@ import debug class single_bank_1rw_1r_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "bitcell_1rw_1r" diff --git a/compiler/tests/19_single_bank_1w_1r_test.py b/compiler/tests/19_single_bank_1w_1r_test.py index 12b9f3a0..c1228e5a 100755 --- a/compiler/tests/19_single_bank_1w_1r_test.py +++ b/compiler/tests/19_single_bank_1w_1r_test.py @@ -18,7 +18,8 @@ import debug class single_bank_1w_1r_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "bitcell_1w_1r" diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index 1d010db5..6cff481b 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -18,7 +18,8 @@ import debug class single_bank_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=4, diff --git a/compiler/tests/19_single_bank_wmask_test.py b/compiler/tests/19_single_bank_wmask_test.py index 439ffeba..50567ebb 100755 --- a/compiler/tests/19_single_bank_wmask_test.py +++ b/compiler/tests/19_single_bank_wmask_test.py @@ -18,7 +18,8 @@ import debug class single_bank_wmask_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config diff --git a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py index fdeae56f..599cb2ce 100755 --- a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py @@ -18,8 +18,9 @@ import debug #@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete") class psram_1bank_2mux_1rw_1w_test(openram_test): - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py b/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py index 20fbd8e6..0d236bc2 100755 --- a/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py @@ -21,7 +21,8 @@ import debug class psram_1bank_2mux_1rw_1w_wmask_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "pbitcell" @@ -58,4 +59,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py index a5c01d8f..30b951fb 100755 --- a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py @@ -18,8 +18,9 @@ import debug #@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error") class psram_1bank_2mux_1w_1r_test(openram_test): - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/20_psram_1bank_2mux_test.py b/compiler/tests/20_psram_1bank_2mux_test.py index 64fa72ca..44272b2d 100755 --- a/compiler/tests/20_psram_1bank_2mux_test.py +++ b/compiler/tests/20_psram_1bank_2mux_test.py @@ -18,8 +18,9 @@ import debug #@unittest.skip("SKIPPING 20_psram_1bank_2mux_test, wide metal supply routing error") class psram_1bank_2mux_test(openram_test): - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "pbitcell" OPTS.replica_bitcell="replica_pbitcell" diff --git a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py index 7779b794..472a60a6 100755 --- a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py +++ b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py @@ -17,8 +17,9 @@ import debug class psram_1bank_4mux_1rw_1r_test(openram_test): - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py index 60192759..a8d635ba 100755 --- a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py @@ -18,7 +18,8 @@ import debug class sram_1bank_2mux_1rw_1r_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "bitcell_1rw_1r" diff --git a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py index 2e1e848f..bf572700 100755 --- a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py @@ -18,8 +18,9 @@ import debug #@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error") class psram_1bank_2mux_1w_1r_test(openram_test): - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "bitcell_1w_1r" diff --git a/compiler/tests/20_sram_1bank_2mux_test.py b/compiler/tests/20_sram_1bank_2mux_test.py index 7e5a4f3a..582f5217 100755 --- a/compiler/tests/20_sram_1bank_2mux_test.py +++ b/compiler/tests/20_sram_1bank_2mux_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_2mux_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=4, num_words=32, diff --git a/compiler/tests/20_sram_1bank_2mux_wmask_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_test.py index 65f025a7..50bd41dc 100755 --- a/compiler/tests/20_sram_1bank_2mux_wmask_test.py +++ b/compiler/tests/20_sram_1bank_2mux_wmask_test.py @@ -21,7 +21,8 @@ import debug class sram_1bank_2mux_wmask_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=8, write_size=4, @@ -51,4 +52,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py index a5232267..05cb7c0d 100755 --- a/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py +++ b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py @@ -21,7 +21,8 @@ import debug class sram_1bank_32b_1024_wmask_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=32, write_size=8, @@ -50,4 +51,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_4mux_test.py b/compiler/tests/20_sram_1bank_4mux_test.py index 34af86a1..e38ef7c4 100755 --- a/compiler/tests/20_sram_1bank_4mux_test.py +++ b/compiler/tests/20_sram_1bank_4mux_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_4mux_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=4, num_words=64, diff --git a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py index 48a42106..69a623d2 100755 --- a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py @@ -18,7 +18,8 @@ import debug class sram_1bank_8mux_1rw_1r_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "bitcell_1rw_1r" diff --git a/compiler/tests/20_sram_1bank_8mux_test.py b/compiler/tests/20_sram_1bank_8mux_test.py index c5eaea75..dfdcd5b7 100755 --- a/compiler/tests/20_sram_1bank_8mux_test.py +++ b/compiler/tests/20_sram_1bank_8mux_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_8mux_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=2, num_words=128, diff --git a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py index f6bccc13..f9b96b84 100755 --- a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py @@ -18,7 +18,8 @@ import debug class sram_1bank_nomux_1rw_1r_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config OPTS.bitcell = "bitcell_1rw_1r" diff --git a/compiler/tests/20_sram_1bank_nomux_test.py b/compiler/tests/20_sram_1bank_nomux_test.py index 650d2ac2..c79d8552 100755 --- a/compiler/tests/20_sram_1bank_nomux_test.py +++ b/compiler/tests/20_sram_1bank_nomux_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_nomux_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=4, num_words=16, diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_test.py index e0292e95..24d7c97d 100755 --- a/compiler/tests/20_sram_1bank_nomux_wmask_test.py +++ b/compiler/tests/20_sram_1bank_nomux_wmask_test.py @@ -21,7 +21,8 @@ import debug class sram_1bank_nomux_wmask_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=8, write_size=4, @@ -51,4 +52,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index c5d9d3d0..5fd4bf29 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -19,7 +19,8 @@ import debug class sram_2bank_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram_config import sram_config c = sram_config(word_size=16, num_words=32, diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index ebb424aa..832a6308 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -18,7 +18,8 @@ import debug class timing_sram_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.spice_name="hspice" OPTS.analytical_delay = False OPTS.netlist_only = True diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py index 83bd5509..1844fd39 100755 --- a/compiler/tests/21_hspice_setuphold_test.py +++ b/compiler/tests/21_hspice_setuphold_test.py @@ -18,7 +18,8 @@ import debug class timing_setup_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.spice_name="hspice" OPTS.analytical_delay = False OPTS.netlist_only = True diff --git a/compiler/tests/21_model_delay_test.py b/compiler/tests/21_model_delay_test.py index a4de4c2a..e21d658e 100755 --- a/compiler/tests/21_model_delay_test.py +++ b/compiler/tests/21_model_delay_test.py @@ -20,7 +20,8 @@ class model_delay_test(openram_test): """ Compare the accuracy of the analytical model with a spice simulation. """ def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index a5eb67fa..fb72a57d 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -18,7 +18,8 @@ import debug class timing_sram_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.spice_name="ngspice" OPTS.analytical_delay = False OPTS.netlist_only = True diff --git a/compiler/tests/21_ngspice_setuphold_test.py b/compiler/tests/21_ngspice_setuphold_test.py index 0d160943..246bdff9 100755 --- a/compiler/tests/21_ngspice_setuphold_test.py +++ b/compiler/tests/21_ngspice_setuphold_test.py @@ -18,7 +18,8 @@ import debug class timing_setup_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.spice_name="ngspice" OPTS.analytical_delay = False OPTS.netlist_only = True diff --git a/compiler/tests/22_psram_1bank_2mux_func_test.py b/compiler/tests/22_psram_1bank_2mux_func_test.py index f986c3e7..7a6da149 100755 --- a/compiler/tests/22_psram_1bank_2mux_func_test.py +++ b/compiler/tests/22_psram_1bank_2mux_func_test.py @@ -18,7 +18,8 @@ import debug class psram_1bank_2mux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_psram_1bank_4mux_func_test.py b/compiler/tests/22_psram_1bank_4mux_func_test.py index c5fd8945..facd3874 100755 --- a/compiler/tests/22_psram_1bank_4mux_func_test.py +++ b/compiler/tests/22_psram_1bank_4mux_func_test.py @@ -19,7 +19,8 @@ import debug class psram_1bank_4mux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_psram_1bank_8mux_func_test.py b/compiler/tests/22_psram_1bank_8mux_func_test.py index acb168c0..acf0c3a4 100755 --- a/compiler/tests/22_psram_1bank_8mux_func_test.py +++ b/compiler/tests/22_psram_1bank_8mux_func_test.py @@ -19,7 +19,8 @@ import debug class psram_1bank_8mux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_psram_1bank_nomux_func_test.py b/compiler/tests/22_psram_1bank_nomux_func_test.py index a2a2b41c..b7d6cf78 100755 --- a/compiler/tests/22_psram_1bank_nomux_func_test.py +++ b/compiler/tests/22_psram_1bank_nomux_func_test.py @@ -19,7 +19,8 @@ import debug class psram_1bank_nomux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py index 2037169e..10d19c1c 100755 --- a/compiler/tests/22_sram_1bank_2mux_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_func_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_2mux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py index 178f955b..d2bf7886 100755 --- a/compiler/tests/22_sram_1bank_4mux_func_test.py +++ b/compiler/tests/22_sram_1bank_4mux_func_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_4mux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py index d531163a..3f6ff55f 100755 --- a/compiler/tests/22_sram_1bank_8mux_func_test.py +++ b/compiler/tests/22_sram_1bank_8mux_func_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_8mux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py index eb6d2412..2aa20e99 100755 --- a/compiler/tests/22_sram_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_func_test.py @@ -19,7 +19,8 @@ import debug class sram_1bank_nomux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True diff --git a/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py b/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py index 169e34d0..d271d1e5 100755 --- a/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py @@ -19,7 +19,8 @@ import debug class psram_1bank_nomux_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_sram_wmask_1w_1r_func_test.py b/compiler/tests/22_sram_wmask_1w_1r_func_test.py index 2ee79750..50acd5bf 100755 --- a/compiler/tests/22_sram_wmask_1w_1r_func_test.py +++ b/compiler/tests/22_sram_wmask_1w_1r_func_test.py @@ -21,7 +21,8 @@ import debug class sram_wmask_1w_1r_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/22_sram_wmask_func_test.py b/compiler/tests/22_sram_wmask_func_test.py index c390f030..d29795a9 100755 --- a/compiler/tests/22_sram_wmask_func_test.py +++ b/compiler/tests/22_sram_wmask_func_test.py @@ -19,7 +19,8 @@ import debug class sram_wmask_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False diff --git a/compiler/tests/23_lib_sram_model_corners_test.py b/compiler/tests/23_lib_sram_model_corners_test.py index 5840c05d..1e853fae 100755 --- a/compiler/tests/23_lib_sram_model_corners_test.py +++ b/compiler/tests/23_lib_sram_model_corners_test.py @@ -18,7 +18,8 @@ import debug class lib_model_corners_lib_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.netlist_only = True from characterizer import lib diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index 75e73f71..6043d83f 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -18,7 +18,8 @@ import debug class lib_sram_model_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.netlist_only = True from characterizer import lib diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index 1fc5a66b..9df647ce 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -18,7 +18,8 @@ import debug class lib_sram_prune_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.trim_netlist = True diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 0ababf32..08bb5565 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -17,7 +17,8 @@ import debug class lib_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.analytical_delay = False OPTS.trim_netlist = False diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index 5f7fdc60..14ad551f 100755 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -18,7 +18,8 @@ import debug class lef_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram import sram from sram_config import sram_config diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index da6a2682..c385e455 100755 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -17,7 +17,8 @@ import debug class verilog_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) from sram import sram from sram_config import sram_config diff --git a/compiler/tests/26_hspice_pex_pinv_test.py b/compiler/tests/26_hspice_pex_pinv_test.py index f0cccba3..b4b55cdb 100755 --- a/compiler/tests/26_hspice_pex_pinv_test.py +++ b/compiler/tests/26_hspice_pex_pinv_test.py @@ -20,7 +20,8 @@ import debug class hspice_pex_pinv_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import pinv # load the hspice diff --git a/compiler/tests/26_ngspice_pex_pinv_test.py b/compiler/tests/26_ngspice_pex_pinv_test.py index 2eb95948..e6e0cfb2 100755 --- a/compiler/tests/26_ngspice_pex_pinv_test.py +++ b/compiler/tests/26_ngspice_pex_pinv_test.py @@ -19,7 +19,8 @@ import debug class ngspice_pex_pinv_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) import pinv # load the ngspice diff --git a/compiler/tests/26_pex_test.py b/compiler/tests/26_pex_test.py index 78409249..4eff7db5 100755 --- a/compiler/tests/26_pex_test.py +++ b/compiler/tests/26_pex_test.py @@ -19,7 +19,8 @@ import debug class sram_func_test(openram_test): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) OPTS.use_pex = True diff --git a/compiler/tests/30_openram_back_end_test.py b/compiler/tests/30_openram_back_end_test.py index de1bec05..73d201b1 100755 --- a/compiler/tests/30_openram_back_end_test.py +++ b/compiler/tests/30_openram_back_end_test.py @@ -20,7 +20,8 @@ class openram_back_end_test(openram_test): def runTest(self): OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) - globals.init_openram("{0}/tests/config_{1}".format(OPENRAM_HOME,OPTS.tech_name)) + config_file = "{}/tests/configs/config_back_end".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(1, "Testing top-level back-end openram.py with 2-bit, 16 word SRAM.") out_file = "testsram" @@ -51,7 +52,7 @@ class openram_back_end_test(openram_test): exe_name = "{0}/openram.py ".format(OPENRAM_HOME) else: exe_name = "coverage run -p {0}/openram.py ".format(OPENRAM_HOME) - config_name = "{0}config_{1}_back_end.py".format(OPENRAM_HOME + "/tests/",OPTS.tech_name) + config_name = "{0}/tests/configs/config_back_end.py".format(OPENRAM_HOME) cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name, out_file, out_path, diff --git a/compiler/tests/30_openram_front_end_test.py b/compiler/tests/30_openram_front_end_test.py index dbe7fcb9..3aec10f9 100755 --- a/compiler/tests/30_openram_front_end_test.py +++ b/compiler/tests/30_openram_front_end_test.py @@ -16,12 +16,12 @@ from sram_factory import factory import debug import getpass -#@unittest.skip("SKIPPING 30_openram_front_end_test") class openram_front_end_test(openram_test): def runTest(self): OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) - globals.init_openram("{0}/tests/config_{1}".format(OPENRAM_HOME,OPTS.tech_name)) + config_file = "{}/tests/configs/config_front_end".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) debug.info(1, "Testing top-level front-end openram.py with 2-bit, 16 word SRAM.") out_file = "testsram" @@ -52,7 +52,7 @@ class openram_front_end_test(openram_test): exe_name = "{0}/openram.py ".format(OPENRAM_HOME) else: exe_name = "coverage run -p {0}/openram.py ".format(OPENRAM_HOME) - config_name = "{0}config_{1}_front_end.py".format(OPENRAM_HOME + "/tests/",OPTS.tech_name) + config_name = "{0}/tests/configs/config_front_end.py".format(OPENRAM_HOME) cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name, out_file, out_path, diff --git a/compiler/tests/config_freepdk45.py b/compiler/tests/config_freepdk45.py deleted file mode 100644 index 3103217f..00000000 --- a/compiler/tests/config_freepdk45.py +++ /dev/null @@ -1,18 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2019 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -word_size = 1 -num_words = 16 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] - -route_supplies = True -check_lvsdrc = True - diff --git a/compiler/tests/config_freepdk45_back_end.py b/compiler/tests/config_freepdk45_back_end.py deleted file mode 100644 index 68417a3b..00000000 --- a/compiler/tests/config_freepdk45_back_end.py +++ /dev/null @@ -1,20 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2019 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -word_size = 1 -num_words = 16 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] - -inline_lvsdrc = True -route_supplies = True -check_lvsdrc = True -analytical_delay = False - diff --git a/compiler/tests/config_freepdk45_front_end.py b/compiler/tests/config_freepdk45_front_end.py deleted file mode 100644 index 1886d808..00000000 --- a/compiler/tests/config_freepdk45_front_end.py +++ /dev/null @@ -1,18 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2019 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -word_size = 1 -num_words = 16 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] - -analytical_delay = False - - diff --git a/compiler/tests/config_scn4m_subm.py b/compiler/tests/configs/config.py similarity index 61% rename from compiler/tests/config_scn4m_subm.py rename to compiler/tests/configs/config.py index abb31435..4711214b 100644 --- a/compiler/tests/config_scn4m_subm.py +++ b/compiler/tests/configs/config.py @@ -5,10 +5,12 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +from globals import OPTS word_size = 1 num_words = 16 -tech_name = "scn4m_subm" +tech_name = OPTS.tech_name + process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] @@ -16,7 +18,13 @@ temperatures = [25] route_supplies = True check_lvsdrc = True -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" +if tech_name == "freepdk45": + supply_voltages = [1.0] + drc_name = "calibre" + lvs_name = "calibre" + pex_name = "calibre" +else: + drc_name = "magic" + lvs_name = "netgen" + pex_name = "magic" diff --git a/compiler/tests/config_scn4m_subm_back_end.py b/compiler/tests/configs/config_back_end.py similarity index 63% rename from compiler/tests/config_scn4m_subm_back_end.py rename to compiler/tests/configs/config_back_end.py index 35e4cd91..57288031 100644 --- a/compiler/tests/config_scn4m_subm_back_end.py +++ b/compiler/tests/configs/config_back_end.py @@ -5,10 +5,11 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +from globals import OPTS word_size = 1 num_words = 16 -tech_name = "scn4m_subm" +tech_name = OPTS.tech_name process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] @@ -18,6 +19,13 @@ check_lvsdrc = True inline_lvsdrc = True analytical_delay = False -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" +if tech_name == "freepdk45": + supply_voltages = [1.0] + drc_name = "calibre" + lvs_name = "calibre" + pex_name = "calibre" +else: + drc_name = "magic" + lvs_name = "netgen" + pex_name = "magic" + diff --git a/compiler/tests/config_scn4m_subm_front_end.py b/compiler/tests/configs/config_front_end.py similarity index 58% rename from compiler/tests/config_scn4m_subm_front_end.py rename to compiler/tests/configs/config_front_end.py index 142191a0..4a4faf37 100644 --- a/compiler/tests/config_scn4m_subm_front_end.py +++ b/compiler/tests/configs/config_front_end.py @@ -5,15 +5,23 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +from globals import OPTS word_size = 1 num_words = 16 -tech_name = "scn4m_subm" +tech_name = OPTS.tech_name process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" +if tech_name == "freepdk45": + supply_voltages = [1.0] + drc_name = "calibre" + lvs_name = "calibre" + pex_name = "calibre" +else: + drc_name = "magic" + lvs_name = "netgen" + pex_name = "magic" + diff --git a/compiler/tests/config_scn3me_subm.py b/compiler/tests/scn3me_subm/config.py similarity index 100% rename from compiler/tests/config_scn3me_subm.py rename to compiler/tests/scn3me_subm/config.py diff --git a/compiler/tests/config_scn3me_subm_back_end.py b/compiler/tests/scn3me_subm/config_back_end.py similarity index 100% rename from compiler/tests/config_scn3me_subm_back_end.py rename to compiler/tests/scn3me_subm/config_back_end.py diff --git a/compiler/tests/config_scn3me_subm_front_end.py b/compiler/tests/scn3me_subm/config_front_end.py similarity index 100% rename from compiler/tests/config_scn3me_subm_front_end.py rename to compiler/tests/scn3me_subm/config_front_end.py diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index caa3c748..4ffeb4fe 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -35,39 +35,38 @@ GDS["zoom"] = 0.05 # create the GDS layer map # FIXME: parse the gds layer map from the cadence map? layer = {} -layer["active"] = 1 -layer["pwell"] = 2 -layer["nwell"] = 3 -layer["nimplant"]= 4 -layer["pimplant"]= 5 -layer["vtg"] = 6 -layer["vth"] = 7 -layer["thkox"] = 8 -layer["poly"] = 9 -layer["contact"] = 10 -layer["active_contact"] = 10 -layer["metal1"] = 11 -layer["via1"] = 12 -layer["metal2"] = 13 -layer["via2"] = 14 -layer["metal3"] = 15 -layer["via3"] = 16 -layer["metal4"] = 17 -layer["via4"] = 18 -layer["metal5"] = 19 -layer["via5"] = 20 -layer["metal6"] = 21 -layer["via6"] = 22 -layer["metal7"] = 23 -layer["via7"] = 24 -layer["metal8"] = 25 -layer["via8"] = 26 -layer["metal9"] = 27 -layer["via9"] = 28 -layer["metal10"] = 29 -layer["text"] = 239 -layer["boundary"]= 239 -layer["blockage"]= 239 +layer["active"] = (1, 0) +layer["pwell"] = (2, 0) +layer["nwell"] = (3, 0) +layer["nimplant"]= (4, 0) +layer["pimplant"]= (5, 0) +layer["vtg"] = (6, 0) +layer["vth"] = (7, 0) +layer["thkox"] = (8, 0) +layer["poly"] = (9, 0) +layer["contact"] = (10, 0) +layer["active_contact"] = (10, 0) +layer["metal1"] = (11, 0) +layer["via1"] = (12, 0) +layer["metal2"] = (13, 0) +layer["via2"] = (14, 0) +layer["metal3"] = (15, 0) +layer["via3"] = (16, 0) +layer["metal4"] = (17, 0) +layer["via4"] = (18, 0) +layer["metal5"] = (19, 0) +layer["via5"] = (20, 0) +layer["metal6"] = (21, 0) +layer["via6"] = (22, 0) +layer["metal7"] = (23, 0) +layer["via7"] = (24, 0) +layer["metal8"] = (25, 0) +layer["via8"] = (26, 0) +layer["metal9"] = (27, 0) +layer["via9"] = (28, 0) +layer["metal10"] = (29, 0) +layer["text"] = (239, 0) +layer["boundary"]= (239, 0) ################################################### ##END GDS Layer Map diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index 074009f2..cc405c21 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -29,24 +29,24 @@ GDS["zoom"] = 0.5 # create the GDS layer map layer={} -layer["vtg"] = -1 -layer["vth"] = -1 -layer["contact"] = 47 -layer["pwell"] = 41 -layer["nwell"] = 42 -layer["active"] = 43 -layer["pimplant"] = 44 -layer["nimplant"] = 45 -layer["poly"] = 46 -layer["active_contact"] = 48 -layer["metal1"] = 49 -layer["via1"] = 50 -layer["metal2"] = 51 -layer["via2"] = 61 -layer["metal3"] = 62 -layer["text"] = 63 -layer["boundary"] = 63 -layer["blockage"] = 83 +layer["vtg"] = (-1, 0) +layer["vth"] = (-1, 0) +layer["contact"] = (47, 0) +layer["pwell"] = (41, 0) +layer["nwell"] = (42, 0) +layer["active"] = (43, 0) +layer["pimplant"] = (44, 0) +layer["nimplant"] = (45, 0) +layer["poly"] = (46, 0) +layer["active_contact"] = (48, 0) +layer["metal1"] = (49, 0) +layer["via1"] = (50, 0) +layer["metal2"] = (51, 0) +layer["via2"] = (61, 0) +layer["metal3"] = (62, 0) +layer["text"] = (63, 0) +layer["boundary"] = (63, 0) +layer["blockage"] = (83, 0) ################################################### ##END GDS Layer Map diff --git a/technology/scn4m_subm/mag_lib/.magicrc b/technology/scn4m_subm/mag_lib/.magicrc index 0dfe42ef..c85bb879 100644 --- a/technology/scn4m_subm/mag_lib/.magicrc +++ b/technology/scn4m_subm/mag_lib/.magicrc @@ -1,4 +1,7 @@ -path sys +$::env(OPENRAM_TECH)/scn4m_subm/tech +set openram_paths [split $::env(OPENRAM_TECH) ":"] +foreach p $openram_paths { + path sys +$p/scn4m_subm/tech +} tech load SCN4M_SUBM.20 -noprompt scalegrid 1 4 set GND gnd diff --git a/technology/scn4m_subm/models/ff/nmos.sp b/technology/scn4m_subm/models/ff/nmos.sp index 02e8b528..b6d4957e 100644 --- a/technology/scn4m_subm/models/ff/nmos.sp +++ b/technology/scn4m_subm/models/ff/nmos.sp @@ -3,11 +3,12 @@ * Note: These models are approximate * and should be substituted with actual * models from MOSIS or SCN4ME +* FF model is a copy of nominal with -10% vth0 ********************************************* .MODEL n NMOS ( LEVEL = 49 +VERSION = 3.1 TNOM = 27 TOX = 7.6E-9 -+XJ = 1.5E-7 NCH = 1.7E17 VTH0 = 0.4964448 ++XJ = 1.5E-7 NCH = 1.7E17 VTH0 = 0.4468003 +K1 = 0.5307769 K2 = 0.0199705 K3 = 0.2963637 +K3B = 0.2012165 W0 = 2.836319E-6 NLX = 2.894802E-7 +DVT0W = 0 DVT1W = 5.3E6 DVT2W = -0.032 diff --git a/technology/scn4m_subm/models/ff/pmos.sp b/technology/scn4m_subm/models/ff/pmos.sp index 3a47539c..33004072 100644 --- a/technology/scn4m_subm/models/ff/pmos.sp +++ b/technology/scn4m_subm/models/ff/pmos.sp @@ -3,11 +3,12 @@ * Note: These models are approximate * and should be substituted with actual * models from MOSIS or SCN4ME +* FF model is a copy of nominal with -.10% vth0 ********************************************* .MODEL p PMOS ( LEVEL = 49 +VERSION = 3.1 TNOM = 27 TOX = 7.6E-9 -+XJ = 1.5E-7 NCH = 1.7E17 VTH0 = -0.6636594 ++XJ = 1.5E-7 NCH = 1.7E17 VTH0 = -0.5972935 +K1 = 0.4564781 K2 = -0.019447 K3 = 39.382919 +K3B = -2.8930965 W0 = 2.655585E-6 NLX = 1.51028E-7 +DVT0W = 0 DVT1W = 5.3E6 DVT2W = -0.032 diff --git a/technology/scn4m_subm/models/ss/nmos.sp b/technology/scn4m_subm/models/ss/nmos.sp index 02e8b528..b0b3352d 100644 --- a/technology/scn4m_subm/models/ss/nmos.sp +++ b/technology/scn4m_subm/models/ss/nmos.sp @@ -3,11 +3,12 @@ * Note: These models are approximate * and should be substituted with actual * models from MOSIS or SCN4ME +* SS model is a copy of nominal with +10% vth0 ********************************************* .MODEL n NMOS ( LEVEL = 49 +VERSION = 3.1 TNOM = 27 TOX = 7.6E-9 -+XJ = 1.5E-7 NCH = 1.7E17 VTH0 = 0.4964448 ++XJ = 1.5E-7 NCH = 1.7E17 VTH0 = 0.5108928 +K1 = 0.5307769 K2 = 0.0199705 K3 = 0.2963637 +K3B = 0.2012165 W0 = 2.836319E-6 NLX = 2.894802E-7 +DVT0W = 0 DVT1W = 5.3E6 DVT2W = -0.032 diff --git a/technology/scn4m_subm/models/ss/pmos.sp b/technology/scn4m_subm/models/ss/pmos.sp index 3a47539c..24c7d712 100644 --- a/technology/scn4m_subm/models/ss/pmos.sp +++ b/technology/scn4m_subm/models/ss/pmos.sp @@ -3,11 +3,12 @@ * Note: These models are approximate * and should be substituted with actual * models from MOSIS or SCN4ME +* SS model is a copy of nominal with +10% vth0 ********************************************* .MODEL p PMOS ( LEVEL = 49 +VERSION = 3.1 TNOM = 27 TOX = 7.6E-9 -+XJ = 1.5E-7 NCH = 1.7E17 VTH0 = -0.6636594 ++XJ = 1.5E-7 NCH = 1.7E17 VTH0 = -0.7300253 +K1 = 0.4564781 K2 = -0.019447 K3 = 39.382919 +K3B = -2.8930965 W0 = 2.655585E-6 NLX = 1.51028E-7 +DVT0W = 0 DVT1W = 5.3E6 DVT2W = -0.032 diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 37e55e21..6edaf7aa 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -35,26 +35,25 @@ GDS["zoom"] = 0.5 # create the GDS layer map layer={} -layer["vtg"] = -1 -layer["vth"] = -1 -layer["contact"] = 47 -layer["pwell"] = 41 -layer["nwell"] = 42 -layer["active"] = 43 -layer["pimplant"] = 44 -layer["nimplant"] = 45 -layer["poly"] = 46 -layer["active_contact"] = 48 -layer["metal1"] = 49 -layer["via1"] = 50 -layer["metal2"] = 51 -layer["via2"] = 61 -layer["metal3"] = 62 -layer["via3"] = 30 -layer["metal4"] = 31 -layer["text"] = 63 -layer["boundary"] = 63 -layer["blockage"] = 83 +layer["vtg"] = (-1, 0) +layer["vth"] = (-1, 0) +layer["contact"] = (47, 0) +layer["pwell"] = (41, 0) +layer["nwell"] = (42, 0) +layer["active"] = (43, 0) +layer["pimplant"] = (44, 0) +layer["nimplant"] = (45, 0) +layer["poly"] = (46, 0) +layer["active_contact"] = (48, 0) +layer["metal1"] = (49, 0) +layer["via1"] = (50, 0) +layer["metal2"] = (51, 0) +layer["via2"] = (61, 0) +layer["metal3"] = (62, 0) +layer["via3"] = (30, 0) +layer["metal4"] = (31, 0) +layer["text"] = (63, 0) +layer["boundary"] = (63, 0) ################################################### ##END GDS Layer Map