mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-08-22 06:07:31 +02:00
Rename unit test files according to test. Modify off-grid pins and blockages. Reorganize router code a bit.
This commit is contained in:
@@ -650,7 +650,7 @@ class VlsiLayout:
|
|||||||
cellBoundary[3]=right_top_Y
|
cellBoundary[3]=right_top_Y
|
||||||
return cellBoundary
|
return cellBoundary
|
||||||
|
|
||||||
def readPin(self,label_name):
|
def readPinShape(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.
|
||||||
@@ -663,7 +663,7 @@ class VlsiLayout:
|
|||||||
label_layer = Text.drawingLayer
|
label_layer = Text.drawingLayer
|
||||||
label_coordinate = Text.coordinates
|
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
|
# sort the boundaries, return the max area pin boundary
|
||||||
pin_boundaries.sort(cmpBoundaryAreas,reverse=True)
|
pin_boundaries.sort(cmpBoundaryAreas,reverse=True)
|
||||||
@@ -675,7 +675,7 @@ class VlsiLayout:
|
|||||||
|
|
||||||
return [label_name, label_layer, pin_boundary]
|
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
|
Search for a pin label and return ALL the enclosing rectangles on the same layer
|
||||||
as the pin label.
|
as the pin label.
|
||||||
@@ -688,7 +688,7 @@ class VlsiLayout:
|
|||||||
label_layer = Text.drawingLayer
|
label_layer = Text.drawingLayer
|
||||||
label_coordinate = Text.coordinates
|
label_coordinate = Text.coordinates
|
||||||
|
|
||||||
pin_boundaries=self.readAllPinInStructureList(label_coordinate, label_layer)
|
pin_boundaries=self.readAllPinShapesInStructureList(label_coordinate, label_layer)
|
||||||
|
|
||||||
# Convert to user units
|
# Convert to user units
|
||||||
new_boundaries = []
|
new_boundaries = []
|
||||||
@@ -699,7 +699,7 @@ class VlsiLayout:
|
|||||||
|
|
||||||
return [label_name, label_layer, new_boundaries]
|
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.
|
Given the label coordinate, search for enclosing structures on the given layer.
|
||||||
Return the single biggest area rectangle.
|
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
|
View the data by creating an RGB array and mapping the data
|
||||||
structure to the RGB color palette.
|
structure to the RGB color palette.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
v_map = np.zeros((self.width,self.height,3), 'uint8')
|
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')
|
h_map = np.ones((self.width,self.height,3), 'uint8')
|
||||||
|
|
||||||
# We shouldn't have a path greater than 50% the HPWL
|
# We shouldn't have a path greater than 50% the HPWL
|
||||||
@@ -62,12 +62,12 @@ class grid:
|
|||||||
#h_img.show()
|
#h_img.show()
|
||||||
|
|
||||||
# concatenate them into a plot with the two layers
|
# 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(h_img, (0,0))
|
||||||
img.paste(mid_img, (self.width,0))
|
img.paste(mid_img, (self.width,0))
|
||||||
img.paste(v_img, (self.width+25,0))
|
img.paste(v_img, (self.width+10,0))
|
||||||
img.show()
|
#img.show()
|
||||||
img.save("test.png")
|
img.save(filename)
|
||||||
|
|
||||||
def set_property(self,ll,ur,z,name,value=True):
|
def set_property(self,ll,ur,z,name,value=True):
|
||||||
assert(ur[1] >= ll[1] and ur[0] >= ll[0])
|
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)
|
cost = self.cost(newpath) + self.cost_to_target(n)
|
||||||
self.q.put((cost,newpath))
|
self.q.put((cost,newpath))
|
||||||
|
|
||||||
self.view()
|
|
||||||
debug.error("Unable to route path. Expand area?",-1)
|
debug.error("Unable to route path. Expand area?",-1)
|
||||||
|
|
||||||
def is_target(self,point):
|
def is_target(self,point):
|
||||||
|
|||||||
+148
-98
@@ -11,29 +11,33 @@ import grid
|
|||||||
class router:
|
class router:
|
||||||
"""A router class to read an obstruction map from a gds and plan a
|
"""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.
|
route on a given layer. This is limited to two layer routes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, gds_name):
|
def __init__(self, gds_name):
|
||||||
"""Use the gds file for the blockages with the top module topName and
|
"""Use the gds file for the blockages with the top module topName and
|
||||||
layers for the layers to route on
|
layers for the layers to route on
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# Load the gds file and read in all the shapes
|
||||||
self.gds_name = gds_name
|
self.gds_name = gds_name
|
||||||
self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
|
self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
|
||||||
self.reader = gdsMill.Gds2reader(self.layout)
|
self.reader = gdsMill.Gds2reader(self.layout)
|
||||||
self.reader.loadFromFile(gds_name)
|
self.reader.loadFromFile(gds_name)
|
||||||
self.top_name = self.layout.rootStructureName
|
self.top_name = self.layout.rootStructureName
|
||||||
|
|
||||||
|
# A list of pin names for source and dest
|
||||||
self.pin_names = []
|
self.pin_names = []
|
||||||
|
# The map of pin names to list of all pin shapes for a pin.
|
||||||
self.pin_shapes = {}
|
self.pin_shapes = {}
|
||||||
# Used to track which shapes should not become blockages
|
# The corresponding layers of the above pin shapes
|
||||||
self.all_pin_shapes = []
|
|
||||||
self.pin_layers = {}
|
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.boundary = self.layout.measureBoundary(self.top_name)
|
||||||
self.ll = vector(self.boundary[0])
|
self.ll = vector(self.boundary[0])
|
||||||
self.ur = vector(self.boundary[1])
|
self.ur = vector(self.boundary[1])
|
||||||
self.size = self.ur - self.ll
|
|
||||||
|
|
||||||
|
|
||||||
def set_top(self,top_name):
|
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_width = tech.drc["minwidth_{0}".format(horiz_layer)]
|
||||||
self.horiz_layer_number = tech.layer[horiz_layer]
|
self.horiz_layer_number = tech.layer[horiz_layer]
|
||||||
|
|
||||||
# contacted track spacing
|
# Contacted track spacing.
|
||||||
via_connect = contact(self.layers, (1, 1))
|
via_connect = contact(self.layers, (1, 1))
|
||||||
max_via_size = max(via_connect.width,via_connect.height)
|
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)]
|
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.horiz_track_width = max_via_size + horiz_layer_spacing
|
||||||
self.vert_track_width = max_via_size + vert_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)
|
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):
|
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
|
# We will add a halo around the boundary
|
||||||
# of this many tracks
|
# of this many tracks
|
||||||
track_halo = 5
|
size = self.ur - self.ll
|
||||||
debug.info(1,"Size: {0} x {1}".format(self.size.x,self.size.y))
|
debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
|
||||||
|
|
||||||
# pad the tracks on each side by the halo as well
|
# The routing grid starts at the self.ll and goes up/right
|
||||||
self.left_in_tracks = int(math.floor(self.ll.x/self.track_width)) - track_halo
|
# The +1 is because the source/dest object may get expanded outside the region
|
||||||
self.bottom_in_tracks = int(math.floor(self.ll.y/self.track_width)) - track_halo
|
self.height_in_tracks = int(math.ceil(self.ur.x/self.track_width))+2
|
||||||
self.right_in_tracks = int(math.ceil(self.ur.x/self.track_width)) + track_halo
|
self.width_in_tracks = int(math.ceil(self.ur.y/self.track_width))+2
|
||||||
self.top_in_tracks = int(math.ceil(self.ur.y/self.track_width)) + track_halo
|
|
||||||
|
|
||||||
# We will offset so th lower left is track 0,0
|
debug.info(1,"Size (in tracks, from ll): {0} x {1}".format(self.width_in_tracks, self.height_in_tracks))
|
||||||
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))
|
|
||||||
|
|
||||||
self.rg = grid.grid(self.height_in_tracks,self.width_in_tracks)
|
self.rg = grid.grid(self.height_in_tracks,self.width_in_tracks)
|
||||||
|
|
||||||
|
|
||||||
def find_pin(self,pin):
|
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_shapes[str(pin)]=[]
|
||||||
self.pin_names.append(pin_name)
|
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)))
|
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
|
# 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])]
|
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)
|
# convert the pin coordinates to tracks and round the sizes down
|
||||||
self.pin_shapes[str(pin)].append(new_shape)
|
self.pin_shapes[str(pin)].append(shape)
|
||||||
self.all_pin_shapes.append(new_shape)
|
|
||||||
self.pin_layers[str(pin)] = pin_layer
|
self.pin_layers[str(pin)] = pin_layer
|
||||||
|
self.all_pin_shapes.append(shape)
|
||||||
|
|
||||||
return self.pin_shapes[str(pin)]
|
return self.pin_shapes[str(pin)]
|
||||||
|
|
||||||
def find_blockages(self):
|
def find_blockages(self):
|
||||||
|
"""
|
||||||
|
Iterate through all the layers and write the obstacles to the routing grid.
|
||||||
|
"""
|
||||||
if len(self.pin_names)!=2:
|
if len(self.pin_names)!=2:
|
||||||
debug.error("Must set pins before creating blockages.",-1)
|
debug.error("Must set pins before creating blockages.",-1)
|
||||||
|
|
||||||
for layer in self.layers:
|
for layer in self.layers:
|
||||||
self.write_obstacle(self.top_name)
|
self.write_obstacle(self.top_name)
|
||||||
|
|
||||||
def clear_pins(self):
|
def clear_pins(self):
|
||||||
|
"""
|
||||||
|
Reset the source and destination pins to start a new routing.
|
||||||
|
"""
|
||||||
self.source = []
|
self.source = []
|
||||||
self.dest = []
|
self.dest = []
|
||||||
|
|
||||||
@@ -125,42 +137,79 @@ class router:
|
|||||||
Route a single source-destination net and return
|
Route a single source-destination net and return
|
||||||
the simplified rectilinear path.
|
the simplified rectilinear path.
|
||||||
"""
|
"""
|
||||||
|
# Clear the pins if we have previously routed
|
||||||
self.clear_pins()
|
self.clear_pins()
|
||||||
|
|
||||||
|
# Set up layers and track sizes
|
||||||
self.set_layers(layers)
|
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.create_routing_grid()
|
||||||
|
|
||||||
self.set_source(src)
|
self.set_source(src)
|
||||||
|
|
||||||
self.set_target(dest)
|
self.set_target(dest)
|
||||||
|
|
||||||
self.find_blockages()
|
self.find_blockages()
|
||||||
|
|
||||||
|
self.rg.view("preroute.png")
|
||||||
|
|
||||||
# returns the path in tracks
|
# returns the path in tracks
|
||||||
path = self.rg.route()
|
self.path = self.rg.route()
|
||||||
debug.info(1,"Found path. ")
|
debug.info(1,"Found path. ")
|
||||||
debug.info(2,str(path))
|
debug.info(2,str(self.path))
|
||||||
self.set_path(path)
|
self.set_path(self.path)
|
||||||
# First, simplify the path.
|
|
||||||
contracted_path = self.contract_path(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))
|
debug.info(1,str(contracted_path))
|
||||||
# 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
|
# Make sure there's a pin enclosure on the source and dest
|
||||||
src_shape = self.convert_track_to_shape(contracted_path[0])
|
src_shape = self.convert_track_to_shape(contracted_path[0])
|
||||||
dest_shape = self.convert_track_to_shape(contracted_path[-1])
|
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))
|
||||||
|
cell.add_wire(self.layers,abs_path)
|
||||||
|
|
||||||
return (src_shape,abs_path,dest_shape)
|
|
||||||
|
|
||||||
def create_steiner_routes(self,pins):
|
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
|
pass
|
||||||
|
|
||||||
def find_steiner_points(self,pins):
|
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
|
pass
|
||||||
|
|
||||||
def translate_coordinates(self, coord, mirr, angle, xyShift):
|
def translate_coordinates(self, coord, mirr, angle, xyShift):
|
||||||
"""Calculate coordinates after flip, rotate, and shift"""
|
"""
|
||||||
|
Calculate coordinates after flip, rotate, and shift
|
||||||
|
"""
|
||||||
coordinate = []
|
coordinate = []
|
||||||
for item in coord:
|
for item in coord:
|
||||||
x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
|
x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
|
||||||
@@ -169,7 +218,9 @@ class router:
|
|||||||
return coordinate
|
return coordinate
|
||||||
|
|
||||||
def convert_shape_to_units(self, shape):
|
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
|
unit_factor = [tech.GDS["unit"][0]] * 2
|
||||||
ll=shape[0].scale(unit_factor)
|
ll=shape[0].scale(unit_factor)
|
||||||
ur=shape[1].scale(unit_factor)
|
ur=shape[1].scale(unit_factor)
|
||||||
@@ -177,7 +228,9 @@ class router:
|
|||||||
|
|
||||||
|
|
||||||
def min_max_coord(self, coord):
|
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 = []
|
coordinate = []
|
||||||
minx = min(coord[0][0], coord[1][0], coord[2][0], coord[3][0])
|
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])
|
maxx = max(coord[0][0], coord[1][0], coord[2][0], coord[3][0])
|
||||||
@@ -188,71 +241,81 @@ class router:
|
|||||||
return coordinate
|
return coordinate
|
||||||
|
|
||||||
def get_inertia(self,p0,p1):
|
def get_inertia(self,p0,p1):
|
||||||
|
"""
|
||||||
|
Sets the direction based on the previous direction we came from.
|
||||||
|
"""
|
||||||
# direction (index) of movement
|
# direction (index) of movement
|
||||||
if p0.x==p1.x:
|
if p0.x==p1.x:
|
||||||
inertia = 1
|
return 1
|
||||||
elif p0.y==p1.y:
|
elif p0.y==p1.y:
|
||||||
inertia = 0
|
return 0
|
||||||
else:
|
else:
|
||||||
inertia = 2
|
# z direction
|
||||||
return inertia
|
return 2
|
||||||
|
|
||||||
|
|
||||||
def contract_path(self,path):
|
def contract_path(self,path):
|
||||||
"""
|
"""
|
||||||
Remove intermediate points in a rectilinear path.
|
Remove intermediate points in a rectilinear path.
|
||||||
"""
|
"""
|
||||||
newpath = [path[0]]
|
newpath = [path[0]]
|
||||||
for i in range(len(path)-1):
|
for i in range(1,len(path)-1):
|
||||||
if i==0:
|
|
||||||
continue
|
|
||||||
prev_inertia=self.get_inertia(path[i-1],path[i])
|
prev_inertia=self.get_inertia(path[i-1],path[i])
|
||||||
next_inertia=self.get_inertia(path[i],path[i+1])
|
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:
|
if prev_inertia!=next_inertia:
|
||||||
newpath.append(path[i])
|
newpath.append(path[i])
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
# always add the last path
|
||||||
newpath.append(path[-1])
|
newpath.append(path[-1])
|
||||||
|
|
||||||
return newpath
|
return newpath
|
||||||
|
|
||||||
def set_path(self,path):
|
def set_path(self,path):
|
||||||
|
"""
|
||||||
|
Mark the path in the routing grid.
|
||||||
|
"""
|
||||||
debug.info(3,"Set path: " + str(path))
|
debug.info(3,"Set path: " + str(path))
|
||||||
self.rg.set_path(path)
|
self.rg.set_path(path)
|
||||||
|
|
||||||
def set_source(self,name):
|
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)
|
shapes = self.find_pin(name)
|
||||||
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
||||||
for shape in shapes:
|
for shape in shapes:
|
||||||
debug.info(1,"Set source: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
shape_in_tracks=self.convert_shape_to_tracks(shape)
|
||||||
self.rg.set_source(shape[0],shape[1],zindex)
|
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):
|
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)
|
shapes = self.find_pin(name)
|
||||||
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
||||||
for shape in shapes:
|
for shape in shapes:
|
||||||
debug.info(1,"Set target: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
shape_in_tracks=self.convert_shape_to_tracks(shape)
|
||||||
self.rg.set_target(shape[0],shape[1],zindex)
|
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)):
|
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:
|
for boundary in self.layout.structures[sref].boundaries:
|
||||||
coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
|
coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
|
||||||
shape_coords = self.min_max_coord(coord_trans)
|
shape_coords = self.min_max_coord(coord_trans)
|
||||||
shape = self.convert_shape_to_units(shape_coords)
|
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]:
|
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
|
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1
|
||||||
pin_shape_tracks=self.convert_units_to_tracks(shape,round_bigger=False)
|
|
||||||
|
|
||||||
# don't add a blockage if this shape was a pin shape
|
# don't add a blockage if this shape was a pin shape
|
||||||
if pin_shape_tracks not in self.all_pin_shapes:
|
if shape not in self.all_pin_shapes:
|
||||||
# inflate the ll and ur by 1 track in each direction
|
[ll,ur]=self.convert_shape_to_tracks(shape)
|
||||||
[ll,ur]=self.convert_units_to_tracks(shape)
|
|
||||||
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1
|
|
||||||
self.rg.add_blockage(ll,ur,zlayer)
|
self.rg.add_blockage(ll,ur,zlayer)
|
||||||
|
|
||||||
|
|
||||||
@@ -277,55 +340,42 @@ class router:
|
|||||||
"""
|
"""
|
||||||
Convert a path set of tracks to center line path.
|
Convert a path set of tracks to center line path.
|
||||||
"""
|
"""
|
||||||
track_factor = [self.track_width] * 2
|
|
||||||
# we can ignore the layers here
|
# we can ignore the layers here
|
||||||
# add_wire will filter out duplicates
|
# add_wire will filter out duplicates
|
||||||
pt = vector(p[0],p[1])
|
pt = vector(p[0],p[1])
|
||||||
pt=pt.scale(track_factor)
|
pt=pt.scale(self.track_widths)
|
||||||
return snap_to_grid(pt)
|
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.
|
Convert a rectangular shape into track units.
|
||||||
"""
|
"""
|
||||||
[ll,ur] = shape
|
[ll,ur] = shape
|
||||||
|
|
||||||
# offset lowest corner object to to (-track halo,-track halo)
|
|
||||||
ll = snap_to_grid(ll)
|
ll = snap_to_grid(ll)
|
||||||
ur = snap_to_grid(ur)
|
ur = snap_to_grid(ur)
|
||||||
|
|
||||||
# to scale coordinates to tracks
|
# to scale coordinates to tracks
|
||||||
track_factor = [1/self.track_width] * 2
|
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()
|
||||||
if round_bigger: # Always round blockage shapes up.
|
ur = ur.ceil() if round_bigger else ur.round()
|
||||||
ll = ll.scale(track_factor).floor() + self.track_offset
|
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
|
||||||
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()
|
|
||||||
|
|
||||||
return [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
|
# to scale coordinates to tracks
|
||||||
# FIXME: should be offset by spacing, not track width
|
# FIXME: should be the metal width no the track width?
|
||||||
x = tracks.x*self.track_width - 0.25*self.track_width
|
x = track.x*self.track_width - 0.5*self.track_width
|
||||||
y = tracks.y*self.track_width - 0.25*self.track_width
|
y = track.y*self.track_width - 0.5*self.track_width
|
||||||
# offset lowest corner object to to (-track halo,-track halo)
|
# offset lowest corner object to to (-track halo,-track halo)
|
||||||
ll = snap_to_grid(vector(x,y))
|
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]
|
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)
|
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
|
||||||
r=router.router(self.gdsname)
|
r=router.router(self.gdsname)
|
||||||
layer_stack =("metal1","via1","metal2")
|
layer_stack =("metal1","via1","metal2")
|
||||||
(src_rect,path,dest_rect)=r.route(layer_stack,src="A",dest="B")
|
r.route(layer_stack,src="A",dest="B")
|
||||||
#r.rg.view()
|
r.add_route(self)
|
||||||
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 = routing("test1", "01_no_blockages_test")
|
||||||
r = routing("test1", "AB_no_blockages")
|
|
||||||
self.local_check(r)
|
self.local_check(r)
|
||||||
|
|
||||||
# fails if there are any DRC errors on any cells
|
# fails if there are any DRC errors on any cells
|
||||||
|
|||||||
Binary file not shown.
+1
-1
@@ -45,7 +45,7 @@ def auto_measure_libcell(pin_list, name, units, layer):
|
|||||||
[cell["width"], cell["height"]] = measure_result
|
[cell["width"], cell["height"]] = measure_result
|
||||||
|
|
||||||
for pin in pin_list:
|
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
|
return cell
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user