mirror of https://github.com/VLSIDA/OpenRAM.git
Cleanup of router.
Made offsets in geometry snap to grid. Changed gds_write to use list for visited flag. Rewrite self.gds each call in case of any changes.
This commit is contained in:
parent
7432192e5e
commit
985d04d4b5
|
|
@ -53,3 +53,14 @@ class design(hierarchy_design):
|
|||
for inst in self.insts:
|
||||
total_module_power += inst.mod.analytical_power(proc, vdd, temp, load)
|
||||
return total_module_power
|
||||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
pins = ",".join(self.pins)
|
||||
insts = [" {}".format(x) for x in self.insts]
|
||||
objs = [" {}".format(x) for x in self.objs]
|
||||
s = "********** design {0} **********\n".format(self.name)
|
||||
s += "\n pins ({0})={1}\n".format(len(self.pins), pins)
|
||||
s += "\n objs ({0})=\n{1}".format(len(self.objs), "\n".join(objs))
|
||||
s += "\n insts ({0})=\n{1}\n".format(len(self.insts), "\n".join(insts))
|
||||
return s
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from vector import vector
|
|||
import tech
|
||||
import math
|
||||
from globals import OPTS
|
||||
from utils import round_to_grid
|
||||
|
||||
class geometry:
|
||||
"""
|
||||
|
|
@ -46,8 +47,8 @@ class geometry:
|
|||
def normalize(self):
|
||||
""" Re-find the LL and UR points after a transform """
|
||||
(first,second)=self.boundary
|
||||
ll = vector(min(first[0],second[0]),min(first[1],second[1]))
|
||||
ur = vector(max(first[0],second[0]),max(first[1],second[1]))
|
||||
ll = vector(min(first[0],second[0]),min(first[1],second[1])).snap_to_grid()
|
||||
ur = vector(max(first[0],second[0]),max(first[1],second[1])).snap_to_grid()
|
||||
self.boundary=[ll,ur]
|
||||
|
||||
def update_boundary(self):
|
||||
|
|
@ -142,8 +143,8 @@ class instance(geometry):
|
|||
self.rotate = rotate
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.mirror = mirror
|
||||
self.width = mod.width
|
||||
self.height = mod.height
|
||||
self.width = round_to_grid(mod.width)
|
||||
self.height = round_to_grid(mod.height)
|
||||
self.compute_boundary(offset,mirror,rotate)
|
||||
|
||||
debug.info(4, "creating instance: " + self.name)
|
||||
|
|
@ -191,15 +192,15 @@ class instance(geometry):
|
|||
self.mod.gds_write_file(self.gds)
|
||||
# now write an instance of my module/structure
|
||||
new_layout.addInstance(self.gds,
|
||||
offsetInMicrons=self.offset,
|
||||
mirror=self.mirror,
|
||||
rotate=self.rotate)
|
||||
|
||||
offsetInMicrons=self.offset,
|
||||
mirror=self.mirror,
|
||||
rotate=self.rotate)
|
||||
|
||||
def place(self, offset, mirror="R0", rotate=0):
|
||||
""" This updates the placement of an instance. """
|
||||
debug.info(3, "placing instance {}".format(self.name))
|
||||
# Update the placement of an already added instance
|
||||
self.offset = vector(offset)
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.mirror = mirror
|
||||
self.rotate = rotate
|
||||
self.update_boundary()
|
||||
|
|
@ -238,7 +239,7 @@ class instance(geometry):
|
|||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
return "inst: " + self.name + " mod=" + self.mod.name
|
||||
return "( inst: " + self.name + " @" + str(self.offset) + " mod=" + self.mod.name + " " + self.mirror + " R=" + str(self.rotate) + ")"
|
||||
|
||||
def __repr__(self):
|
||||
""" override print function output """
|
||||
|
|
@ -260,13 +261,13 @@ class path(geometry):
|
|||
# supported right now. It might not work in gdsMill.
|
||||
assert(0)
|
||||
|
||||
def gds_write_file(self, newLayout):
|
||||
def gds_write_file(self, new_layout):
|
||||
"""Writes the path to GDS"""
|
||||
debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates)
|
||||
newLayout.addPath(layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
coordinates=self.coordinates,
|
||||
width=self.path_width)
|
||||
new_layout.addPath(layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
coordinates=self.coordinates,
|
||||
width=self.path_width)
|
||||
|
||||
def get_blockages(self, layer):
|
||||
""" Fail since we don't support paths yet. """
|
||||
|
|
@ -301,15 +302,15 @@ class label(geometry):
|
|||
|
||||
debug.info(4,"creating label " + self.text + " " + str(self.layerNumber) + " " + str(self.offset))
|
||||
|
||||
def gds_write_file(self, newLayout):
|
||||
def gds_write_file(self, new_layout):
|
||||
"""Writes the text label to GDS"""
|
||||
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
||||
newLayout.addText(text=self.text,
|
||||
layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
offsetInMicrons=self.offset,
|
||||
magnification=self.zoom,
|
||||
rotate=None)
|
||||
new_layout.addText(text=self.text,
|
||||
layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
offsetInMicrons=self.offset,
|
||||
magnification=self.zoom,
|
||||
rotate=None)
|
||||
|
||||
def get_blockages(self, layer):
|
||||
""" Returns an empty list since text cannot be blockages. """
|
||||
|
|
@ -321,7 +322,7 @@ class label(geometry):
|
|||
|
||||
def __repr__(self):
|
||||
""" override print function output """
|
||||
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + self.layerNumber + " )"
|
||||
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " )"
|
||||
|
||||
class rectangle(geometry):
|
||||
"""Represents a rectangular shape"""
|
||||
|
|
@ -333,8 +334,8 @@ class rectangle(geometry):
|
|||
self.layerNumber = layerNumber
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.size = vector(width, height).snap_to_grid()
|
||||
self.width = self.size.x
|
||||
self.height = self.size.y
|
||||
self.width = round_to_grid(self.size.x)
|
||||
self.height = round_to_grid(self.size.y)
|
||||
self.compute_boundary(offset,"",0)
|
||||
|
||||
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
|
||||
|
|
@ -348,16 +349,16 @@ class rectangle(geometry):
|
|||
else:
|
||||
return []
|
||||
|
||||
def gds_write_file(self, newLayout):
|
||||
def gds_write_file(self, new_layout):
|
||||
"""Writes the rectangular shape to GDS"""
|
||||
debug.info(4, "writing rectangle (" + str(self.layerNumber) + "):"
|
||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||
newLayout.addBox(layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
offsetInMicrons=self.offset,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
center=False)
|
||||
new_layout.addBox(layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
offsetInMicrons=self.offset,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
center=False)
|
||||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class layout(lef.lef):
|
|||
self.insts = [] # Holds module/cell layout instances
|
||||
self.objs = [] # Holds all other objects (labels, geometries, etc)
|
||||
self.pin_map = {} # Holds name->pin_layout map for all pins
|
||||
self.visited = False # Flag for traversing the hierarchy
|
||||
self.visited = [] # List of modules we have already visited
|
||||
self.is_library_cell = False # Flag for library cells
|
||||
self.gds_read()
|
||||
|
||||
|
|
@ -432,59 +432,66 @@ class layout(lef.lef):
|
|||
|
||||
# open the gds file if it exists or else create a blank layout
|
||||
if os.path.isfile(self.gds_file):
|
||||
debug.info(3, "opening %s" % self.gds_file)
|
||||
debug.info(3, "opening {}".format(self.gds_file))
|
||||
self.is_library_cell=True
|
||||
self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||
reader = gdsMill.Gds2reader(self.gds)
|
||||
reader.loadFromFile(self.gds_file)
|
||||
else:
|
||||
debug.info(4, "creating structure %s" % self.name)
|
||||
debug.info(3, "Creating layout structure {}".format(self.name))
|
||||
self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"])
|
||||
|
||||
def print_gds(self, gds_file=None):
|
||||
"""Print the gds file (not the vlsi class) to the terminal """
|
||||
if gds_file == None:
|
||||
gds_file = self.gds_file
|
||||
debug.info(4, "Printing %s" % gds_file)
|
||||
debug.info(4, "Printing {}".format(gds_file))
|
||||
arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||
reader = gdsMill.Gds2reader(arrayCellLayout, debugToTerminal=1)
|
||||
reader.loadFromFile(gds_file)
|
||||
|
||||
def clear_visited(self):
|
||||
""" Recursively clear the visited flag """
|
||||
if not self.visited:
|
||||
for i in self.insts:
|
||||
i.mod.clear_visited()
|
||||
self.visited = False
|
||||
self.visited = []
|
||||
|
||||
def gds_write_file(self, newLayout):
|
||||
def gds_write_file(self, gds_layout):
|
||||
"""Recursive GDS write function"""
|
||||
# Visited means that we already prepared self.gds for this subtree
|
||||
if self.visited:
|
||||
if self.name in self.visited:
|
||||
return
|
||||
for i in self.insts:
|
||||
i.gds_write_file(newLayout)
|
||||
i.gds_write_file(gds_layout)
|
||||
for i in self.objs:
|
||||
i.gds_write_file(newLayout)
|
||||
i.gds_write_file(gds_layout)
|
||||
for pin_name in self.pin_map.keys():
|
||||
for pin in self.pin_map[pin_name]:
|
||||
pin.gds_write_file(newLayout)
|
||||
self.visited = True
|
||||
pin.gds_write_file(gds_layout)
|
||||
self.visited.append(self.name)
|
||||
|
||||
def gds_write(self, gds_name):
|
||||
"""Write the entire gds of the object to the file."""
|
||||
debug.info(3, "Writing to {0}".format(gds_name))
|
||||
debug.info(3, "Writing to {}".format(gds_name))
|
||||
|
||||
# If we already wrote a GDS, we need to reset and traverse it again in
|
||||
# case we made changes.
|
||||
if not self.is_library_cell and self.visited:
|
||||
debug.info(3, "Creating layout structure {}".format(self.name))
|
||||
self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"])
|
||||
|
||||
writer = gdsMill.Gds2writer(self.gds)
|
||||
# MRG: 3/2/18 We don't want to clear the visited flag since
|
||||
# this would result in duplicates of all instances being placed in self.gds
|
||||
# which may have been previously processed!
|
||||
#self.clear_visited()
|
||||
# MRG: 10/4/18 We need to clear if we make changes and write a second GDS!
|
||||
self.clear_visited()
|
||||
|
||||
# recursively create all the remaining objects
|
||||
self.gds_write_file(self.gds)
|
||||
|
||||
# populates the xyTree data structure for gds
|
||||
# self.gds.prepareForWrite()
|
||||
writer.writeToFile(gds_name)
|
||||
debug.info(3, "Done writing to {}".format(gds_name))
|
||||
|
||||
def get_boundary(self):
|
||||
""" Return the lower-left and upper-right coordinates of boundary """
|
||||
|
|
@ -1008,7 +1015,7 @@ class layout(lef.lef):
|
|||
def pdf_write(self, pdf_name):
|
||||
# NOTE: Currently does not work (Needs further research)
|
||||
#self.pdf_name = self.name + ".pdf"
|
||||
debug.info(0, "Writing to %s" % pdf_name)
|
||||
debug.info(0, "Writing to {}".format(pdf_name))
|
||||
pdf = gdsMill.pdfLayout(self.gds)
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ class options(optparse.Values):
|
|||
# This is the name of the technology.
|
||||
tech_name = ""
|
||||
# This is the temp directory where all intermediate results are stored.
|
||||
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||
#openram_temp = "{0}/openram_temp/".format(os.getenv("HOME"))
|
||||
#openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||
openram_temp = "{0}/openram_temp/".format(os.getenv("HOME"))
|
||||
# This is the verbosity level to control debug information. 0 is none, 1
|
||||
# is minimal, etc.
|
||||
debug_level = 0
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ class grid:
|
|||
self.map[n].path=value
|
||||
|
||||
def clear_blockages(self):
|
||||
debug.info(2,"Clearing all blockages")
|
||||
self.set_blocked(set(self.map.keys()),False)
|
||||
|
||||
def set_source(self,n,value=True):
|
||||
|
|
|
|||
|
|
@ -17,26 +17,28 @@ class router:
|
|||
It populates blockages on a grid class.
|
||||
"""
|
||||
|
||||
def __init__(self, gds_name=None, module=None):
|
||||
"""Use the gds file or the cell for the blockages with the top module topName and
|
||||
layers for the layers to route on
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
"""
|
||||
self.gds_name = gds_name
|
||||
self.module = module
|
||||
debug.check(not (gds_name and module), "Specify only a GDS file or module")
|
||||
This will instantiate a copy of the gds file or the module at (0,0) and
|
||||
route on top of this. The blockages from the gds/module will be considered.
|
||||
"""
|
||||
self.cell = design
|
||||
|
||||
# If we specified a module instead, write it out to read the gds
|
||||
# If didn't specify a gds blockage file, write it out to read the gds
|
||||
# This isn't efficient, but easy for now
|
||||
if module:
|
||||
gds_name = OPTS.openram_temp+"temp.gds"
|
||||
module.gds_write(gds_name)
|
||||
if not gds_filename:
|
||||
gds_filename = OPTS.openram_temp+"temp.gds"
|
||||
self.cell.gds_write(gds_filename)
|
||||
|
||||
# Load the gds file and read in all the shapes
|
||||
self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
|
||||
self.reader = gdsMill.Gds2reader(self.layout)
|
||||
self.reader.loadFromFile(gds_name)
|
||||
self.reader.loadFromFile(gds_filename)
|
||||
self.top_name = self.layout.rootStructureName
|
||||
|
||||
# Set up layers and track sizes
|
||||
self.set_layers(layers)
|
||||
|
||||
### The pin data structures
|
||||
# A map of pin names to pin structures
|
||||
self.pins = {}
|
||||
|
|
@ -157,6 +159,7 @@ class router:
|
|||
self.pins[pin_name] = pin_set
|
||||
self.all_pins.update(pin_set)
|
||||
|
||||
|
||||
def find_pins(self,pin_name):
|
||||
"""
|
||||
Finds the pin shapes and converts to tracks.
|
||||
|
|
@ -189,7 +192,53 @@ class router:
|
|||
# # self.rg.reinit()
|
||||
|
||||
|
||||
|
||||
def find_pins_and_blockages(self, pin_list):
|
||||
"""
|
||||
Find the pins and blockages in the design
|
||||
"""
|
||||
# This finds the pin shapes and sorts them into "groups" that are connected
|
||||
for pin in pin_list:
|
||||
self.find_pins(pin)
|
||||
|
||||
# This will get all shapes as blockages and convert to grid units
|
||||
# This ignores shapes that were pins
|
||||
self.find_blockages()
|
||||
|
||||
# This will convert the pins to grid units
|
||||
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
|
||||
for pin in pin_list:
|
||||
self.convert_pins(pin)
|
||||
|
||||
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
|
||||
self.enclose_pins()
|
||||
|
||||
def prepare_blockages(self):
|
||||
"""
|
||||
Reset and add all of the blockages in the design.
|
||||
Names is a list of pins to add as a blockage.
|
||||
"""
|
||||
debug.info(1,"Preparing blockages.")
|
||||
|
||||
# Start fresh. Not the best for run-time, but simpler.
|
||||
self.clear_blockages()
|
||||
# This adds the initial blockges of the design
|
||||
#print("BLOCKING:",self.blocked_grids)
|
||||
self.set_blockages(self.blocked_grids,True)
|
||||
|
||||
# Block all of the supply rails (some will be unblocked if they're a target)
|
||||
self.set_supply_rail_blocked(True)
|
||||
|
||||
# Block all of the pin components (some will be unblocked if they're a source/target)
|
||||
for name in self.pin_components.keys():
|
||||
self.set_blockages(self.pin_components[name],True)
|
||||
|
||||
# Block all of the pin component partial blockages
|
||||
for name in self.pin_component_blockages.keys():
|
||||
self.set_blockages(self.pin_component_blockages[name],True)
|
||||
|
||||
# These are the paths that have already been routed.
|
||||
self.set_path_blockages()
|
||||
|
||||
def translate_coordinates(self, coord, mirr, angle, xyShift):
|
||||
"""
|
||||
Calculate coordinates after flip, rotate, and shift
|
||||
|
|
@ -251,6 +300,7 @@ class router:
|
|||
"""
|
||||
Clear all blockages on the grid.
|
||||
"""
|
||||
debug.info(2,"Clearing all blockages")
|
||||
self.rg.clear_blockages()
|
||||
|
||||
def set_blockages(self, blockages, value=True):
|
||||
|
|
@ -776,6 +826,7 @@ class router:
|
|||
# FIXME: This could be optimized, but we just do a simple greedy biggest shape
|
||||
# for now.
|
||||
for pin_name in self.pin_components.keys():
|
||||
print("Enclosing {}".format(pin_name))
|
||||
for pin_set,partial_set in zip(self.pin_components[pin_name],self.pin_component_blockages[pin_name]):
|
||||
total_pin_grids = pin_set | partial_set
|
||||
while self.enclose_pin_grids(total_pin_grids):
|
||||
|
|
@ -834,6 +885,7 @@ class router:
|
|||
"""
|
||||
Add the supply rails of given name as a routing target.
|
||||
"""
|
||||
debug.info(2,"Add supply rail target {}".format(pin_name))
|
||||
for rail in self.supply_rails:
|
||||
if rail.name != pin_name:
|
||||
continue
|
||||
|
|
@ -847,6 +899,7 @@ class router:
|
|||
"""
|
||||
Add the supply rails of given name as a routing target.
|
||||
"""
|
||||
debug.info(2,"Blocking supply rail")
|
||||
for rail in self.supply_rails:
|
||||
for wave_index in range(len(rail)):
|
||||
pin_in_tracks = rail[wave_index]
|
||||
|
|
@ -857,6 +910,7 @@ class router:
|
|||
"""
|
||||
Block all of the pin components.
|
||||
"""
|
||||
debug.info(2,"Setting blockages {0} {1}".format(pin_name,value))
|
||||
for component in self.pin_components[pin_name]:
|
||||
self.set_blockages(component, value)
|
||||
|
||||
|
|
@ -892,15 +946,16 @@ class router:
|
|||
"""
|
||||
path=self.prepare_path(path)
|
||||
|
||||
# convert the path back to absolute units from tracks
|
||||
# This assumes 1-track wide again
|
||||
abs_path = [self.convert_point_to_units(x[0]) for x in path]
|
||||
debug.info(1,str(abs_path))
|
||||
|
||||
debug.info(1,"Adding route: {}".format(str(path)))
|
||||
# If it is only a square, add an enclosure to the track
|
||||
if len(path)==1:
|
||||
self.add_single_enclosure(abs_path[0])
|
||||
print("Single {}".format(str(path[0][0])))
|
||||
self.add_single_enclosure(path[0][0])
|
||||
else:
|
||||
print("Route")
|
||||
# convert the path back to absolute units from tracks
|
||||
# This assumes 1-track wide again
|
||||
abs_path = [self.convert_point_to_units(x[0]) for x in path]
|
||||
# Otherwise, add the route which includes enclosures
|
||||
self.cell.add_route(layers=self.layers,
|
||||
coordinates=abs_path,
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ class signal_router(router):
|
|||
route on a given layer. This is limited to two layer routes.
|
||||
"""
|
||||
|
||||
def __init__(self, gds_name=None, module=None):
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
"""
|
||||
Use the gds file for the blockages with the top module topName and
|
||||
layers for the layers to route on
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
"""
|
||||
router.__init__(self, gds_name, module)
|
||||
router.__init__(self, layers, design, gds_filename)
|
||||
|
||||
|
||||
def create_routing_grid(self):
|
||||
|
|
@ -36,14 +36,13 @@ class signal_router(router):
|
|||
self.rg = signal_grid.signal_grid(self.ll, self.ur, self.track_width)
|
||||
|
||||
|
||||
def route(self, cell, layers, src, dest, detour_scale=5):
|
||||
def route(self, src, dest, detour_scale=5):
|
||||
"""
|
||||
Route a single source-destination net and return
|
||||
the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route.
|
||||
This is used to speed up the routing when there is not much detouring needed.
|
||||
"""
|
||||
debug.info(1,"Running signal router from {0} to {1}...".format(src,dest))
|
||||
self.cell = cell
|
||||
|
||||
self.pins[src] = []
|
||||
self.pins[dest] = []
|
||||
|
|
@ -52,38 +51,29 @@ class signal_router(router):
|
|||
if (hasattr(self,'rg')):
|
||||
self.clear_pins()
|
||||
else:
|
||||
# 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()
|
||||
|
||||
# Now add the blockages (all shapes except the pins)
|
||||
self.find_pins(src)
|
||||
self.find_pins(dest)
|
||||
# Get the pin shapes
|
||||
self.find_pins_and_blockages([src, dest])
|
||||
|
||||
# This will get all shapes as blockages
|
||||
self.find_blockages()
|
||||
|
||||
# Now add the blockages
|
||||
self.set_blockages(self.blocked_grids,True)
|
||||
#self.set_blockages(self.pin_partials[src],True)
|
||||
#self.set_blockages(self.pin_partials[dest],True)
|
||||
|
||||
# Add blockages from previous paths
|
||||
self.set_path_blockages()
|
||||
|
||||
|
||||
# Block everything
|
||||
self.prepare_blockages()
|
||||
# Clear the pins we are routing
|
||||
self.set_blockages(self.pin_components[src],False)
|
||||
self.set_blockages(self.pin_components[dest],False)
|
||||
|
||||
# Now add the src/tgt if they are not blocked by other shapes
|
||||
self.add_source(src)
|
||||
self.add_target(dest)
|
||||
|
||||
if not self.run_router(detour_scale):
|
||||
if not self.run_router(detour_scale=detour_scale):
|
||||
self.write_debug_gds(stop_program=False)
|
||||
return False
|
||||
|
||||
self.write_debug_gds()
|
||||
|
||||
self.write_debug_gds(stop_program=False)
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ class supply_router(router):
|
|||
routes a grid to connect the supply on the two layers.
|
||||
"""
|
||||
|
||||
def __init__(self, gds_name=None, module=None):
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
"""
|
||||
Use the gds file for the blockages with the top module topName and
|
||||
layers for the layers to route on
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
"""
|
||||
router.__init__(self, gds_name, module)
|
||||
|
||||
router.__init__(self, layers, design, gds_filename)
|
||||
|
||||
# Power rail width in grid units.
|
||||
self.rail_track_width = 2
|
||||
|
||||
|
|
@ -38,12 +38,11 @@ class supply_router(router):
|
|||
import supply_grid
|
||||
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width)
|
||||
|
||||
def route(self, cell, layers, vdd_name="vdd", gnd_name="gnd"):
|
||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||
"""
|
||||
Add power supply rails and connect all pins to these rails.
|
||||
"""
|
||||
debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
||||
self.cell = cell
|
||||
self.vdd_name = vdd_name
|
||||
self.gnd_name = gnd_name
|
||||
|
||||
|
|
@ -51,15 +50,13 @@ class supply_router(router):
|
|||
if (hasattr(self,'rg')):
|
||||
self.clear_pins()
|
||||
else:
|
||||
# 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()
|
||||
|
||||
# Get the pin shapes
|
||||
self.find_pins_and_blockages()
|
||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||
|
||||
# Add the supply rails in a mesh network and connect H/V with vias
|
||||
# Block everything
|
||||
|
|
@ -84,51 +81,6 @@ class supply_router(router):
|
|||
self.write_debug_gds(stop_program=False)
|
||||
return True
|
||||
|
||||
def find_pins_and_blockages(self):
|
||||
"""
|
||||
Find the pins and blockages in teh design
|
||||
"""
|
||||
# This finds the pin shapes and sorts them into "groups" that are connected
|
||||
self.find_pins(self.vdd_name)
|
||||
self.find_pins(self.gnd_name)
|
||||
|
||||
# This will get all shapes as blockages and convert to grid units
|
||||
# This ignores shapes that were pins
|
||||
self.find_blockages()
|
||||
|
||||
# This will convert the pins to grid units
|
||||
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
|
||||
self.convert_pins(self.vdd_name)
|
||||
self.convert_pins(self.gnd_name)
|
||||
|
||||
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
|
||||
self.enclose_pins()
|
||||
|
||||
|
||||
def prepare_blockages(self):
|
||||
"""
|
||||
Reset and add all of the blockages in the design.
|
||||
Names is a list of pins to add as a blockage.
|
||||
"""
|
||||
# Start fresh. Not the best for run-time, but simpler.
|
||||
self.clear_blockages()
|
||||
# This adds the initial blockges of the design
|
||||
#print("BLOCKING:",self.blocked_grids)
|
||||
self.set_blockages(self.blocked_grids,True)
|
||||
|
||||
# Block all of the supply rails (some will be unblocked if they're a target)
|
||||
self.set_supply_rail_blocked(True)
|
||||
|
||||
# Block all of the pin components (some will be unblocked if they're a source/target)
|
||||
for name in self.pin_components.keys():
|
||||
self.set_blockages(self.pin_components[name],True)
|
||||
|
||||
# Block all of the pin component partial blockages
|
||||
for name in self.pin_component_blockages.keys():
|
||||
self.set_blockages(self.pin_component_blockages[name],True)
|
||||
|
||||
# These are the paths that have already been routed.
|
||||
self.set_path_blockages()
|
||||
|
||||
def connect_supply_rails(self, name):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ class no_blockages_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
|
||||
r=router(layer_stack,self,gds_file)
|
||||
self.assertTrue(r.route(src="A",dest="B"))
|
||||
|
||||
r=routing("01_no_blockages_test_{0}".format(OPTS.tech_name))
|
||||
self.local_drc_check(r)
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ class blockages_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
|
||||
r=router(layer_stack,self,gds_file)
|
||||
self.assertTrue(r.route(src="A",dest="B"))
|
||||
|
||||
r=routing("02_blockages_test_{0}".format(OPTS.tech_name))
|
||||
self.local_drc_check(r)
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ class same_layer_pins_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
|
||||
r=router(layer_stack,self,gds_file)
|
||||
self.assertTrue(r.route(src="A",dest="B"))
|
||||
|
||||
r = routing("03_same_layer_pins_test_{0}".format(OPTS.tech_name))
|
||||
self.local_drc_check(r)
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ class diff_layer_pins_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
|
||||
r=router(layer_stack,self,gds_file)
|
||||
self.assertTrue(r.route(src="A",dest="B"))
|
||||
|
||||
r = routing("04_diff_layer_pins_test_{0}".format(OPTS.tech_name))
|
||||
self.local_drc_check(r)
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ class two_nets_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
|
||||
self.assertTrue(r.route(self,layer_stack,src="C",dest="D"))
|
||||
r=router(layer_stack,self,gds_file)
|
||||
self.assertTrue(r.route(src="A",dest="B"))
|
||||
self.assertTrue(r.route(src="C",dest="D"))
|
||||
|
||||
r = routing("05_two_nets_test_{0}".format(OPTS.tech_name))
|
||||
self.local_drc_check(r)
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@ class pin_location_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
r=router(layer_stack,self,gds_file)
|
||||
# these are user coordinates and layers
|
||||
src_pin = [[0.52, 4.099],11]
|
||||
tgt_pin = [[3.533, 1.087],11]
|
||||
#r.route(layer_stack,src="A",dest="B")
|
||||
self.assertTrue(r.route(self,layer_stack,src=src_pin,dest=tgt_pin))
|
||||
self.assertTrue(r.route(src=src_pin,dest=tgt_pin))
|
||||
|
||||
# This only works for freepdk45 since the coordinates are hard coded
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ class big_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
r=router(layer_stack,self,gds_file)
|
||||
connections=[('out_0_2', 'a_0_0'),
|
||||
('out_0_3', 'b_0_0'),
|
||||
('out_0_0', 'a_0_1'),
|
||||
|
|
@ -61,7 +61,7 @@ class big_test(openram_test):
|
|||
('out_4_1', 'a_4_3'),
|
||||
('out_4_5', 'b_4_3')]
|
||||
for (src,tgt) in connections:
|
||||
self.assertTrue(r.route(self,layer_stack,src=src,dest=tgt))
|
||||
self.assertTrue(r.route(src=src,dest=tgt))
|
||||
|
||||
# This test only runs on scn3me_subm tech
|
||||
if OPTS.tech_name=="scn3me_subm":
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ class expand_region_test(openram_test):
|
|||
offset=[0,0])
|
||||
self.connect_inst([])
|
||||
|
||||
r=router(gds_file)
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
r=router(layer_stack,self,gds_file)
|
||||
# This should be infeasible because it is blocked without a detour.
|
||||
self.assertFalse(r.route(self,layer_stack,src="A",dest="B",detour_scale=1))
|
||||
self.assertFalse(r.route(src="A",dest="B",detour_scale=1))
|
||||
# This should be feasible because we allow it to detour
|
||||
self.assertTrue(r.route(self,layer_stack,src="A",dest="B",detour_scale=3))
|
||||
self.assertTrue(r.route(src="A",dest="B",detour_scale=3))
|
||||
|
||||
r = routing("08_expand_region_test_{0}".format(OPTS.tech_name))
|
||||
self.local_drc_check(r)
|
||||
|
|
|
|||
|
|
@ -17,36 +17,26 @@ class no_blockages_test(openram_test):
|
|||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
from gds_cell import gds_cell
|
||||
from design import design
|
||||
from supply_router import supply_router as router
|
||||
|
||||
class routing(design, openram_test):
|
||||
"""
|
||||
A generic GDS design that we can route on.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
design.__init__(self, "top")
|
||||
|
||||
# Instantiate a GDS cell with the design
|
||||
globals.setup_paths()
|
||||
from control_logic import control_logic
|
||||
cell = control_logic(16)
|
||||
#from pinv import pinv
|
||||
#cell = pinv()
|
||||
#gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),"control_logic")
|
||||
#cell = gds_cell(name, gds_file)
|
||||
self.add_inst(name=name,
|
||||
mod=cell,
|
||||
offset=[0,0])
|
||||
self.connect_inst(cell.pin_map.keys())
|
||||
if True:
|
||||
from control_logic import control_logic
|
||||
cell = control_logic(16)
|
||||
else:
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
cell = sram(c, "sram1")
|
||||
|
||||
r=router(module=cell)
|
||||
layer_stack =("metal3","via3","metal4")
|
||||
self.assertTrue(r.route(self,layer_stack))
|
||||
|
||||
r=routing("10_supply_grid_test_{0}".format(OPTS.tech_name))
|
||||
self.local_drc_check(r)
|
||||
print("PRE:",cell)
|
||||
layer_stack =("metal3","via3","metal4")
|
||||
rtr=router(layer_stack, cell)
|
||||
self.assertTrue(rtr.route())
|
||||
self.local_check(cell,True)
|
||||
|
||||
# fails if there are any DRC errors on any cells
|
||||
globals.end_openram()
|
||||
|
|
|
|||
Loading…
Reference in New Issue