mirror of https://github.com/VLSIDA/OpenRAM.git
Merge remote-tracking branch 'private/dev'
This commit is contained in:
commit
c0df3ff1da
|
|
@ -23,10 +23,14 @@ class geometry:
|
||||||
A specific path, shape, or text geometry. Base class for shared
|
A specific path, shape, or text geometry. Base class for shared
|
||||||
items.
|
items.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, lpp=None):
|
||||||
""" By default, everything has no size. """
|
""" By default, everything has no size. """
|
||||||
self.width = 0
|
self.width = 0
|
||||||
self.height = 0
|
self.height = 0
|
||||||
|
if lpp:
|
||||||
|
self.lpp = lpp
|
||||||
|
self.layerNumber = lpp[0]
|
||||||
|
self.layerPurpose = lpp[1]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
|
|
@ -410,10 +414,8 @@ class path(geometry):
|
||||||
|
|
||||||
def __init__(self, lpp, coordinates, path_width):
|
def __init__(self, lpp, coordinates, path_width):
|
||||||
"""Initializes a path for the specified layer"""
|
"""Initializes a path for the specified layer"""
|
||||||
super().__init__()
|
super().__init__(lpp)
|
||||||
self.name = "path"
|
self.name = "path"
|
||||||
self.layerNumber = lpp[0]
|
|
||||||
self.layerPurpose = lpp[1]
|
|
||||||
self.coordinates = map(lambda x: [x[0], x[1]], coordinates)
|
self.coordinates = map(lambda x: [x[0], x[1]], coordinates)
|
||||||
self.coordinates = vector(self.coordinates).snap_to_grid()
|
self.coordinates = vector(self.coordinates).snap_to_grid()
|
||||||
self.path_width = path_width
|
self.path_width = path_width
|
||||||
|
|
@ -448,11 +450,9 @@ class label(geometry):
|
||||||
|
|
||||||
def __init__(self, text, lpp, offset, zoom=None):
|
def __init__(self, text, lpp, offset, zoom=None):
|
||||||
"""Initializes a text label for specified layer"""
|
"""Initializes a text label for specified layer"""
|
||||||
super().__init__()
|
super().__init__(lpp)
|
||||||
self.name = "label"
|
self.name = "label"
|
||||||
self.text = text
|
self.text = text
|
||||||
self.layerNumber = lpp[0]
|
|
||||||
self.layerPurpose = lpp[1]
|
|
||||||
self.offset = vector(offset).snap_to_grid()
|
self.offset = vector(offset).snap_to_grid()
|
||||||
|
|
||||||
if not zoom:
|
if not zoom:
|
||||||
|
|
@ -495,10 +495,8 @@ class rectangle(geometry):
|
||||||
|
|
||||||
def __init__(self, lpp, offset, width, height):
|
def __init__(self, lpp, offset, width, height):
|
||||||
"""Initializes a rectangular shape for specified layer"""
|
"""Initializes a rectangular shape for specified layer"""
|
||||||
super().__init__()
|
super().__init__(lpp)
|
||||||
self.name = "rect"
|
self.name = "rect"
|
||||||
self.layerNumber = lpp[0]
|
|
||||||
self.layerPurpose = lpp[1]
|
|
||||||
self.offset = vector(offset).snap_to_grid()
|
self.offset = vector(offset).snap_to_grid()
|
||||||
self.size = vector(width, height).snap_to_grid()
|
self.size = vector(width, height).snap_to_grid()
|
||||||
self.width = round_to_grid(self.size.x)
|
self.width = round_to_grid(self.size.x)
|
||||||
|
|
|
||||||
|
|
@ -473,11 +473,25 @@ class layout():
|
||||||
"""
|
"""
|
||||||
self.pin_map = {}
|
self.pin_map = {}
|
||||||
|
|
||||||
|
def copy_layout_pin_shapes(self, text):
|
||||||
|
"""
|
||||||
|
Copy the shapes of the layout pins as objects.
|
||||||
|
"""
|
||||||
|
for s in self.pin_map[text]:
|
||||||
|
self.add_rect(layer=s.layer,
|
||||||
|
offset=s.ll(),
|
||||||
|
width=s.width(),
|
||||||
|
height=s.height())
|
||||||
|
|
||||||
def replace_layout_pin(self, text, pin):
|
def replace_layout_pin(self, text, pin):
|
||||||
"""
|
"""
|
||||||
Remove the old pin and replace with a new one
|
Remove the old pin and replace with a new one
|
||||||
"""
|
"""
|
||||||
|
# Keep the shapes as they were used to connect to the router pins
|
||||||
|
self.copy_layout_pin_shapes(text)
|
||||||
|
# Remove the shapes as actual pins
|
||||||
self.remove_layout_pin(text)
|
self.remove_layout_pin(text)
|
||||||
|
# Add the new pin
|
||||||
self.add_layout_pin(text=text,
|
self.add_layout_pin(text=text,
|
||||||
layer=pin.layer,
|
layer=pin.layer,
|
||||||
offset=pin.ll(),
|
offset=pin.ll(),
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,10 @@ class dff_buf(design.design):
|
||||||
well_spacing = max(well_spacing, self.pwell_to_nwell)
|
well_spacing = max(well_spacing, self.pwell_to_nwell)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing + self.well_extend_active, 0))
|
|
||||||
|
well_spacing += self.well_extend_active
|
||||||
|
|
||||||
|
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing, 0))
|
||||||
|
|
||||||
# Add INV2 to the right
|
# Add INV2 to the right
|
||||||
self.inv2_inst.place(vector(self.inv1_inst.rx(), 0))
|
self.inv2_inst.place(vector(self.inv1_inst.rx(), 0))
|
||||||
|
|
|
||||||
|
|
@ -78,81 +78,80 @@ class grid:
|
||||||
for k in self.map:
|
for k in self.map:
|
||||||
self.map[k].blocked=False
|
self.map[k].blocked=False
|
||||||
|
|
||||||
def set_source(self, n, value=True):
|
def clear_source(self):
|
||||||
|
for k in self.map:
|
||||||
|
self.map[k].source=False
|
||||||
|
self.source = set()
|
||||||
|
|
||||||
|
def set_source(self, n):
|
||||||
if not isinstance(n, vector3d):
|
if not isinstance(n, vector3d):
|
||||||
for item in n:
|
for item in n:
|
||||||
self.set_source(item, value)
|
self.set_source(item)
|
||||||
else:
|
else:
|
||||||
self.add_map(n)
|
self.add_map(n)
|
||||||
self.map[n].source=value
|
self.map[n].source=True
|
||||||
|
self.map[n].blocked=False
|
||||||
self.source.add(n)
|
self.source.add(n)
|
||||||
|
|
||||||
def set_target(self, n, value=True):
|
def clear_target(self):
|
||||||
|
for k in self.map:
|
||||||
|
self.map[k].target=False
|
||||||
|
self.target = set()
|
||||||
|
|
||||||
|
def set_target(self, n):
|
||||||
if not isinstance(n, vector3d):
|
if not isinstance(n, vector3d):
|
||||||
for item in n:
|
for item in n:
|
||||||
self.set_target(item, value)
|
self.set_target(item)
|
||||||
else:
|
else:
|
||||||
self.add_map(n)
|
self.add_map(n)
|
||||||
self.map[n].target=value
|
self.map[n].target=True
|
||||||
|
self.map[n].blocked=False
|
||||||
self.target.add(n)
|
self.target.add(n)
|
||||||
|
|
||||||
def add_source(self, track_list, value=True):
|
def add_source(self, track_list):
|
||||||
debug.info(3, "Adding source list={0}".format(str(track_list)))
|
debug.info(3, "Adding source list={0}".format(str(track_list)))
|
||||||
for n in track_list:
|
for n in track_list:
|
||||||
debug.info(4, "Adding source ={0}".format(str(n)))
|
debug.info(4, "Adding source ={0}".format(str(n)))
|
||||||
self.set_source(n, value)
|
self.set_source(n)
|
||||||
self.set_blocked(n, False)
|
# self.set_blocked(n, False)
|
||||||
|
|
||||||
def add_target(self, track_list, value=True):
|
def add_target(self, track_list):
|
||||||
debug.info(3, "Adding target list={0}".format(str(track_list)))
|
debug.info(3, "Adding target list={0}".format(str(track_list)))
|
||||||
for n in track_list:
|
for n in track_list:
|
||||||
debug.info(4, "Adding target ={0}".format(str(n)))
|
debug.info(4, "Adding target ={0}".format(str(n)))
|
||||||
self.set_target(n, value)
|
self.set_target(n)
|
||||||
self.set_blocked(n, False)
|
# self.set_blocked(n, False)
|
||||||
|
|
||||||
def add_perimeter_target(self, side="all", value=True):
|
def add_perimeter_target(self, side="all"):
|
||||||
debug.info(3, "Adding perimeter target")
|
debug.info(3, "Adding perimeter target")
|
||||||
|
|
||||||
|
perimeter_list = []
|
||||||
# Add the left/right columns
|
# Add the left/right columns
|
||||||
if side=="all" or side=="left":
|
if side=="all" or side=="left":
|
||||||
x = self.ll.x
|
x = self.ll.x
|
||||||
for y in range(self.ll.y, self.ur.y, 1):
|
for y in range(self.ll.y, self.ur.y, 1):
|
||||||
n = vector3d(x, y, 0)
|
perimeter_list.append(vector3d(x, y, 0))
|
||||||
self.set_target(n, value)
|
perimeter_list.append(vector3d(x, y, 1))
|
||||||
self.set_blocked(n, False)
|
|
||||||
n = vector3d(x, y, 1)
|
|
||||||
self.set_target(n, value)
|
|
||||||
self.set_blocked(n, False)
|
|
||||||
|
|
||||||
if side=="all" or side=="right":
|
if side=="all" or side=="right":
|
||||||
x = self.ur.x
|
x = self.ur.x
|
||||||
for y in range(self.ll.y, self.ur.y, 1):
|
for y in range(self.ll.y, self.ur.y, 1):
|
||||||
n = vector3d(x, y, 0)
|
perimeter_list.append(vector3d(x, y, 0))
|
||||||
self.set_target(n, value)
|
perimeter_list.append(vector3d(x, y, 1))
|
||||||
self.set_blocked(n, False)
|
|
||||||
n = vector3d(x, y, 1)
|
|
||||||
self.set_target(n, value)
|
|
||||||
self.set_blocked(n, False)
|
|
||||||
|
|
||||||
if side=="all" or side=="bottom":
|
if side=="all" or side=="bottom":
|
||||||
y = self.ll.y
|
y = self.ll.y
|
||||||
for x in range(self.ll.x, self.ur.x, 1):
|
for x in range(self.ll.x, self.ur.x, 1):
|
||||||
n = vector3d(x, y, 0)
|
perimeter_list.append(vector3d(x, y, 0))
|
||||||
self.set_target(n, value)
|
perimeter_list.append(vector3d(x, y, 1))
|
||||||
self.set_blocked(n, False)
|
|
||||||
n = vector3d(x, y, 1)
|
|
||||||
self.set_target(n, value)
|
|
||||||
self.set_blocked(n, False)
|
|
||||||
|
|
||||||
if side=="all" or side=="top":
|
if side=="all" or side=="top":
|
||||||
y = self.ur.y
|
y = self.ur.y
|
||||||
for x in range(self.ll.x, self.ur.x, 1):
|
for x in range(self.ll.x, self.ur.x, 1):
|
||||||
n = vector3d(x, y, 0)
|
perimeter_list.append(vector3d(x, y, 0))
|
||||||
self.set_target(n, value)
|
perimeter_list.append(vector3d(x, y, 1))
|
||||||
self.set_blocked(n, False)
|
|
||||||
n = vector3d(x, y, 1)
|
self.set_target(perimeter_list)
|
||||||
self.set_target(n, value)
|
|
||||||
self.set_blocked(n, False)
|
|
||||||
|
|
||||||
def is_target(self, point):
|
def is_target(self, point):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ class grid_cell:
|
||||||
if self.min_cost > 0:
|
if self.min_cost > 0:
|
||||||
return self.min_cost
|
return self.min_cost
|
||||||
|
|
||||||
|
|
||||||
def get_type(self):
|
def get_type(self):
|
||||||
type_string = ""
|
type_string = ""
|
||||||
|
|
||||||
|
|
@ -50,7 +49,5 @@ class grid_cell:
|
||||||
if self.path:
|
if self.path:
|
||||||
type_string += "P"
|
type_string += "P"
|
||||||
|
|
||||||
if type_string != "":
|
return type_string
|
||||||
return type_string
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
import math
|
||||||
import gdsMill
|
import gdsMill
|
||||||
from tech import drc, GDS
|
from tech import drc, GDS
|
||||||
from tech import layer as techlayer
|
from tech import layer as techlayer
|
||||||
import math
|
|
||||||
import debug
|
import debug
|
||||||
from router_tech import router_tech
|
from router_tech import router_tech
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
|
|
@ -189,7 +190,6 @@ class router(router_tech):
|
||||||
# self.combine_adjacent_pins(pin)
|
# self.combine_adjacent_pins(pin)
|
||||||
# print_time("Combining adjacent pins",datetime.now(), start_time, 4)
|
# print_time("Combining adjacent pins",datetime.now(), start_time, 4)
|
||||||
|
|
||||||
|
|
||||||
# Separate any adjacent grids of differing net names
|
# Separate any adjacent grids of differing net names
|
||||||
# that overlap
|
# that overlap
|
||||||
# Must be done before enclosing pins
|
# Must be done before enclosing pins
|
||||||
|
|
@ -266,18 +266,10 @@ class router(router_tech):
|
||||||
This will try to separate all grid pins by the supplied
|
This will try to separate all grid pins by the supplied
|
||||||
number of separation tracks (default is to prevent adjacency).
|
number of separation tracks (default is to prevent adjacency).
|
||||||
"""
|
"""
|
||||||
# Commented out to debug with SCMOS
|
|
||||||
# if separation==0:
|
|
||||||
# return
|
|
||||||
|
|
||||||
pin_names = self.pin_groups.keys()
|
pin_names = self.pin_groups.keys()
|
||||||
for i, pin_name1 in enumerate(pin_names):
|
|
||||||
for j, pin_name2 in enumerate(pin_names):
|
for (pin_name1, pin_name2) in itertools.combinations(pin_names, 2):
|
||||||
if i == j:
|
self.separate_adjacent_pin(pin_name1, pin_name2, separation)
|
||||||
continue
|
|
||||||
if i > j:
|
|
||||||
return
|
|
||||||
self.separate_adjacent_pin(pin_name1, pin_name2, separation)
|
|
||||||
|
|
||||||
def separate_adjacent_pin(self, pin_name1, pin_name2, separation):
|
def separate_adjacent_pin(self, pin_name1, pin_name2, separation):
|
||||||
"""
|
"""
|
||||||
|
|
@ -290,6 +282,7 @@ class router(router_tech):
|
||||||
"Comparing {0} and {1} adjacency".format(pin_name1,
|
"Comparing {0} and {1} adjacency".format(pin_name1,
|
||||||
pin_name2))
|
pin_name2))
|
||||||
removed_grids = 0
|
removed_grids = 0
|
||||||
|
|
||||||
for index1, pg1 in enumerate(self.pin_groups[pin_name1]):
|
for index1, pg1 in enumerate(self.pin_groups[pin_name1]):
|
||||||
for index2, pg2 in enumerate(self.pin_groups[pin_name2]):
|
for index2, pg2 in enumerate(self.pin_groups[pin_name2]):
|
||||||
adj_grids = pg1.adjacent_grids(pg2, separation)
|
adj_grids = pg1.adjacent_grids(pg2, separation)
|
||||||
|
|
@ -362,7 +355,7 @@ class router(router_tech):
|
||||||
# Start fresh. Not the best for run-time, but simpler.
|
# Start fresh. Not the best for run-time, but simpler.
|
||||||
self.clear_blockages()
|
self.clear_blockages()
|
||||||
# This adds the initial blockges of the design
|
# This adds the initial blockges of the design
|
||||||
#print("BLOCKING:", self.blocked_grids)
|
# print("BLOCKING:", self.blocked_grids)
|
||||||
self.set_blockages(self.blocked_grids, True)
|
self.set_blockages(self.blocked_grids, True)
|
||||||
|
|
||||||
# Block all of the supply rails
|
# Block all of the supply rails
|
||||||
|
|
@ -389,8 +382,9 @@ class router(router_tech):
|
||||||
# Don't mark the other components as targets since we want to route
|
# Don't mark the other components as targets since we want to route
|
||||||
# directly to a rail, but unblock all the source components so we can
|
# directly to a rail, but unblock all the source components so we can
|
||||||
# route over them
|
# route over them
|
||||||
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
# 1/6/21: This would cause things that looked like loops in the supply tree router
|
||||||
self.set_blockages(blockage_grids, False)
|
# blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
||||||
|
# self.set_blockages(blockage_grids, False)
|
||||||
|
|
||||||
def convert_shape_to_units(self, shape):
|
def convert_shape_to_units(self, shape):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1039,18 +1033,18 @@ class router(router_tech):
|
||||||
(ll, ur) = self.convert_track_to_shape(coord)
|
(ll, ur) = self.convert_track_to_shape(coord)
|
||||||
self.cell.add_rect(layer="text",
|
self.cell.add_rect(layer="text",
|
||||||
offset=ll,
|
offset=ll,
|
||||||
width=ur[0]-ll[0],
|
width=ur[0] - ll[0],
|
||||||
height=ur[1]-ll[1])
|
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",
|
# self.cell.add_rect(layer="boundary",
|
||||||
offset=ll,
|
# offset=ll,
|
||||||
width=ur[0]-ll[0],
|
# width=ur[0] - ll[0],
|
||||||
height=ur[1]-ll[1])
|
# height=ur[1] - ll[1])
|
||||||
(ll, ur) = pin.rect
|
(ll, ur) = pin.rect
|
||||||
self.cell.add_rect(layer="text",
|
self.cell.add_rect(layer="text",
|
||||||
offset=ll,
|
offset=ll,
|
||||||
width=ur[0]-ll[0],
|
width=ur[0] - ll[0],
|
||||||
height=ur[1]-ll[1])
|
height=ur[1] - ll[1])
|
||||||
|
|
||||||
def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True):
|
def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1058,9 +1052,9 @@ class router(router_tech):
|
||||||
search information annotated on it.
|
search information annotated on it.
|
||||||
"""
|
"""
|
||||||
debug.info(0, "Writing annotated router gds file to {}".format(gds_name))
|
debug.info(0, "Writing annotated router gds file to {}".format(gds_name))
|
||||||
self.del_router_info()
|
|
||||||
self.add_router_info()
|
self.add_router_info()
|
||||||
self.cell.gds_write(gds_name)
|
self.cell.gds_write(gds_name)
|
||||||
|
self.del_router_info()
|
||||||
|
|
||||||
if stop_program:
|
if stop_program:
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -1071,17 +1065,17 @@ class router(router_tech):
|
||||||
Display grid information in the GDS file for a single grid cell.
|
Display grid information in the GDS file for a single grid cell.
|
||||||
"""
|
"""
|
||||||
shape = self.convert_track_to_shape(g)
|
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",
|
self.cell.add_rect(layer="text",
|
||||||
offset=shape[0],
|
offset=shape[0],
|
||||||
width=shape[1].x-shape[0].x,
|
width=shape[1].x - shape[0].x,
|
||||||
height=shape[1].y-shape[0].y)
|
height=shape[1].y - shape[0].y)
|
||||||
t = self.rg.map[g].get_type()
|
t = self.rg.map[g].get_type()
|
||||||
|
|
||||||
# midpoint offset
|
# 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)
|
(shape[1].y + shape[0].y) / 2)
|
||||||
if t != None:
|
if t:
|
||||||
if g[2] == 1:
|
if g[2] == 1:
|
||||||
# Upper layer is upper right label
|
# Upper layer is upper right label
|
||||||
type_off = off + partial_track
|
type_off = off + partial_track
|
||||||
|
|
@ -1107,16 +1101,15 @@ class router(router_tech):
|
||||||
|
|
||||||
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",
|
layer="text",
|
||||||
offset=shape[0],
|
offset=shape[0])
|
||||||
zoom=0.05)
|
|
||||||
|
|
||||||
def del_router_info(self):
|
def del_router_info(self):
|
||||||
"""
|
"""
|
||||||
Erase all of the comments on the current level.
|
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"]
|
lpp = techlayer["text"]
|
||||||
self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num]
|
self.cell.objs = [x for x in self.cell.objs if x.lpp != lpp]
|
||||||
|
|
||||||
def add_router_info(self):
|
def add_router_info(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1132,7 +1125,6 @@ class router(router_tech):
|
||||||
show_all_grids = True
|
show_all_grids = True
|
||||||
|
|
||||||
if show_all_grids:
|
if show_all_grids:
|
||||||
# self.rg.add_all_grids()
|
|
||||||
for g in self.rg.map:
|
for g in self.rg.map:
|
||||||
self.annotate_grid(g)
|
self.annotate_grid(g)
|
||||||
|
|
||||||
|
|
@ -1143,8 +1135,8 @@ class router(router_tech):
|
||||||
(ll, ur) = blockage.inflate()
|
(ll, ur) = blockage.inflate()
|
||||||
self.cell.add_rect(layer="text",
|
self.cell.add_rect(layer="text",
|
||||||
offset=ll,
|
offset=ll,
|
||||||
width=ur.x-ll.x,
|
width=ur.x - ll.x,
|
||||||
height=ur.y-ll.y)
|
height=ur.y - ll.y)
|
||||||
if show_blockage_grids:
|
if show_blockage_grids:
|
||||||
self.set_blockages(self.blocked_grids, True)
|
self.set_blockages(self.blocked_grids, True)
|
||||||
for g in self.rg.map:
|
for g in self.rg.map:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import debug
|
||||||
from globals import print_time
|
from globals import print_time
|
||||||
from router import router
|
from router import router
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from supply_grid import supply_grid
|
from signal_grid import signal_grid
|
||||||
|
|
||||||
|
|
||||||
class signal_escape_router(router):
|
class signal_escape_router(router):
|
||||||
|
|
@ -30,31 +30,38 @@ class signal_escape_router(router):
|
||||||
"""
|
"""
|
||||||
size = self.ur - self.ll
|
size = self.ur - self.ll
|
||||||
debug.info(1,"Size: {0} x {1}".format(size.x, size.y))
|
debug.info(1,"Size: {0} x {1}".format(size.x, size.y))
|
||||||
self.rg = supply_grid(self.ll, self.ur, self.track_width)
|
self.rg = signal_grid(self.ll, self.ur, self.track_width)
|
||||||
|
|
||||||
def escape_route(self, pin_list):
|
def perimeter_dist(self, pin_name):
|
||||||
|
"""
|
||||||
|
Return the shortest Manhattan distance to the bounding box perimeter.
|
||||||
|
"""
|
||||||
|
loc = self.cell.get_pin(pin_name).center()
|
||||||
|
x_dist = min(loc.x - self.ll.x, self.ur.x - loc.x)
|
||||||
|
y_dist = min(loc.y - self.ll.y, self.ur.y - loc.y)
|
||||||
|
|
||||||
|
return min(x_dist, y_dist)
|
||||||
|
|
||||||
|
def escape_route(self, pin_names):
|
||||||
"""
|
"""
|
||||||
Takes a list of tuples (name, side) and routes them. After routing,
|
Takes a list of tuples (name, side) and routes them. After routing,
|
||||||
it removes the old pin and places a new one on the perimeter.
|
it removes the old pin and places a new one on the perimeter.
|
||||||
"""
|
"""
|
||||||
pin_names = [x[0] for x in pin_list]
|
self.create_routing_grid()
|
||||||
|
|
||||||
# Clear the pins if we have previously routed
|
|
||||||
if (hasattr(self,'rg')):
|
|
||||||
self.clear_pins()
|
|
||||||
else:
|
|
||||||
self.create_routing_grid()
|
|
||||||
|
|
||||||
# Get the pin shapes
|
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
self.find_pins_and_blockages(pin_names)
|
self.find_pins_and_blockages(pin_names)
|
||||||
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
||||||
|
|
||||||
|
# Order the routes by closest to the perimeter first
|
||||||
|
# This prevents some pins near the perimeter from being blocked by other pins
|
||||||
|
ordered_pin_names = sorted(pin_names, key=lambda x: self.perimeter_dist(x))
|
||||||
|
|
||||||
# Route the supply pins to the supply rails
|
# Route the supply pins to the supply rails
|
||||||
# Route vdd first since we want it to be shorter
|
# Route vdd first since we want it to be shorter
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
for pin_name, side in pin_list:
|
for pin_name in ordered_pin_names:
|
||||||
self.route_signal(pin_name, side)
|
self.route_signal(pin_name)
|
||||||
|
|
||||||
print_time("Maze routing pins",datetime.now(), start_time, 3)
|
print_time("Maze routing pins",datetime.now(), start_time, 3)
|
||||||
|
|
||||||
|
|
@ -62,10 +69,10 @@ class signal_escape_router(router):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def route_signal(self, pin_name, side):
|
def route_signal(self, pin_name, side="all"):
|
||||||
|
|
||||||
for detour_scale in [5 * pow(2, x) for x in range(5)]:
|
for detour_scale in [5 * pow(2, x) for x in range(5)]:
|
||||||
debug.info(1, "Exit routing {0} with scale {1}".format(pin_name, detour_scale))
|
debug.info(1, "Escape routing {0} with scale {1}".format(pin_name, detour_scale))
|
||||||
|
|
||||||
# Clear everything in the routing grid.
|
# Clear everything in the routing grid.
|
||||||
self.rg.reinit()
|
self.rg.reinit()
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,6 @@ class signal_grid(grid):
|
||||||
""" Create a routing map of width x height cells and 2 in the z-axis. """
|
""" Create a routing map of width x height cells and 2 in the z-axis. """
|
||||||
grid.__init__(self, ll, ur, track_factor)
|
grid.__init__(self, ll, ur, track_factor)
|
||||||
|
|
||||||
# priority queue for the maze routing
|
|
||||||
self.q = []
|
|
||||||
|
|
||||||
def reinit(self):
|
def reinit(self):
|
||||||
""" Reinitialize everything for a new route. """
|
""" Reinitialize everything for a new route. """
|
||||||
|
|
||||||
|
|
@ -33,14 +30,8 @@ class signal_grid(grid):
|
||||||
for p in self.map.values():
|
for p in self.map.values():
|
||||||
p.reset()
|
p.reset()
|
||||||
|
|
||||||
# clear source and target pins
|
self.clear_source()
|
||||||
self.source = set()
|
self.clear_target()
|
||||||
self.target = set()
|
|
||||||
|
|
||||||
# Clear the queue
|
|
||||||
while len(self.q) > 0:
|
|
||||||
heappop(self.q)
|
|
||||||
self.counter = 0
|
|
||||||
|
|
||||||
def init_queue(self):
|
def init_queue(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -51,12 +42,13 @@ class signal_grid(grid):
|
||||||
"""
|
"""
|
||||||
# Counter is used to not require data comparison in Python 3.x
|
# Counter is used to not require data comparison in Python 3.x
|
||||||
# Items will be returned in order they are added during cost ties
|
# Items will be returned in order they are added during cost ties
|
||||||
|
self.q = []
|
||||||
self.counter = 0
|
self.counter = 0
|
||||||
for s in self.source:
|
for s in self.source:
|
||||||
cost = self.cost_to_target(s)
|
cost = self.cost_to_target(s)
|
||||||
debug.info(3, "Init: cost=" + str(cost) + " " + str([s]))
|
debug.info(3, "Init: cost=" + str(cost) + " " + str([s]))
|
||||||
heappush(self.q, (cost, self.counter, grid_path([vector3d(s)])))
|
heappush(self.q, (cost, self.counter, grid_path([vector3d(s)])))
|
||||||
self.counter+=1
|
self.counter += 1
|
||||||
|
|
||||||
def route(self, detour_scale):
|
def route(self, detour_scale):
|
||||||
"""
|
"""
|
||||||
|
|
@ -72,11 +64,7 @@ class signal_grid(grid):
|
||||||
# Check if something in the queue is already a source and a target!
|
# Check if something in the queue is already a source and a target!
|
||||||
for s in self.source:
|
for s in self.source:
|
||||||
if self.is_target(s):
|
if self.is_target(s):
|
||||||
return((grid_path([vector3d(s)]),0))
|
return((grid_path([vector3d(s)]), 0))
|
||||||
|
|
||||||
# Make sure the queue is empty if we run another route
|
|
||||||
while len(self.q)>0:
|
|
||||||
heappop(self.q)
|
|
||||||
|
|
||||||
# Put the source items into the queue
|
# Put the source items into the queue
|
||||||
self.init_queue()
|
self.init_queue()
|
||||||
|
|
|
||||||
|
|
@ -144,15 +144,13 @@ class supply_tree_router(router):
|
||||||
|
|
||||||
# Marks all pin components except index as target
|
# Marks all pin components except index as target
|
||||||
self.add_pin_component_target(pin_name, dest_idx)
|
self.add_pin_component_target(pin_name, dest_idx)
|
||||||
|
|
||||||
# Actually run the A* router
|
# Actually run the A* router
|
||||||
if self.run_router(detour_scale=detour_scale):
|
if self.run_router(detour_scale=detour_scale):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.write_debug_gds("debug_route.gds", True)
|
self.write_debug_gds("debug_route.gds", True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_io_pin(self, instance, pin_name, new_name=""):
|
def add_io_pin(self, instance, pin_name, new_name=""):
|
||||||
"""
|
"""
|
||||||
Add a signle input or output pin up to metal 3.
|
Add a signle input or output pin up to metal 3.
|
||||||
|
|
|
||||||
|
|
@ -254,43 +254,37 @@ class sram_1bank(sram_base):
|
||||||
# List of pin to new pin name
|
# List of pin to new pin name
|
||||||
pins_to_route = []
|
pins_to_route = []
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
# Depending on the port, use the bottom/top or left/right sides
|
|
||||||
# Port 0 is left/bottom
|
|
||||||
# Port 1 is right/top
|
|
||||||
bottom_or_top = "bottom" if port==0 else "top"
|
|
||||||
left_or_right = "left" if port==0 else "right"
|
|
||||||
|
|
||||||
# Connect the control pins as inputs
|
# Connect the control pins as inputs
|
||||||
for signal in self.control_logic_inputs[port]:
|
for signal in self.control_logic_inputs[port]:
|
||||||
if signal.startswith("rbl"):
|
if signal.startswith("rbl"):
|
||||||
continue
|
continue
|
||||||
if signal=="clk":
|
if signal=="clk":
|
||||||
pins_to_route.append(("{0}{1}".format(signal, port), bottom_or_top))
|
pins_to_route.append("{0}{1}".format(signal, port))
|
||||||
else:
|
else:
|
||||||
pins_to_route.append(("{0}{1}".format(signal, port), left_or_right))
|
pins_to_route.append("{0}{1}".format(signal, port))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
pins_to_route.append(("din{0}[{1}]".format(port, bit), bottom_or_top))
|
pins_to_route.append("din{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
if port in self.readwrite_ports or port in self.read_ports:
|
if port in self.readwrite_ports or port in self.read_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
pins_to_route.append(("dout{0}[{1}]".format(port, bit), bottom_or_top))
|
pins_to_route.append("dout{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
for bit in range(self.col_addr_size):
|
for bit in range(self.col_addr_size):
|
||||||
pins_to_route.append(("addr{0}[{1}]".format(port, bit), bottom_or_top))
|
pins_to_route.append("addr{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
for bit in range(self.row_addr_size):
|
for bit in range(self.row_addr_size):
|
||||||
pins_to_route.append(("addr{0}[{1}]".format(port, bit + self.col_addr_size), left_or_right))
|
pins_to_route.append("addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
for bit in range(self.num_wmasks):
|
for bit in range(self.num_wmasks):
|
||||||
pins_to_route.append(("wmask{0}[{1}]".format(port, bit), bottom_or_top))
|
pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
for bit in range(self.num_spare_cols):
|
for bit in range(self.num_spare_cols):
|
||||||
pins_to_route.append(("spare_wen{0}[{1}]".format(port, bit), bottom_or_top))
|
pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
rtr=router(self.m3_stack, self)
|
rtr=router(self.m3_stack, self)
|
||||||
rtr.escape_route(pins_to_route)
|
rtr.escape_route(pins_to_route)
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,12 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
|
||||||
f.write("drc off\n")
|
f.write("drc off\n")
|
||||||
f.write("gds polygon subcell true\n")
|
f.write("gds polygon subcell true\n")
|
||||||
f.write("gds warning default\n")
|
f.write("gds warning default\n")
|
||||||
f.write("gds flatten true\n")
|
# These two options are temporarily disabled until Tim fixes a bug in magic related
|
||||||
f.write("gds readonly true\n")
|
# to flattening channel routes and vias (hierarchy with no devices in it). Otherwise,
|
||||||
|
# they appear to be disconnected.
|
||||||
|
f.write("#gds flatten true\n")
|
||||||
f.write("#gds ordering true\n")
|
f.write("#gds ordering true\n")
|
||||||
|
f.write("gds readonly true\n")
|
||||||
f.write("gds read {}\n".format(gds_name))
|
f.write("gds read {}\n".format(gds_name))
|
||||||
f.write('puts "Finished reading gds {}"\n'.format(gds_name))
|
f.write('puts "Finished reading gds {}"\n'.format(gds_name))
|
||||||
f.write("load {}\n".format(cell_name))
|
f.write("load {}\n".format(cell_name))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue