mirror of https://github.com/VLSIDA/OpenRAM.git
Rename unit test files according to test. Modify off-grid pins and blockages. Reorganize router code a bit.
This commit is contained in:
parent
1f5841b933
commit
0766db9e11
|
|
@ -650,7 +650,7 @@ class VlsiLayout:
|
|||
cellBoundary[3]=right_top_Y
|
||||
return cellBoundary
|
||||
|
||||
def readPin(self,label_name):
|
||||
def readPinShape(self,label_name):
|
||||
"""
|
||||
Search for a pin label and return the largest enclosing rectangle
|
||||
on the same layer as the pin label.
|
||||
|
|
@ -663,7 +663,7 @@ class VlsiLayout:
|
|||
label_layer = Text.drawingLayer
|
||||
label_coordinate = Text.coordinates
|
||||
|
||||
pin_boundaries=self.readAllPinInStructureList(label_coordinate, label_layer)
|
||||
pin_boundaries=self.readAllPinShapesInStructureList(label_coordinate, label_layer)
|
||||
|
||||
# sort the boundaries, return the max area pin boundary
|
||||
pin_boundaries.sort(cmpBoundaryAreas,reverse=True)
|
||||
|
|
@ -675,7 +675,7 @@ class VlsiLayout:
|
|||
|
||||
return [label_name, label_layer, pin_boundary]
|
||||
|
||||
def readAllPin(self,label_name):
|
||||
def readAllPinShapes(self,label_name):
|
||||
"""
|
||||
Search for a pin label and return ALL the enclosing rectangles on the same layer
|
||||
as the pin label.
|
||||
|
|
@ -688,7 +688,7 @@ class VlsiLayout:
|
|||
label_layer = Text.drawingLayer
|
||||
label_coordinate = Text.coordinates
|
||||
|
||||
pin_boundaries=self.readAllPinInStructureList(label_coordinate, label_layer)
|
||||
pin_boundaries=self.readAllPinShapesInStructureList(label_coordinate, label_layer)
|
||||
|
||||
# Convert to user units
|
||||
new_boundaries = []
|
||||
|
|
@ -699,7 +699,7 @@ class VlsiLayout:
|
|||
|
||||
return [label_name, label_layer, new_boundaries]
|
||||
|
||||
def readAllPinInStructureList(self,label_coordinates,layer):
|
||||
def readAllPinShapesInStructureList(self,label_coordinates,layer):
|
||||
"""
|
||||
Given the label coordinate, search for enclosing structures on the given layer.
|
||||
Return the single biggest area rectangle.
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ class grid:
|
|||
|
||||
|
||||
|
||||
def view(self):
|
||||
def view(self,filename="test.png"):
|
||||
"""
|
||||
View the data by creating an RGB array and mapping the data
|
||||
structure to the RGB color palette.
|
||||
"""
|
||||
|
||||
v_map = np.zeros((self.width,self.height,3), 'uint8')
|
||||
mid_map = np.ones((25,self.height,3), 'uint8')
|
||||
mid_map = np.ones((10,self.height,3), 'uint8')
|
||||
h_map = np.ones((self.width,self.height,3), 'uint8')
|
||||
|
||||
# We shouldn't have a path greater than 50% the HPWL
|
||||
|
|
@ -62,12 +62,12 @@ class grid:
|
|||
#h_img.show()
|
||||
|
||||
# concatenate them into a plot with the two layers
|
||||
img = Image.new('RGB', (2*self.width+25, self.height))
|
||||
img = Image.new('RGB', (2*self.width+10, self.height))
|
||||
img.paste(h_img, (0,0))
|
||||
img.paste(mid_img, (self.width,0))
|
||||
img.paste(v_img, (self.width+25,0))
|
||||
img.show()
|
||||
img.save("test.png")
|
||||
img.paste(v_img, (self.width+10,0))
|
||||
#img.show()
|
||||
img.save(filename)
|
||||
|
||||
def set_property(self,ll,ur,z,name,value=True):
|
||||
assert(ur[1] >= ll[1] and ur[0] >= ll[0])
|
||||
|
|
@ -135,7 +135,6 @@ class grid:
|
|||
cost = self.cost(newpath) + self.cost_to_target(n)
|
||||
self.q.put((cost,newpath))
|
||||
|
||||
self.view()
|
||||
debug.error("Unable to route path. Expand area?",-1)
|
||||
|
||||
def is_target(self,point):
|
||||
|
|
|
|||
|
|
@ -11,29 +11,33 @@ import grid
|
|||
class router:
|
||||
"""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.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, gds_name):
|
||||
"""Use the gds file for the blockages with the top module topName and
|
||||
layers for the layers to route on
|
||||
|
||||
"""
|
||||
# Load the gds file and read in all the shapes
|
||||
self.gds_name = gds_name
|
||||
self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
|
||||
self.reader = gdsMill.Gds2reader(self.layout)
|
||||
self.reader.loadFromFile(gds_name)
|
||||
self.top_name = self.layout.rootStructureName
|
||||
|
||||
# A list of pin names for source and dest
|
||||
self.pin_names = []
|
||||
# The map of pin names to list of all pin shapes for a pin.
|
||||
self.pin_shapes = {}
|
||||
# Used to track which shapes should not become blockages
|
||||
self.all_pin_shapes = []
|
||||
# The corresponding layers of the above pin shapes
|
||||
self.pin_layers = {}
|
||||
|
||||
# Used to track which shapes should not become blockages. This
|
||||
# will contain all of both source and dest pin shapes in units not tracks.
|
||||
self.all_pin_shapes = []
|
||||
|
||||
# The boundary will determine the limits to the size of the routing grid
|
||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
self.ll = vector(self.boundary[0])
|
||||
self.ur = vector(self.boundary[1])
|
||||
self.size = self.ur - self.ll
|
||||
|
||||
|
||||
def set_top(self,top_name):
|
||||
|
|
@ -53,7 +57,7 @@ class router:
|
|||
self.horiz_layer_width = tech.drc["minwidth_{0}".format(horiz_layer)]
|
||||
self.horiz_layer_number = tech.layer[horiz_layer]
|
||||
|
||||
# contacted track spacing
|
||||
# Contacted track spacing.
|
||||
via_connect = contact(self.layers, (1, 1))
|
||||
max_via_size = max(via_connect.width,via_connect.height)
|
||||
horiz_layer_spacing = tech.drc[str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name)]
|
||||
|
|
@ -61,39 +65,42 @@ class router:
|
|||
self.horiz_track_width = max_via_size + horiz_layer_spacing
|
||||
self.vert_track_width = max_via_size + vert_layer_spacing
|
||||
|
||||
# This is so we can use a single resolution grid for both layers
|
||||
# We'll keep horizontal and vertical tracks the same for simplicity.
|
||||
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
||||
debug.info(1,"Track width:"+str(self.track_width))
|
||||
debug.info(1,"Track width: "+str(self.track_width))
|
||||
|
||||
self.track_widths = [self.track_width] * 2
|
||||
self.track_factor = [1/self.track_width] * 2
|
||||
debug.info(1,"Track factor: {0}".format(self.track_factor))
|
||||
|
||||
|
||||
|
||||
def create_routing_grid(self):
|
||||
""" Create a routing grid that spans given area. Wires cannot exist outside region. """
|
||||
"""
|
||||
Create a routing grid that spans given area. Wires cannot exist outside region.
|
||||
"""
|
||||
# We will add a halo around the boundary
|
||||
# of this many tracks
|
||||
track_halo = 5
|
||||
debug.info(1,"Size: {0} x {1}".format(self.size.x,self.size.y))
|
||||
size = self.ur - self.ll
|
||||
debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
|
||||
|
||||
# pad the tracks on each side by the halo as well
|
||||
self.left_in_tracks = int(math.floor(self.ll.x/self.track_width)) - track_halo
|
||||
self.bottom_in_tracks = int(math.floor(self.ll.y/self.track_width)) - track_halo
|
||||
self.right_in_tracks = int(math.ceil(self.ur.x/self.track_width)) + track_halo
|
||||
self.top_in_tracks = int(math.ceil(self.ur.y/self.track_width)) + track_halo
|
||||
# The routing grid starts at the self.ll and goes up/right
|
||||
# The +1 is because the source/dest object may get expanded outside the region
|
||||
self.height_in_tracks = int(math.ceil(self.ur.x/self.track_width))+2
|
||||
self.width_in_tracks = int(math.ceil(self.ur.y/self.track_width))+2
|
||||
|
||||
# We will offset so th lower left is track 0,0
|
||||
self.track_offset = vector(-self.left_in_tracks,-self.bottom_in_tracks)
|
||||
|
||||
self.width_in_tracks = self.right_in_tracks - self.left_in_tracks
|
||||
self.height_in_tracks = self.top_in_tracks - self.bottom_in_tracks
|
||||
|
||||
debug.info(1,"Size (in tracks): {0} x {1}".format(self.width_in_tracks, self.height_in_tracks))
|
||||
debug.info(1,"Size (in tracks, from ll): {0} x {1}".format(self.width_in_tracks, self.height_in_tracks))
|
||||
|
||||
self.rg = grid.grid(self.height_in_tracks,self.width_in_tracks)
|
||||
|
||||
|
||||
def find_pin(self,pin):
|
||||
""" Finds the pin shapes and converts to tracks """
|
||||
(pin_name,pin_layer,pin_shapes) = self.layout.readAllPin(str(pin))
|
||||
"""
|
||||
Finds the pin shapes and converts to tracks
|
||||
"""
|
||||
|
||||
# Returns all the shapes that enclose a pin on a given layer
|
||||
(pin_name,pin_layer,pin_shapes) = self.layout.readAllPinShapes(str(pin))
|
||||
|
||||
self.pin_shapes[str(pin)]=[]
|
||||
self.pin_names.append(pin_name)
|
||||
|
|
@ -102,21 +109,26 @@ class router:
|
|||
debug.info(2,"Find pin {0} layer {1} shape {2}".format(pin_name,str(pin_layer),str(pin_shape)))
|
||||
# repack the shape as a pair of vectors rather than four values
|
||||
shape=[vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])]
|
||||
new_shape = self.convert_shape_to_tracks(shape,round_bigger=False)
|
||||
self.pin_shapes[str(pin)].append(new_shape)
|
||||
self.all_pin_shapes.append(new_shape)
|
||||
# convert the pin coordinates to tracks and round the sizes down
|
||||
self.pin_shapes[str(pin)].append(shape)
|
||||
self.pin_layers[str(pin)] = pin_layer
|
||||
self.all_pin_shapes.append(shape)
|
||||
|
||||
return self.pin_shapes[str(pin)]
|
||||
|
||||
def find_blockages(self):
|
||||
"""
|
||||
Iterate through all the layers and write the obstacles to the routing grid.
|
||||
"""
|
||||
if len(self.pin_names)!=2:
|
||||
debug.error("Must set pins before creating blockages.",-1)
|
||||
|
||||
for layer in self.layers:
|
||||
self.write_obstacle(self.top_name)
|
||||
|
||||
def clear_pins(self):
|
||||
"""
|
||||
Reset the source and destination pins to start a new routing.
|
||||
"""
|
||||
self.source = []
|
||||
self.dest = []
|
||||
|
||||
|
|
@ -125,42 +137,79 @@ class router:
|
|||
Route a single source-destination net and return
|
||||
the simplified rectilinear path.
|
||||
"""
|
||||
# Clear the pins if we have previously routed
|
||||
self.clear_pins()
|
||||
|
||||
# Set up layers and track sizes
|
||||
self.set_layers(layers)
|
||||
|
||||
# Creat a routing grid over the entire area
|
||||
# FIXME: This could be created only over the routing region,
|
||||
# but this is simplest for now.
|
||||
self.create_routing_grid()
|
||||
|
||||
self.set_source(src)
|
||||
|
||||
self.set_target(dest)
|
||||
|
||||
self.find_blockages()
|
||||
|
||||
self.rg.view("preroute.png")
|
||||
|
||||
# returns the path in tracks
|
||||
path = self.rg.route()
|
||||
self.path = self.rg.route()
|
||||
debug.info(1,"Found path. ")
|
||||
debug.info(2,str(path))
|
||||
self.set_path(path)
|
||||
# First, simplify the path.
|
||||
contracted_path = self.contract_path(path)
|
||||
debug.info(1,str(contracted_path))
|
||||
debug.info(2,str(self.path))
|
||||
self.set_path(self.path)
|
||||
|
||||
self.rg.view("postroute.png")
|
||||
return
|
||||
|
||||
def add_route(self,cell):
|
||||
"""
|
||||
Add the current wire route to the given design instance.
|
||||
"""
|
||||
# First, simplify the path for
|
||||
contracted_path = self.contract_path(self.path)
|
||||
debug.info(1,str(contracted_path))
|
||||
|
||||
# Make sure there's a pin enclosure on the source and dest
|
||||
src_shape = self.convert_track_to_shape(contracted_path[0])
|
||||
cell.add_rect(layer=self.layers[0],
|
||||
offset=src_shape[0],
|
||||
width=src_shape[1].x-src_shape[0].x,
|
||||
height=src_shape[1].y-src_shape[0].y)
|
||||
|
||||
dest_shape = self.convert_track_to_shape(contracted_path[-1])
|
||||
cell.add_rect(layer=self.layers[0],
|
||||
offset=dest_shape[0],
|
||||
width=dest_shape[1].x-dest_shape[0].x,
|
||||
height=dest_shape[1].y-dest_shape[0].y)
|
||||
|
||||
|
||||
# convert the path back to absolute units from tracks
|
||||
abs_path = map(self.convert_point_to_units,contracted_path)
|
||||
debug.info(1,str(abs_path))
|
||||
|
||||
# Make sure there's a pin enclosure on the source and dest
|
||||
src_shape = self.convert_track_to_shape(contracted_path[0])
|
||||
dest_shape = self.convert_track_to_shape(contracted_path[-1])
|
||||
cell.add_wire(self.layers,abs_path)
|
||||
|
||||
return (src_shape,abs_path,dest_shape)
|
||||
|
||||
def create_steiner_routes(self,pins):
|
||||
"""Find a set of steiner points and then return the list of
|
||||
point-to-point routes."""
|
||||
"""
|
||||
Find a set of steiner points and then return the list of
|
||||
point-to-point routes.
|
||||
"""
|
||||
pass
|
||||
|
||||
def find_steiner_points(self,pins):
|
||||
""" Find the set of steiner points and return them."""
|
||||
"""
|
||||
Find the set of steiner points and return them.
|
||||
"""
|
||||
pass
|
||||
|
||||
def translate_coordinates(self, coord, mirr, angle, xyShift):
|
||||
"""Calculate coordinates after flip, rotate, and shift"""
|
||||
"""
|
||||
Calculate coordinates after flip, rotate, and shift
|
||||
"""
|
||||
coordinate = []
|
||||
for item in coord:
|
||||
x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
|
||||
|
|
@ -169,7 +218,9 @@ class router:
|
|||
return coordinate
|
||||
|
||||
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 = [tech.GDS["unit"][0]] * 2
|
||||
ll=shape[0].scale(unit_factor)
|
||||
ur=shape[1].scale(unit_factor)
|
||||
|
|
@ -177,7 +228,9 @@ class router:
|
|||
|
||||
|
||||
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])
|
||||
maxx = max(coord[0][0], coord[1][0], coord[2][0], coord[3][0])
|
||||
|
|
@ -188,71 +241,81 @@ class router:
|
|||
return coordinate
|
||||
|
||||
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:
|
||||
inertia = 1
|
||||
return 1
|
||||
elif p0.y==p1.y:
|
||||
inertia = 0
|
||||
return 0
|
||||
else:
|
||||
inertia = 2
|
||||
return inertia
|
||||
# z direction
|
||||
return 2
|
||||
|
||||
|
||||
def contract_path(self,path):
|
||||
"""
|
||||
Remove intermediate points in a rectilinear path.
|
||||
Remove intermediate points in a rectilinear path.
|
||||
"""
|
||||
newpath = [path[0]]
|
||||
for i in range(len(path)-1):
|
||||
if i==0:
|
||||
continue
|
||||
for i in range(1,len(path)-1):
|
||||
prev_inertia=self.get_inertia(path[i-1],path[i])
|
||||
next_inertia=self.get_inertia(path[i],path[i+1])
|
||||
|
||||
# if we switch directions, add the point, otherwise don't
|
||||
if prev_inertia!=next_inertia:
|
||||
newpath.append(path[i])
|
||||
else:
|
||||
continue
|
||||
|
||||
# always add the last path
|
||||
newpath.append(path[-1])
|
||||
|
||||
return newpath
|
||||
|
||||
def set_path(self,path):
|
||||
"""
|
||||
Mark the path in the routing grid.
|
||||
"""
|
||||
debug.info(3,"Set path: " + str(path))
|
||||
self.rg.set_path(path)
|
||||
|
||||
def set_source(self,name):
|
||||
"""
|
||||
Mark the grids that are in the pin rectangle ranges to have the source property.
|
||||
"""
|
||||
shapes = self.find_pin(name)
|
||||
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
||||
for shape in shapes:
|
||||
debug.info(1,"Set source: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
||||
self.rg.set_source(shape[0],shape[1],zindex)
|
||||
shape_in_tracks=self.convert_shape_to_tracks(shape)
|
||||
debug.info(1,"Set source: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex))
|
||||
self.rg.set_source(shape_in_tracks[0],shape_in_tracks[1],zindex)
|
||||
|
||||
|
||||
def set_target(self,name):
|
||||
"""
|
||||
Mark the grids that are in the pin rectangle ranges to have the target property.
|
||||
"""
|
||||
shapes = self.find_pin(name)
|
||||
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
||||
for shape in shapes:
|
||||
debug.info(1,"Set target: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
||||
self.rg.set_target(shape[0],shape[1],zindex)
|
||||
shape_in_tracks=self.convert_shape_to_tracks(shape)
|
||||
debug.info(1,"Set target: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex))
|
||||
self.rg.set_target(shape_in_tracks[0],shape_in_tracks[1],zindex)
|
||||
|
||||
def write_obstacle(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
|
||||
"""Recursive write boundaries on each Structure in GDS file to LEF"""
|
||||
|
||||
"""
|
||||
Recursive write boundaries as blockages to the routing grid.
|
||||
Recurses for each Structure in GDS.
|
||||
"""
|
||||
for boundary in self.layout.structures[sref].boundaries:
|
||||
coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
|
||||
shape_coords = self.min_max_coord(coord_trans)
|
||||
shape = self.convert_shape_to_units(shape_coords)
|
||||
|
||||
# only consider the two layers that we are routing on
|
||||
if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
|
||||
# We round the pins down, so we must do this to skip them
|
||||
pin_shape_tracks=self.convert_units_to_tracks(shape,round_bigger=False)
|
||||
|
||||
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1
|
||||
# don't add a blockage if this shape was a pin shape
|
||||
if pin_shape_tracks not in self.all_pin_shapes:
|
||||
# inflate the ll and ur by 1 track in each direction
|
||||
[ll,ur]=self.convert_units_to_tracks(shape)
|
||||
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1
|
||||
if shape not in self.all_pin_shapes:
|
||||
[ll,ur]=self.convert_shape_to_tracks(shape)
|
||||
self.rg.add_blockage(ll,ur,zlayer)
|
||||
|
||||
|
||||
|
|
@ -277,55 +340,42 @@ class router:
|
|||
"""
|
||||
Convert a path set of tracks to center line path.
|
||||
"""
|
||||
track_factor = [self.track_width] * 2
|
||||
# we can ignore the layers here
|
||||
# add_wire will filter out duplicates
|
||||
pt = vector(p[0],p[1])
|
||||
pt=pt.scale(track_factor)
|
||||
return snap_to_grid(pt)
|
||||
pt=pt.scale(self.track_widths)
|
||||
return pt
|
||||
|
||||
def convert_units_to_tracks(self,shape,round_bigger=True):
|
||||
def convert_shape_to_tracks(self,shape,round_bigger=False):
|
||||
"""
|
||||
Convert a rectangular shape into track units.
|
||||
"""
|
||||
[ll,ur] = shape
|
||||
|
||||
# offset lowest corner object to to (-track halo,-track halo)
|
||||
ll = snap_to_grid(ll)
|
||||
ur = snap_to_grid(ur)
|
||||
|
||||
# to scale coordinates to tracks
|
||||
track_factor = [1/self.track_width] * 2
|
||||
|
||||
|
||||
|
||||
if round_bigger: # Always round blockage shapes up.
|
||||
ll = ll.scale(track_factor).floor() + self.track_offset
|
||||
ur = ur.scale(track_factor).ceil() + self.track_offset
|
||||
if ll.x<0:
|
||||
ll.x=0
|
||||
if ll.y<0:
|
||||
ll.y=0
|
||||
else: # Always round pin shapes down
|
||||
ll = ll.scale(track_factor).round()
|
||||
ur = ur.scale(track_factor).round()
|
||||
|
||||
debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
|
||||
ll=ll.scale(self.track_factor)
|
||||
ur=ur.scale(self.track_factor)
|
||||
ll = ll.floor() if round_bigger else ll.round()
|
||||
ur = ur.ceil() if round_bigger else ur.round()
|
||||
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
|
||||
return [ll,ur]
|
||||
|
||||
|
||||
def convert_track_to_shape(self,tracks):
|
||||
def convert_track_to_shape(self,track):
|
||||
"""
|
||||
Convert a set of track units into a rectangle shape.
|
||||
Convert a grid point into a rectangle shape that occupies the centered
|
||||
track.
|
||||
"""
|
||||
|
||||
tracks = tracks - self.track_offset
|
||||
# to scale coordinates to tracks
|
||||
# FIXME: should be offset by spacing, not track width
|
||||
x = tracks.x*self.track_width - 0.25*self.track_width
|
||||
y = tracks.y*self.track_width - 0.25*self.track_width
|
||||
# FIXME: should be the metal width no the track width?
|
||||
x = track.x*self.track_width - 0.5*self.track_width
|
||||
y = track.y*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(0.5*self.track_width,0.5*self.track_width))
|
||||
ur = snap_to_grid(ll + vector(self.track_width,self.track_width))
|
||||
|
||||
return [ll,ur]
|
||||
|
||||
|
|
|
|||
|
|
@ -49,21 +49,11 @@ class no_blockages_test(unittest.TestCase):
|
|||
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
|
||||
r=router.router(self.gdsname)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
(src_rect,path,dest_rect)=r.route(layer_stack,src="A",dest="B")
|
||||
#r.rg.view()
|
||||
self.add_rect(layer=layer_stack[0],
|
||||
offset=src_rect[0],
|
||||
width=src_rect[1].x-src_rect[0].x,
|
||||
height=src_rect[1].y-src_rect[0].y)
|
||||
self.add_wire(layer_stack,path)
|
||||
self.add_rect(layer=layer_stack[0],
|
||||
offset=dest_rect[0],
|
||||
width=dest_rect[1].x-dest_rect[0].x,
|
||||
height=dest_rect[1].y-dest_rect[0].y)
|
||||
|
||||
r.route(layer_stack,src="A",dest="B")
|
||||
r.add_route(self)
|
||||
|
||||
|
||||
r = routing("test1", "AB_no_blockages")
|
||||
r = routing("test1", "01_no_blockages_test")
|
||||
self.local_check(r)
|
||||
|
||||
# fails if there are any DRC errors on any cells
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -45,7 +45,7 @@ def auto_measure_libcell(pin_list, name, units, layer):
|
|||
[cell["width"], cell["height"]] = measure_result
|
||||
|
||||
for pin in pin_list:
|
||||
cell[str(pin)] = gds_pin_center(cell_vlsi.readPin(str(pin)))
|
||||
cell[str(pin)] = gds_pin_center(cell_vlsi.readPinShape(str(pin)))
|
||||
return cell
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue