Reimplement gdsMill pin functions so they are run once when a GDS is loaded. Get pins is now a table lookup.

This commit is contained in:
Matt Guthaus 2018-11-07 11:31:44 -08:00
parent 485590052a
commit 1fe767343e
12 changed files with 116 additions and 165 deletions

View File

@ -88,9 +88,9 @@ def get_libcell_size(name, units, layer):
return(get_gds_size(name, cell_gds, units, layer)) return(get_gds_size(name, cell_gds, units, layer))
def get_gds_pins(pin_list, name, gds_filename, units, layer): def get_gds_pins(pin_names, name, gds_filename, units):
""" """
Open a GDS file and find the pins in pin_list as text on a given layer. Open a GDS file and find the pins in pin_names as text on a given layer.
Return these as a rectangle layer pair for each pin. Return these as a rectangle layer pair for each pin.
""" """
cell_vlsi = gdsMill.VlsiLayout(units=units) cell_vlsi = gdsMill.VlsiLayout(units=units)
@ -98,23 +98,23 @@ def get_gds_pins(pin_list, name, gds_filename, units, layer):
reader.loadFromFile(gds_filename) reader.loadFromFile(gds_filename)
cell = {} cell = {}
for pin in pin_list: for pin_name in pin_names:
cell[str(pin)]=[] cell[str(pin_name)]=[]
label_list=cell_vlsi.getPinShapeByLabel(str(pin)) pin_list=cell_vlsi.getAllPinShapes(str(pin_name))
for label in label_list: for pin_shape in pin_list:
(name,layer,boundary)=label (layer,boundary)=pin_shape
rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
# this is a list because other cells/designs may have must-connect pins # this is a list because other cells/designs may have must-connect pins
cell[str(pin)].append(pin_layout(pin, rect, layer)) cell[str(pin_name)].append(pin_layout(pin_name, rect, layer))
return cell return cell
def get_libcell_pins(pin_list, name, units, layer): 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. Open a GDS file and find the pins in pin_list as text on a given layer.
Return these as a rectangle layer pair for each pin. Return these as a rectangle layer pair for each pin.
""" """
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
return(get_gds_pins(pin_list, name, cell_gds, units, layer)) return(get_gds_pins(pin_list, name, cell_gds, units))

View File

@ -13,7 +13,7 @@ class bitcell(design.design):
pin_names = ["bl", "br", "wl", "vdd", "gnd"] pin_names = ["bl", "br", "wl", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"])
def __init__(self): def __init__(self):
design.design.__init__(self, "cell_6t") design.design.__init__(self, "cell_6t")

View File

@ -13,7 +13,7 @@ class bitcell_1rw_1r(design.design):
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"] pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"])
def __init__(self): def __init__(self):
design.design.__init__(self, "cell_1rw_1r") design.design.__init__(self, "cell_1rw_1r")

View File

@ -12,7 +12,7 @@ class replica_bitcell(design.design):
pin_names = ["bl", "br", "wl", "vdd", "gnd"] pin_names = ["bl", "br", "wl", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"])
def __init__(self): def __init__(self):
design.design.__init__(self, "replica_cell_6t") design.design.__init__(self, "replica_cell_6t")

View File

@ -12,7 +12,7 @@ class replica_bitcell_1rw_1r(design.design):
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"] pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"])
def __init__(self): def __init__(self):
design.design.__init__(self, "replica_cell_1rw_1r") design.design.__init__(self, "replica_cell_1rw_1r")

View File

@ -60,6 +60,9 @@ class VlsiLayout:
self.tempCoordinates=None self.tempCoordinates=None
self.tempPassFail = True self.tempPassFail = True
# This is the pin map
self.pins = {}
def rotatedCoordinates(self,coordinatesToRotate,rotateAngle): def rotatedCoordinates(self,coordinatesToRotate,rotateAngle):
#helper method to rotate a list of coordinates #helper method to rotate a list of coordinates
angle=math.radians(float(0)) angle=math.radians(float(0))
@ -208,6 +211,10 @@ class VlsiLayout:
#self.traverseTheHierarchy() #self.traverseTheHierarchy()
self.populateCoordinateMap() self.populateCoordinateMap()
for layerNumber in self.layerNumbersInUse:
self.processLabelPins(layerNumber)
def populateCoordinateMap(self): def populateCoordinateMap(self):
def addToXyTree(startingStructureName = None,transformPath = None): def addToXyTree(startingStructureName = None,transformPath = None):
#print("populateCoordinateMap") #print("populateCoordinateMap")
@ -478,6 +485,10 @@ class VlsiLayout:
return False #these shapes are ok return False #these shapes are ok
def isPointInsideOfBox(self,pointCoordinates,boxCoordinates): def isPointInsideOfBox(self,pointCoordinates,boxCoordinates):
"""
Check if a point is contained in the shape
"""
debug.check(len(boxCoordinates)==4,"Invalid number of coordinates for box.")
leftBound = boxCoordinates[0][0] leftBound = boxCoordinates[0][0]
rightBound = boxCoordinates[0][0] rightBound = boxCoordinates[0][0]
topBound = boxCoordinates[0][1] topBound = boxCoordinates[0][1]
@ -499,7 +510,9 @@ class VlsiLayout:
return True return True
def isShapeInsideOfBox(self,shapeCoordinates, boxCoordinates): def isShapeInsideOfBox(self,shapeCoordinates, boxCoordinates):
#go through every point in the shape to test if they are all inside the box """
Go through every point in the shape to test if they are all inside the box.
"""
for point in shapeCoordinates: for point in shapeCoordinates:
if not self.isPointInsideOfBox(point,boxCoordinates): if not self.isPointInsideOfBox(point,boxCoordinates):
return False return False
@ -634,160 +647,85 @@ class VlsiLayout:
return cellBoundary return cellBoundary
def getLabelDBInfo(self,label_name): def getTexts(self, layer):
""" """
Return the coordinates in DB units and layer of all matching labels Get all of the labels on a given layer only at the root level.
""" """
label_list = [] text_list = []
label_layer = None
label_coordinate = [None, None]
# Why must this be the last one found? It breaks if we return the first.
for Text in self.structures[self.rootStructureName].texts: for Text in self.structures[self.rootStructureName].texts:
if Text.textString == label_name or Text.textString == label_name+"\x00": if Text.drawingLayer == layer:
label_layer = Text.drawingLayer text_list.append(Text)
label_coordinate = Text.coordinates[0] return text_list
if label_layer!=None:
label_list.append((label_coordinate,label_layer))
debug.check(len(label_list)>0,"Did not find labels {0}.".format(label_name)) def getPinShape(self, pin_name):
return label_list
def getLabelInfo(self,label_name):
"""
Return the coordinates in USER units and layer of a label
"""
label_list=self.getLabelDBInfo(label_name)
new_list=[]
for label in label_list:
(label_coordinate,label_layer)=label
user_coordinates = [x*self.units[0] for x in label_coordinate]
new_list.append(user_coordinates,label_layer)
return new_list
def getPinShapeByLocLayer(self, coordinate, layer):
"""
Return the largest enclosing rectangle on a layer and at a location.
Coordinates should be in USER units.
"""
db_coordinate = [x/self.units[0] for x in coordinate]
return self.getPinShapeByDBLocLayer(db_coordinate, layer)
def getPinShapeByDBLocLayer(self, coordinate, layer):
"""
Return the largest enclosing rectangle on a layer and at a location.
Coordinates should be in DB units.
"""
pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer)
if len(pin_boundaries) == 0:
debug.warning("Did not find pin on layer {0} at coordinate {1}".format(layer, coordinate))
# sort the boundaries, return the max area pin boundary
pin_boundaries.sort(key=boundaryArea,reverse=True)
pin_boundary=pin_boundaries[0]
# Convert to USER units
pin_boundary=[pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0],
pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]]
# Make a name if we don't have the pin name
return ["p"+str(coordinate)+"_"+str(layer), layer, pin_boundary]
def getAllPinShapesByLocLayer(self, coordinate, layer):
"""
Return ALL the enclosing rectangles on the same layer
at the given coordinate. Coordinates should be in USER units.
"""
db_coordinate = [int(x/self.units[0]) for x in coordinate]
return self.getAllPinShapesByDBLocLayer(db_coordinate, layer)
def getAllPinShapesByDBLocLayer(self, coordinate, layer):
"""
Return ALL the enclosing rectangles on the same layer
at the given coordinate. Input coordinates should be in DB units.
Returns user unit shapes.
"""
pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer)
# Convert to user units
new_boundaries = []
for pin_boundary in pin_boundaries:
new_pin_boundary = [pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0],
pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]]
new_boundaries.append(["p"+str(coordinate)+"_"+str(layer), layer, new_pin_boundary])
return new_boundaries
def getPinShapeByLabel(self,label_name):
""" """
Search for a pin label and return the largest enclosing rectangle Search for a pin label and return the largest enclosing rectangle
on the same layer as the pin label. on the same layer as the pin label.
Signal an error if there are multiple labels on different layers.
""" """
label_list=self.getLabelDBInfo(label_name) pin_list = self.getAllPinShapes(pin_name)
shape_list=[] max_pin = None
for label in label_list: max_area = 0
(label_coordinate,label_layer)=label for pin in pin_list:
shape = self.getPinShapeByDBLocLayer(label_coordinate, label_layer) (layer,boundary) = pin
shape_list.append(shape) new_area = boundaryArea(boundary)
return shape_list if max_pin == None or new_area>max_area:
max_pin = pin
max_area = new_area
def getAllPinShapesByLabel(self,label_name): return max_pin
def getAllPinShapes(self, pin_name):
""" """
Search for a pin label and return ALL the enclosing rectangles on the same layer Search for a pin label and return ALL the enclosing rectangles on the same layer
as the pin label. as the pin label.
""" """
label_list=self.getLabelDBInfo(label_name)
shape_list = [] shape_list = []
for label in label_list: pin_map = self.pins[pin_name]
(label_coordinate,label_layer)=label for pin in pin_map:
shape_list.extend(self.getAllPinShapesByDBLocLayer(label_coordinate, label_layer)) (pin_layer, boundary) = pin
shape_list.append(pin)
return shape_list return shape_list
def getAllPinShapesInStructureList(self,coordinates,layer):
def processLabelPins(self, layer):
""" """
Given a coordinate, search for enclosing structures on the given layer. Find all text labels and create a map to a list of shapes that
Return all pin shapes. they enclose on the given layer.
""" """
boundaries = [] # Get the labels on a layer in the root level
for TreeUnit in self.xyTree: labels = self.getTexts(layer)
boundaries.extend(self.getPinInStructure(coordinates,layer,TreeUnit)) # Get all of the shapes on the layer at all levels
# and transform them to the current level
shapes = self.getAllShapes(layer)
return boundaries 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))
label_text = label.textString
# Remove the padding if it exists
if label_text[-1] == "\x00":
label_text = label_text[0:-1]
try:
self.pins[label_text]
except KeyError:
self.pins[label_text] = []
self.pins[label_text].extend(pin_shapes)
def getPinInStructure(self,coordinates,layer,structure):
def getAllShapes(self,layer):
""" """
Go through all the shapes in a structure and return the list of shapes Return all gshapes on a given layer in [llx, lly, urx, ury] format and
that the label coordinates are inside. user units.
"""
(structureName,structureOrigin,structureuVector,structurevVector)=structure
boundaries = []
for boundary in self.structures[str(structureName)].boundaries:
# Pin enclosures only work on rectangular pins so ignore any non rectangle
# This may report not finding pins, but the user should fix this by adding a rectangle.
if len(boundary.coordinates)!=5:
continue
if layer==boundary.drawingLayer:
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=self.transformRectangle(boundaryRect,structureuVector,structurevVector)
boundaryRect=[boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(),
boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()]
if self.labelInRectangle(coordinates,boundaryRect):
boundaries.append(boundaryRect)
return boundaries
def getAllShapesInStructureList(self,layer):
"""
Return all pin shapes on a given layer.
""" """
boundaries = [] boundaries = []
for TreeUnit in self.xyTree: for TreeUnit in self.xyTree:
@ -812,7 +750,8 @@ class VlsiLayout:
def getShapesInStructure(self,layer,structure): def getShapesInStructure(self,layer,structure):
""" """
Go through all the shapes in a structure and return the list of shapes. Go through all the shapes in a structure and return the list of shapes in
the form [llx, lly, urx, ury]
""" """
(structureName,structureOrigin,structureuVector,structurevVector)=structure (structureName,structureOrigin,structureuVector,structurevVector)=structure
@ -820,6 +759,7 @@ class VlsiLayout:
boundaries = [] boundaries = []
for boundary in self.structures[str(structureName)].boundaries: for boundary in self.structures[str(structureName)].boundaries:
# FIXME: Right now, this only supports rectangular shapes! # FIXME: Right now, this only supports rectangular shapes!
#debug.check(len(boundary.coordinates)==5,"Non-rectangular shape.")
if len(boundary.coordinates)!=5: if len(boundary.coordinates)!=5:
continue continue
if layer==boundary.drawingLayer: if layer==boundary.drawingLayer:
@ -874,8 +814,8 @@ class VlsiLayout:
""" """
Checks if a coordinate is within a given rectangle. Rectangle is [leftx, bottomy, rightx, topy]. Checks if a coordinate is within a given rectangle. Rectangle is [leftx, bottomy, rightx, topy].
""" """
coordinate_In_Rectangle_x_range=(coordinate[0]>=int(rectangle[0]))&(coordinate[0]<=int(rectangle[2])) coordinate_In_Rectangle_x_range=(coordinate[0]>=rectangle[0])&(coordinate[0]<=rectangle[2])
coordinate_In_Rectangle_y_range=(coordinate[1]>=int(rectangle[1]))&(coordinate[1]<=int(rectangle[3])) coordinate_In_Rectangle_y_range=(coordinate[1]>=rectangle[1])&(coordinate[1]<=rectangle[3])
if coordinate_In_Rectangle_x_range & coordinate_In_Rectangle_y_range: if coordinate_In_Rectangle_x_range & coordinate_In_Rectangle_y_range:
return True return True
else: else:

View File

@ -12,7 +12,7 @@ class dff(design.design):
pin_names = ["D", "Q", "clk", "vdd", "gnd"] pin_names = ["D", "Q", "clk", "vdd", "gnd"]
(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"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
def __init__(self, name="dff"): def __init__(self, name="dff"):
design.design.__init__(self, name) design.design.__init__(self, name)

View File

@ -13,7 +13,7 @@ class sense_amp(design.design):
pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"] pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"])
def __init__(self, name): def __init__(self, name):
design.design.__init__(self, name) design.design.__init__(self, name)

View File

@ -12,7 +12,7 @@ class tri_gate(design.design):
pin_names = ["in", "en", "en_bar", "out", "gnd", "vdd"] pin_names = ["in", "en", "en_bar", "out", "gnd", "vdd"]
(width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"])
unique_id = 1 unique_id = 1

View File

@ -13,7 +13,7 @@ class write_driver(design.design):
pin_names = ["din", "bl", "br", "en", "gnd", "vdd"] pin_names = ["din", "bl", "br", "en", "gnd", "vdd"]
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"])
def __init__(self, name): def __init__(self, name):
design.design.__init__(self, name) design.design.__init__(self, name)

View File

@ -1,6 +1,7 @@
import sys import sys
import gdsMill import gdsMill
from tech import drc,GDS from tech import drc,GDS
from tech import layer as techlayer
import math import math
import debug import debug
from router_tech import router_tech from router_tech import router_tech
@ -95,12 +96,13 @@ class router(router_tech):
def retrieve_pins(self,pin_name): def retrieve_pins(self,pin_name):
""" """
Retrieve the pin shapes from the layout. Retrieve the pin shapes on metal 3 from the layout.
""" """
shape_list=self.layout.getAllPinShapesByLabel(str(pin_name)) debug.info(2,"Retrieving pins for {}.".format(pin_name))
shape_list=self.layout.getAllPinShapes(str(pin_name))
pin_set = set() pin_set = set()
for shape in shape_list: for shape in shape_list:
(name,layer,boundary)=shape (layer,boundary)=shape
# GDSMill boundaries are in (left, bottom, right, top) order # GDSMill boundaries are in (left, bottom, right, top) order
# so repack and snap to the grid # so repack and snap to the grid
ll = vector(boundary[0],boundary[1]).snap_to_grid() ll = vector(boundary[0],boundary[1]).snap_to_grid()
@ -125,10 +127,14 @@ class router(router_tech):
Pin can either be a label or a location,layer pair: [[x,y],layer]. Pin can either be a label or a location,layer pair: [[x,y],layer].
""" """
debug.info(1,"Finding pins for {}.".format(pin_name)) debug.info(1,"Finding pins for {}.".format(pin_name))
import datetime
from globals import print_time
start_time = datetime.datetime.now()
self.retrieve_pins(pin_name) self.retrieve_pins(pin_name)
print_time("Retrieve pins", datetime.datetime.now(), start_time)
start_time = datetime.datetime.now()
self.analyze_pins(pin_name) self.analyze_pins(pin_name)
print_time("Analyze pins", datetime.datetime.now(), start_time)
def find_blockages(self): def find_blockages(self):
""" """
@ -443,7 +449,7 @@ class router(router_tech):
Recursive find boundaries as blockages to the routing grid. Recursive find boundaries as blockages to the routing grid.
""" """
shapes = self.layout.getAllShapesInStructureList(layer_num) shapes = self.layout.getAllShapes(layer_num)
for boundary in shapes: for boundary in shapes:
ll = vector(boundary[0],boundary[1]) ll = vector(boundary[0],boundary[1])
ur = vector(boundary[2],boundary[3]) ur = vector(boundary[2],boundary[3])
@ -626,6 +632,8 @@ class router(router_tech):
""" """
Analyze the shapes of a pin and combine them into groups which are connected. Analyze the shapes of a pin and combine them into groups which are connected.
""" """
debug.info(2,"Analyzing pin groups for {}.".format(pin_name))
pin_set = self.pins[pin_name] pin_set = self.pins[pin_name]
local_debug = False local_debug = False

View File

@ -16,22 +16,25 @@ class library_lvs_test(openram_test):
import verify import verify
(gds_dir, sp_dir, allnames) = setup_files() (gds_dir, sp_dir, allnames) = setup_files()
drc_errors = 0
lvs_errors = 0 lvs_errors = 0
debug.info(1, "Performing LVS on: " + ", ".join(allnames)) debug.info(1, "Performing LVS on: " + ", ".join(allnames))
for f in allnames: for f in allnames:
gds_name = "{0}/{1}.gds".format(gds_dir, f) gds_name = "{0}/{1}.gds".format(gds_dir, f)
sp_name = "{0}/{1}.sp".format(sp_dir, f) sp_name = "{0}/{1}.sp".format(sp_dir, f)
name = re.sub('\.gds$', '', f)
if not os.path.isfile(gds_name): if not os.path.isfile(gds_name):
lvs_errors += 1 lvs_errors += 1
debug.error("Missing GDS file {}".format(gds_name)) debug.error("Missing GDS file {}".format(gds_name))
if not os.path.isfile(sp_name): if not os.path.isfile(sp_name):
lvs_errors += 1 lvs_errors += 1
debug.error("Missing SPICE file {}".format(gds_name)) debug.error("Missing SPICE file {}".format(gds_name))
drc_errors += verify.run_drc(name, gds_name)
lvs_errors += verify.run_lvs(f, gds_name, sp_name) lvs_errors += verify.run_lvs(f, gds_name, sp_name)
# fail if the error count is not zero # fail if the error count is not zero
self.assertEqual(lvs_errors, 0) self.assertEqual(drc_errors+lvs_errors, 0)
globals.end_openram() globals.end_openram()
def setup_files(): def setup_files():