Merge branch 'dev' into datasheet_gen

This commit is contained in:
Jesse Cirimelli-Low 2018-12-04 16:27:04 -08:00
commit b6e7ddd023
14 changed files with 355 additions and 315 deletions

View File

@ -441,10 +441,10 @@ class pin_layout:
""" """
Given three co-linear points, determine if q lies on segment pr Given three co-linear points, determine if q lies on segment pr
""" """
if q[0] <= max(p[0], r[0]) and \ if q.x <= max(p.x, r.x) and \
q[0] >= min(p[0], r[0]) and \ q.x >= min(p.x, r.x) and \
q[1] <= max(p[1], r[1]) and \ q.y <= max(p.y, r.y) and \
q[1] >= min(p[1], r[1]): q.y >= min(p.y, r.y):
return True return True
return False return False
@ -473,8 +473,8 @@ class pin_layout:
x = (b2*c1 - b1*c2)/determinant x = (b2*c1 - b1*c2)/determinant
y = (a1*c2 - a2*c1)/determinant y = (a1*c2 - a2*c1)/determinant
r = [x,y] r = vector(x,y).snap_to_grid()
if self.on_segment(a, r, b) and self.on_segment(c, r, d): if self.on_segment(a, r, b) and self.on_segment(c, r, d):
return [x, y] return r
return None return None

View File

@ -172,7 +172,6 @@ class pin_group:
ymax = max(plc.y,elc.y) ymax = max(plc.y,elc.y)
ll = vector(plc.x, ymin) ll = vector(plc.x, ymin)
ur = vector(prc.x, ymax) ur = vector(prc.x, ymax)
p = pin_layout(pin.name, [ll, ur], pin.layer)
elif pin.yoverlaps(enclosure): elif pin.yoverlaps(enclosure):
# Is it horizontal overlap, extend pin shape to enclosure # Is it horizontal overlap, extend pin shape to enclosure
pbc = pin.bc() pbc = pin.bc()
@ -183,7 +182,6 @@ class pin_group:
xmax = max(pbc.x,ebc.x) xmax = max(pbc.x,ebc.x)
ll = vector(xmin, pbc.y) ll = vector(xmin, pbc.y)
ur = vector(xmax, puc.y) ur = vector(xmax, puc.y)
p = pin_layout(pin.name, [ll, ur], pin.layer)
else: else:
# Neither, so we must do a corner-to corner # Neither, so we must do a corner-to corner
pc = pin.center() pc = pin.center()
@ -194,8 +192,10 @@ class pin_group:
ymax = max(pc.y, ec.y) ymax = max(pc.y, ec.y)
ll = vector(xmin, ymin) ll = vector(xmin, ymin)
ur = vector(xmax, ymax) ur = vector(xmax, ymax)
p = pin_layout(pin.name, [ll, ur], pin.layer)
if ll.x==ur.x or ll.y==ur.y:
return None
p = pin_layout(pin.name, [ll, ur], pin.layer)
return p return p
def find_above_connector(self, pin, enclosures): def find_above_connector(self, pin, enclosures):
@ -226,7 +226,7 @@ class pin_group:
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if above_item.overlaps(pin): if above_item.overlaps(pin):
return None return None
# Otherwise, make a connector to the item # Otherwise, make a connector to the item
p = self.compute_connector(pin, above_item) p = self.compute_connector(pin, above_item)
return p return p
@ -485,7 +485,9 @@ class pin_group:
for pin_list in self.pins: for pin_list in self.pins:
if not self.overlap_any_shape(pin_list, self.enclosures): if not self.overlap_any_shape(pin_list, self.enclosures):
connector = self.find_smallest_connector(pin_list, self.enclosures) connector = self.find_smallest_connector(pin_list, self.enclosures)
debug.check(connector!=None, "Could not find a connector for {} with {}".format(pin_list, self.enclosures)) if connector==None:
debug.error("Could not find a connector for {} with {}".format(pin_list, self.enclosures))
self.router.write_debug_gds("no_connector.gds")
self.enclosures.append(connector) self.enclosures.append(connector)
@ -559,15 +561,13 @@ class pin_group:
of any grid in the other set. of any grid in the other set.
""" """
# We could optimize this to just check the boundaries # We could optimize this to just check the boundaries
g1_grids = set() adj_grids = set()
g2_grids = set()
for g1 in self.grids: for g1 in self.grids:
for g2 in other.grids: for g2 in other.grids:
if g1.distance(g2) <= separation: if g1.distance(g2) <= separation:
g1_grids.add(g1) adj_grids.add(g1)
g2_grids.add(g2)
return g1_grids,g2_grids return adj_grids
def convert_pin(self): def convert_pin(self):
""" """
@ -576,14 +576,16 @@ class pin_group:
should be either blocked or part of the pin. should be either blocked or part of the pin.
""" """
pin_set = set() pin_set = set()
partial_set = set()
blockage_set = set() blockage_set = set()
for pin_list in self.pins: for pin_list in self.pins:
for pin in pin_list: for pin in pin_list:
debug.info(2," Converting {0}".format(pin)) debug.info(2," Converting {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin) (sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin)
pin_set.update(pin_in_tracks) pin_set.update(sufficient)
partial_set.update(insufficient)
# Blockages will be a super-set of pins since it uses the inflated pin shape. # Blockages will be a super-set of pins since it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin) blockage_in_tracks = self.router.convert_blockage(pin)
@ -595,89 +597,94 @@ class pin_group:
if len(shared_set)>0: if len(shared_set)>0:
debug.info(2,"Removing pins {}".format(shared_set)) debug.info(2,"Removing pins {}".format(shared_set))
pin_set.difference_update(shared_set) pin_set.difference_update(shared_set)
shared_set = partial_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing pins {}".format(shared_set))
partial_set.difference_update(shared_set)
shared_set = blockage_set & self.router.blocked_grids shared_set = blockage_set & self.router.blocked_grids
if len(shared_set)>0: if len(shared_set)>0:
debug.info(2,"Removing blocks {}".format(shared_set)) debug.info(2,"Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set) blockage_set.difference_update(shared_set)
# At least one of the groups must have some valid tracks # At least one of the groups must have some valid tracks
if (len(pin_set)==0 and len(blockage_set)==0): if (len(pin_set)==0 and len(partial_set)==0 and len(blockage_set)==0):
#debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) #debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin_list in self.pins: for pin_list in self.pins:
for pin in pin_list: for pin in pin_list:
debug.info(2," Converting {0}".format(pin)) debug.warning(" Expanding conversion {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin, expansion=1) (sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
pin_set.update(pin_in_tracks) pin_set.update(sufficient)
partial_set.update(insufficient)
if len(pin_set)==0: if len(pin_set)==0 and len(partial_set)==0:
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins)) debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins))
self.router.write_debug_gds("blocked_pin.gds") self.router.write_debug_gds("blocked_pin.gds")
# We need to route each of the components, so don't combine the groups # Consider all the grids that would be blocked
self.grids = pin_set | blockage_set self.grids = pin_set | partial_set
# Remember the secondary grids for removing adjacent pins in wide metal spacing # Remember the secondary grids for removing adjacent pins
self.secondary_grids = blockage_set - pin_set self.secondary_grids = partial_set
debug.info(2," pins {}".format(self.grids)) debug.info(2," pins {}".format(self.grids))
debug.info(2," secondary {}".format(self.secondary_grids)) debug.info(2," secondary {}".format(self.secondary_grids))
def recurse_simple_overlap_enclosure(self, start_set, direct): # def recurse_simple_overlap_enclosure(self, start_set, direct):
""" # """
Recursive function to return set of tracks that connects to # Recursive function to return set of tracks that connects to
the actual supply rail wire in a given direction (or terminating # the actual supply rail wire in a given direction (or terminating
when any track is no longer in the supply rail. # when any track is no longer in the supply rail.
""" # """
next_set = grid_utils.expand_border(start_set, direct) # next_set = grid_utils.expand_border(start_set, direct)
supply_tracks = self.router.supply_rail_tracks[self.name] # supply_tracks = self.router.supply_rail_tracks[self.name]
supply_wire_tracks = self.router.supply_rail_wire_tracks[self.name] # supply_wire_tracks = self.router.supply_rail_wire_tracks[self.name]
supply_overlap = next_set & supply_tracks # supply_overlap = next_set & supply_tracks
wire_overlap = next_set & supply_wire_tracks # wire_overlap = next_set & supply_wire_tracks
# If the rail overlap is the same, we are done, since we connected to the actual wire # # If the rail overlap is the same, we are done, since we connected to the actual wire
if len(wire_overlap)==len(start_set): # if len(wire_overlap)==len(start_set):
new_set = start_set | wire_overlap # new_set = start_set | wire_overlap
# If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region # # If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
elif len(supply_overlap)==len(start_set): # elif len(supply_overlap)==len(start_set):
recurse_set = self.recurse_simple_overlap_enclosure(supply_overlap, direct) # recurse_set = self.recurse_simple_overlap_enclosure(supply_overlap, direct)
new_set = start_set | supply_overlap | recurse_set # new_set = start_set | supply_overlap | recurse_set
else: # else:
# If we got no next set, we are done, can't expand! # # If we got no next set, we are done, can't expand!
new_set = set() # new_set = set()
return new_set # return new_set
def create_simple_overlap_enclosure(self, start_set): # def create_simple_overlap_enclosure(self, start_set):
""" # """
This takes a set of tracks that overlap a supply rail and creates an enclosure # This takes a set of tracks that overlap a supply rail and creates an enclosure
that is ensured to overlap the supply rail wire. # that is ensured to overlap the supply rail wire.
It then adds rectangle(s) for the enclosure. # It then adds rectangle(s) for the enclosure.
""" # """
additional_set = set() # additional_set = set()
# Check the layer of any element in the pin to determine which direction to route it # # Check the layer of any element in the pin to determine which direction to route it
e = next(iter(start_set)) # e = next(iter(start_set))
new_set = start_set.copy() # new_set = start_set.copy()
if e.z==0: # if e.z==0:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.NORTH) # new_set = self.recurse_simple_overlap_enclosure(start_set, direction.NORTH)
if not new_set: # if not new_set:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.SOUTH) # new_set = self.recurse_simple_overlap_enclosure(start_set, direction.SOUTH)
else: # else:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.EAST) # new_set = self.recurse_simple_overlap_enclosure(start_set, direction.EAST)
if not new_set: # if not new_set:
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.WEST) # new_set = self.recurse_simple_overlap_enclosure(start_set, direction.WEST)
# Expand the pin grid set to include some extra grids that connect the supply rail # # Expand the pin grid set to include some extra grids that connect the supply rail
self.grids.update(new_set) # self.grids.update(new_set)
# Add the inflated set so we don't get wide metal spacing issues (if it exists) # # Block the grids
self.blockages.update(grid_utils.inflate_set(new_set,self.router.supply_rail_space_width)) # self.blockages.update(new_set)
# Add the polygon enclosures and set this pin group as routed # # Add the polygon enclosures and set this pin group as routed
self.set_routed() # self.set_routed()
self.enclosures = self.compute_enclosures() # self.enclosures = self.compute_enclosures()

View File

@ -21,12 +21,12 @@ class router(router_tech):
It populates blockages on a grid class. It populates blockages on a grid class.
""" """
def __init__(self, layers, design, gds_filename=None): def __init__(self, layers, design, gds_filename=None, rail_track_width=1):
""" """
This will instantiate a copy of the gds file or the module at (0,0) and 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. route on top of this. The blockages from the gds/module will be considered.
""" """
router_tech.__init__(self, layers) router_tech.__init__(self, layers, rail_track_width)
self.cell = design self.cell = design
@ -177,15 +177,15 @@ class router(router_tech):
#print_time("Convert pins",datetime.now(), start_time) #print_time("Convert pins",datetime.now(), start_time)
#start_time = datetime.now() #start_time = datetime.now()
for pin in pin_list: #for pin in pin_list:
self.combine_adjacent_pins(pin) # self.combine_adjacent_pins(pin)
#print_time("Combine pins",datetime.now(), start_time) #print_time("Combine pins",datetime.now(), start_time)
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True) #self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
# Separate any adjacent grids of differing net names to prevent wide metal DRC violations # Separate any adjacent grids of differing net names that overlap
# Must be done before enclosing pins # Must be done before enclosing pins
#start_time = datetime.now() #start_time = datetime.now()
self.separate_adjacent_pins(self.supply_rail_space_width) self.separate_adjacent_pins(0)
#print_time("Separate pins",datetime.now(), start_time) #print_time("Separate pins",datetime.now(), start_time)
# For debug # For debug
#self.separate_adjacent_pins(1) #self.separate_adjacent_pins(1)
@ -201,7 +201,7 @@ class router(router_tech):
""" """
Find pins that have adjacent routing tracks and merge them into a Find pins that have adjacent routing tracks and merge them into a
single pin_group. The pins themselves may not be touching, but single pin_group. The pins themselves may not be touching, but
enclose_pis in the next step will ensure they are touching. enclose_pins in the next step will ensure they are touching.
""" """
debug.info(1,"Combining adjacent pins for {}.".format(pin_name)) debug.info(1,"Combining adjacent pins for {}.".format(pin_name))
# Find all adjacencies # Find all adjacencies
@ -279,48 +279,50 @@ class router(router_tech):
debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2)) debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2))
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]):
# FIgXME: Use separation distance and edge grids only adj_grids = pg1.adjacent_grids(pg2, separation)
grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation)
# These should have the same length, so... # These should have the same length, so...
if len(grids_g1)>0: if len(adj_grids)>0:
debug.info(3,"Adjacent grids {0} {1} {2} {3}".format(index1,grids_g1,index2,grids_g2)) debug.info(2,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids))
self.remove_adjacent_grid(pg1, grids_g1, pg2, grids_g2) self.remove_adjacent_grid(pg1, pg2, adj_grids)
def remove_adjacent_grid(self, pg1, grids1, pg2, grids2): def remove_adjacent_grid(self, pg1, pg2, adj_grids):
""" """
Remove one of the adjacent grids in a heuristic manner. Remove one of the adjacent grids in a heuristic manner.
This will try to keep the groups similar sized by removing from the bigger group.
""" """
# Determine the bigger and smaller group
if pg1.size()>pg2.size(): if pg1.size()>pg2.size():
bigger = pg1 bigger = pg1
bigger_grids = grids1
smaller = pg2 smaller = pg2
smaller_grids = grids2
else: else:
bigger = pg2 bigger = pg2
bigger_grids = grids2
smaller = pg1 smaller = pg1
smaller_grids = grids1
# First, see if we can remove grids that are in the secondary grids for adj in adj_grids:
# i.e. they aren't necessary to the pin grids
if bigger_grids.issubset(bigger.secondary_grids):
debug.info(3,"Removing {} from bigger {}".format(str(bigger_grids), bigger))
bigger.grids.difference_update(bigger_grids)
self.blocked_grids.update(bigger_grids)
return
elif smaller_grids.issubset(smaller.secondary_grids):
debug.info(3,"Removing {} from smaller {}".format(str(smaller_grids), smaller))
smaller.grids.difference_update(smaller_grids)
self.blocked_grids.update(smaller_grids)
return
# If that fails, just randomly remove from the bigger one and give a warning.
# This might fail later. # If the adjacent grids are a subset of the secondary grids (i.e. not necessary)
debug.warning("Removing arbitrary grids from a pin group {} {}".format(bigger, bigger_grids)) # remove them from each
debug.check(len(bigger.grids)>len(bigger_grids),"Zero size pin group after adjacency removal {} {}".format(bigger, bigger_grids)) if adj in bigger.secondary_grids:
bigger.grids.difference_update(bigger_grids) debug.info(2,"Removing {} from bigger secondary {}".format(adj, bigger))
self.blocked_grids.update(bigger_grids) bigger.grids.remove(adj)
bigger.secondary_grids.remove(adj)
self.blocked_grids.add(adj)
elif adj in smaller.secondary_grids:
debug.info(2,"Removing {} from smaller secondary {}".format(adj, smaller))
smaller.grids.remove(adj)
smaller.secondary_grids.remove(adj)
self.blocked_grids.add(adj)
else:
# If we couldn't remove from a secondary grid, we must remove from the primary
# grid of at least one pin
if adj in bigger.grids:
debug.info(2,"Removing {} from bigger primary {}".format(adj, bigger))
bigger.grids.remove(adj)
elif adj in smaller.grids:
debug.info(2,"Removing {} from smaller primary {}".format(adj, smaller))
smaller.grids.remove(adj)
@ -515,36 +517,24 @@ class router(router_tech):
# scale the size bigger to include neaby tracks # scale the size bigger to include neaby tracks
ll=ll.scale(self.track_factor).floor() ll=ll.scale(self.track_factor).floor()
ur=ur.scale(self.track_factor).ceil() ur=ur.scale(self.track_factor).ceil()
#print(pin)
# Keep tabs on tracks with sufficient and insufficient overlap # Keep tabs on tracks with sufficient and insufficient overlap
sufficient_list = set() sufficient_list = set()
insufficient_list = set() insufficient_list = set()
zindex=self.get_zindex(pin.layer_num) zindex=self.get_zindex(pin.layer_num)
for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion): for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion):
for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion): for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion):
(full_overlap,partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex)) (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
if full_overlap: if full_overlap:
sufficient_list.update([full_overlap]) sufficient_list.update([full_overlap])
if partial_overlap: if partial_overlap:
insufficient_list.update([partial_overlap]) insufficient_list.update([partial_overlap])
debug.info(4,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap)) debug.info(2,"Converting [ {0} , {1} ] full={2}".format(x,y, full_overlap))
# Remove the blocked grids # Return all grids with any potential overlap (sufficient or not)
sufficient_list.difference_update(self.blocked_grids) return (sufficient_list,insufficient_list)
insufficient_list.difference_update(self.blocked_grids)
if len(sufficient_list)>0:
return sufficient_list
elif expansion==0 and len(insufficient_list)>0:
best_pin = self.get_all_offgrid_pin(pin, insufficient_list)
#print(best_pin)
return best_pin
elif expansion>0:
nearest_pin = self.get_furthest_offgrid_pin(pin, insufficient_list)
return nearest_pin
else:
return set()
def get_all_offgrid_pin(self, pin, insufficient_list): def get_all_offgrid_pin(self, pin, insufficient_list):
""" """
@ -622,26 +612,32 @@ class router(router_tech):
def convert_pin_coord_to_tracks(self, pin, coord): def convert_pin_coord_to_tracks(self, pin, coord):
""" """
Given a pin and a track coordinate, determine if the pin overlaps enough. Return all tracks that an inflated pin overlaps
If it does, add additional metal to make the pin "on grid".
If it doesn't, add it to the blocked grid list.
""" """
(width, spacing) = self.get_layer_width_space(coord.z) # This is using the full track shape rather than a single track pin shape
# because we will later patch a connector if there isn't overlap.
# This is the rectangle if we put a pin in the center of the track track_pin = self.convert_track_to_shape_pin(coord)
track_pin = self.convert_track_to_pin(coord)
overlap_length = pin.overlap_length(track_pin) # This is the normal pin inflated by a minimum design rule
inflated_pin = pin_layout(pin.name, pin.inflate(0.5*self.track_space), pin.layer)
debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length)) overlap_length = pin.overlap_length(track_pin)
# If it overlaps by more than the min width DRC, we can just use the track debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
if overlap_length==math.inf or snap_val_to_grid(overlap_length) >= snap_val_to_grid(width): inflated_overlap_length = inflated_pin.overlap_length(track_pin)
debug.info(3," Overlap: {0} >? {1}".format(overlap_length,spacing)) debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, inflated_pin.rect, track_pin, inflated_overlap_length))
return (coord, None)
# Otherwise, keep track of the partial overlap grids in case we need to patch it later. # If it overlaps with the pin, it is sufficient
if overlap_length==math.inf or overlap_length > 0:
debug.info(2," Overlap: {0} >? {1}".format(overlap_length,0))
return (coord,None)
# If it overlaps with the inflated pin, it is partial
elif inflated_overlap_length==math.inf or inflated_overlap_length > 0:
debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length,0))
return (None,coord)
else: else:
debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,spacing)) debug.info(2," No overlap: {0} {1}".format(overlap_length,0))
return (None, coord) return (None,None)
@ -653,25 +649,34 @@ class router(router_tech):
Convert a grid point into a rectangle shape that is centered Convert a grid point into a rectangle shape that is centered
track in the track and leaves half a DRC space in each direction. track in the track and leaves half a DRC space in each direction.
""" """
# space depends on which layer it is
if self.get_layer(track[2])==self.horiz_layer_name:
space = 0.5*self.horiz_layer_spacing
else:
space = 0.5*self.vert_layer_spacing
# calculate lower left # calculate lower left
x = track.x*self.track_width - 0.5*self.track_width + space x = track.x*self.track_width - 0.5*self.track_width + 0.5*self.track_space
y = track.y*self.track_width - 0.5*self.track_width + space y = track.y*self.track_width - 0.5*self.track_width + 0.5*self.track_space
ll = snap_to_grid(vector(x,y)) ll = snap_to_grid(vector(x,y))
# calculate upper right # calculate upper right
x = track.x*self.track_width + 0.5*self.track_width - space x = track.x*self.track_width + 0.5*self.track_width - 0.5*self.track_space
y = track.y*self.track_width + 0.5*self.track_width - space y = track.y*self.track_width + 0.5*self.track_width - 0.5*self.track_space
ur = snap_to_grid(vector(x,y)) ur = snap_to_grid(vector(x,y))
p = pin_layout("", [ll, ur], self.get_layer(track[2])) p = pin_layout("", [ll, ur], self.get_layer(track[2]))
return p return p
def convert_track_to_shape_pin(self, track):
"""
Convert a grid point into a rectangle shape that occupies the entire centered
track.
"""
# to scale coordinates to tracks
x = track[0]*self.track_width - 0.5*self.track_width
y = track[1]*self.track_width - 0.5*self.track_width
# offset lowest corner object to to (-track halo,-track halo)
ll = snap_to_grid(vector(x,y))
ur = snap_to_grid(ll + vector(self.track_width,self.track_width))
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
return p
def convert_track_to_shape(self, track): def convert_track_to_shape(self, track):
""" """
Convert a grid point into a rectangle shape that occupies the entire centered Convert a grid point into a rectangle shape that occupies the entire centered
@ -686,6 +691,23 @@ class router(router_tech):
return [ll,ur] return [ll,ur]
def convert_track_to_inflated_pin(self, track):
"""
Convert a grid point into a rectangle shape that is inflated by a half DRC space.
"""
# calculate lower left
x = track.x*self.track_width - 0.5*self.track_width - 0.5*self.track_space
y = track.y*self.track_width - 0.5*self.track_width - 0.5*self.track_space
ll = snap_to_grid(vector(x,y))
# calculate upper right
x = track.x*self.track_width + 0.5*self.track_width + 0.5*self.track_space
y = track.y*self.track_width + 0.5*self.track_width + 0.5*self.track_space
ur = snap_to_grid(vector(x,y))
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
return p
def analyze_pins(self, pin_name): def analyze_pins(self, pin_name):
""" """
Analyze the shapes of a pin and combine them into groups which are connected. Analyze the shapes of a pin and combine them into groups which are connected.
@ -877,8 +899,6 @@ class router(router_tech):
Enclose the tracks from ll to ur in a single rectangle that meets Enclose the tracks from ll to ur in a single rectangle that meets
the track DRC rules. the track DRC rules.
""" """
# Get the layer information
(width, space) = self.get_layer_width_space(zindex)
layer = self.get_layer(zindex) layer = self.get_layer(zindex)
# This finds the pin shape enclosed by the track with DRC spacing on the sides # This finds the pin shape enclosed by the track with DRC spacing on the sides
@ -894,35 +914,35 @@ class router(router_tech):
return pin return pin
def compute_wide_enclosure(self, ll, ur, zindex, name=""): # def compute_wide_enclosure(self, ll, ur, zindex, name=""):
""" # """
Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules. # Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
""" # """
# Find the pin enclosure of the whole track shape (ignoring DRCs) # # Find the pin enclosure of the whole track shape (ignoring DRCs)
(abs_ll,unused) = self.convert_track_to_shape(ll) # (abs_ll,unused) = self.convert_track_to_shape(ll)
(unused,abs_ur) = self.convert_track_to_shape(ur) # (unused,abs_ur) = self.convert_track_to_shape(ur)
# Get the layer information # # Get the layer information
x_distance = abs(abs_ll.x-abs_ur.x) # x_distance = abs(abs_ll.x-abs_ur.x)
y_distance = abs(abs_ll.y-abs_ur.y) # y_distance = abs(abs_ll.y-abs_ur.y)
shape_width = min(x_distance, y_distance) # shape_width = min(x_distance, y_distance)
shape_length = max(x_distance, y_distance) # shape_length = max(x_distance, y_distance)
# Get the DRC rule for the grid dimensions # # Get the DRC rule for the grid dimensions
(width, space) = self.get_layer_width_space(zindex, shape_width, shape_length) # (width, space) = self.get_supply_layer_width_space(zindex)
layer = self.get_layer(zindex) # layer = self.get_layer(zindex)
if zindex==0: # if zindex==0:
spacing = vector(0.5*self.track_width, 0.5*space) # spacing = vector(0.5*self.track_width, 0.5*space)
else: # else:
spacing = vector(0.5*space, 0.5*self.track_width) # spacing = vector(0.5*space, 0.5*self.track_width)
# Compute the shape offsets with correct spacing # # Compute the shape offsets with correct spacing
new_ll = abs_ll + spacing # new_ll = abs_ll + spacing
new_ur = abs_ur - spacing # new_ur = abs_ur - spacing
pin = pin_layout(name, [new_ll, new_ur], layer) # pin = pin_layout(name, [new_ll, new_ur], layer)
return pin # return pin
def contract_path(self,path): def contract_path(self,path):
@ -963,8 +983,7 @@ class router(router_tech):
self.add_route(path) self.add_route(path)
path_set = grid_utils.flatten_set(path) path_set = grid_utils.flatten_set(path)
inflated_path = grid_utils.inflate_set(path_set,self.supply_rail_space_width) self.path_blockages.append(path_set)
self.path_blockages.append(inflated_path)
else: else:
self.write_debug_gds("failed_route.gds") self.write_debug_gds("failed_route.gds")
# clean up so we can try a reroute # clean up so we can try a reroute

View File

@ -3,48 +3,62 @@ from contact import contact
from pin_group import pin_group from pin_group import pin_group
from vector import vector from vector import vector
import debug import debug
import math
class router_tech: class router_tech:
""" """
This is a class to hold the router tech constants. This is a class to hold the router tech constants.
""" """
def __init__(self, layers): def __init__(self, layers, rail_track_width):
""" """
Allows us to change the layers that we are routing on. First layer Allows us to change the layers that we are routing on. First layer
is always horizontal, middle is via, and last is always is always horizontal, middle is via, and last is always
vertical. vertical.
""" """
self.layers = layers self.layers = layers
self.rail_track_width = rail_track_width
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers (self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
# This is the minimum routed track spacing # This is the minimum routed track spacing
via_connect = contact(self.layers, (1, 1)) via_connect = contact(self.layers, (1, 1))
self.max_via_size = max(via_connect.width,via_connect.height) max_via_size = max(via_connect.width,via_connect.height)
self.vert_layer_minwidth = drc("minwidth_{0}".format(self.vert_layer_name)) self.horiz_layer_number = layer[self.horiz_layer_name]
self.vert_layer_spacing = drc(str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name))
self.vert_layer_number = layer[self.vert_layer_name] self.vert_layer_number = layer[self.vert_layer_name]
self.horiz_layer_minwidth = drc("minwidth_{0}".format(self.horiz_layer_name)) if self.rail_track_width>1:
self.horiz_layer_spacing = drc(str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name)) (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
self.horiz_layer_number = layer[self.horiz_layer_name] (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
self.horiz_track_width = self.max_via_size + self.horiz_layer_spacing
self.vert_track_width = self.max_via_size + self.vert_layer_spacing
# For supplies, we will make the wire wider than the vias
self.vert_layer_minwidth = max(self.vert_layer_minwidth, max_via_size)
self.horiz_layer_minwidth = max(self.horiz_layer_minwidth, max_via_size)
self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing
self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
else:
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_layer_width_space(0)
self.horiz_track_width = max_via_size + self.horiz_layer_spacing
self.vert_track_width = max_via_size + self.vert_layer_spacing
# We'll keep horizontal and vertical tracks the same for simplicity. # 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: {:.3f}".format(self.track_width))
self.track_space = max(self.horiz_layer_spacing,self.vert_layer_spacing)
debug.info(1,"Track spacing: {:.3f}".format(self.track_space))
self.track_wire = self.track_width - self.track_space
debug.info(1,"Wire width: {:.3f}".format(self.track_wire))
self.track_widths = vector([self.track_width] * 2) self.track_widths = vector([self.track_width] * 2)
self.track_factor = vector([1/self.track_width] * 2) self.track_factor = vector([1/self.track_width] * 2)
debug.info(2,"Track factor: {0}".format(self.track_factor)) debug.info(2,"Track factor: {}".format(self.track_factor))
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_width - self.horiz_layer_spacing, 1, self.track_width - self.vert_layer_spacing]
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_wire, 1, self.track_wire]
def get_zindex(self,layer_num): def get_zindex(self,layer_num):
if layer_num==self.horiz_layer_number: if layer_num==self.horiz_layer_number:
return 0 return 0
@ -76,4 +90,24 @@ class router_tech:
return (min_width,min_spacing) return (min_width,min_spacing)
def get_supply_layer_width_space(self, zindex):
"""
These are the width and spacing of a supply layer given a supply rail
of the given number of min wire widths.
"""
if zindex==1:
layer_name = self.vert_layer_name
elif zindex==0:
layer_name = self.horiz_layer_name
else:
debug.error("Invalid zindex for track", -1)
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
min_width = drc("minwidth_{0}".format(layer_name), self.rail_track_width*min_wire_width, math.inf)
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.rail_track_width*min_wire_width, math.inf)
return (min_width,min_spacing)

View File

@ -24,17 +24,16 @@ class supply_router(router):
This will route on layers in design. It will get the blockages from 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). either the gds file name or the design itself (by saving to a gds file).
""" """
router.__init__(self, layers, design, gds_filename) # Power rail width in minimum wire widths
self.rail_track_width = 3
router.__init__(self, layers, design, gds_filename, self.rail_track_width)
# The list of supply rails (grid sets) that may be routed # The list of supply rails (grid sets) that may be routed
self.supply_rails = {} self.supply_rails = {}
self.supply_rail_wires = {}
# This is the same as above but as a sigle set for the all the rails # This is the same as above but as a sigle set for the all the rails
self.supply_rail_tracks = {} self.supply_rail_tracks = {}
self.supply_rail_wire_tracks = {}
# Power rail width in grid units.
self.rail_track_width = 2
@ -116,9 +115,7 @@ class supply_router(router):
debug.info(1,"Routing simple overlap pins for {0}".format(pin_name)) debug.info(1,"Routing simple overlap pins for {0}".format(pin_name))
# These are the wire tracks # These are the wire tracks
wire_tracks = self.supply_rail_wire_tracks[pin_name] wire_tracks = self.supply_rail_tracks[pin_name]
# These are the wire and space tracks
supply_tracks = self.supply_rail_tracks[pin_name]
for pg in self.pin_groups[pin_name]: for pg in self.pin_groups[pin_name]:
if pg.is_routed(): if pg.is_routed():
@ -129,13 +126,10 @@ class supply_router(router):
if len(overlap_grids)>0: if len(overlap_grids)>0:
pg.set_routed() pg.set_routed()
continue continue
# Else, if we overlap some of the space track, we can patch it with an enclosure
common_set = supply_tracks & pg.grids
if len(common_set)>0:
pg.create_simple_overlap_enclosure(common_set)
pg.add_enclosure(self.cell)
# Else, if we overlap some of the space track, we can patch it with an enclosure
#pg.create_simple_overlap_enclosure(pg.grids)
#pg.add_enclosure(self.cell)
@ -146,7 +140,7 @@ class supply_router(router):
NOTE: It is still possible though unlikely that there are disconnected groups of rails. NOTE: It is still possible though unlikely that there are disconnected groups of rails.
""" """
all_rails = self.supply_rail_wires[name] all_rails = self.supply_rails[name]
connections = set() connections = set()
via_areas = [] via_areas = []
@ -186,8 +180,8 @@ class supply_router(router):
# the indices to determine a rail is connected to another # the indices to determine a rail is connected to another
# the overlap area for placement of a via # the overlap area for placement of a via
overlap = new_r1 & new_r2 overlap = new_r1 & new_r2
if len(overlap) >= self.supply_rail_wire_width**2: if len(overlap) >= 1:
debug.info(3,"Via overlap {0} {1} {2}".format(len(overlap),self.supply_rail_wire_width**2,overlap)) debug.info(3,"Via overlap {0} {1}".format(len(overlap),overlap))
connections.update([i1,i2]) connections.update([i1,i2])
via_areas.append(overlap) via_areas.append(overlap)
@ -196,7 +190,7 @@ class supply_router(router):
ll = grid_utils.get_lower_left(area) ll = grid_utils.get_lower_left(area)
ur = grid_utils.get_upper_right(area) ur = grid_utils.get_upper_right(area)
center = (ll + ur).scale(0.5,0.5,0) center = (ll + ur).scale(0.5,0.5,0)
self.add_via(center,self.rail_track_width) self.add_via(center,1)
# Determien which indices were not connected to anything above # Determien which indices were not connected to anything above
missing_indices = set([x for x in range(len(self.supply_rails[name]))]) missing_indices = set([x for x in range(len(self.supply_rails[name]))])
@ -209,7 +203,6 @@ class supply_router(router):
ur = grid_utils.get_upper_right(all_rails[rail_index]) ur = grid_utils.get_upper_right(all_rails[rail_index])
debug.info(1,"Removing disconnected supply rail {0} .. {1}".format(ll,ur)) debug.info(1,"Removing disconnected supply rail {0} .. {1}".format(ll,ur))
self.supply_rails[name].pop(rail_index) self.supply_rails[name].pop(rail_index)
self.supply_rail_wires[name].pop(rail_index)
# Make the supply rails into a big giant set of grids for easy blockages. # Make the supply rails into a big giant set of grids for easy blockages.
# Must be done after we determine which ones are connected. # Must be done after we determine which ones are connected.
@ -226,7 +219,7 @@ class supply_router(router):
ll = grid_utils.get_lower_left(rail) ll = grid_utils.get_lower_left(rail)
ur = grid_utils.get_upper_right(rail) ur = grid_utils.get_upper_right(rail)
z = ll.z z = ll.z
pin = self.compute_wide_enclosure(ll, ur, z, name) pin = self.compute_pin_enclosure(ll, ur, z, name)
debug.info(2,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin)) debug.info(2,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin))
self.cell.add_layout_pin(text=name, self.cell.add_layout_pin(text=name,
layer=pin.layer, layer=pin.layer,
@ -242,33 +235,30 @@ class supply_router(router):
self.max_yoffset = self.rg.ur.y self.max_yoffset = self.rg.ur.y
self.max_xoffset = self.rg.ur.x self.max_xoffset = self.rg.ur.x
# Longest length is conservative # # Longest length is conservative
rail_length = max(self.max_yoffset,self.max_xoffset) # rail_length = max(self.max_yoffset,self.max_xoffset)
# Convert the number of tracks to dimensions to get the design rule spacing # # Convert the number of tracks to dimensions to get the design rule spacing
rail_width = self.track_width*self.rail_track_width # rail_width = self.track_width*self.rail_track_width
# Get the conservative width and spacing of the top rails # # Get the conservative width and spacing of the top rails
(horizontal_width, horizontal_space) = self.get_layer_width_space(0, rail_width, rail_length) # (horizontal_width, horizontal_space) = self.get_supply_layer_width_space(0)
(vertical_width, vertical_space) = self.get_layer_width_space(1, rail_width, rail_length) # (vertical_width, vertical_space) = self.get_supply_layer_width_space(1)
width = max(horizontal_width, vertical_width) # width = max(horizontal_width, vertical_width)
space = max(horizontal_space, vertical_space) # space = max(horizontal_space, vertical_space)
# This is the supply rail pitch in terms of routing grids # track_pitch = width + space
# i.e. a rail of self.rail_track_width needs this many tracks including
# space
track_pitch = self.rail_track_width*width + space
# Determine the pitch (in tracks) of the rail wire + spacing # # Determine the pitch (in tracks) of the rail wire + spacing
self.supply_rail_width = math.ceil(track_pitch/self.track_width) # self.supply_rail_width = math.ceil(track_pitch/self.track_width)
debug.info(1,"Rail step: {}".format(self.supply_rail_width)) # debug.info(1,"Rail step: {}".format(self.supply_rail_width))
# Conservatively determine the number of tracks that the rail actually occupies # # Conservatively determine the number of tracks that the rail actually occupies
space_tracks = math.ceil(space/self.track_width) # space_tracks = math.ceil(space/self.track_width)
self.supply_rail_wire_width = self.supply_rail_width - space_tracks # self.supply_rail_wire_width = self.supply_rail_width - space_tracks
debug.info(1,"Rail wire tracks: {}".format(self.supply_rail_wire_width)) # debug.info(1,"Rail wire tracks: {}".format(self.supply_rail_wire_width))
total_space = self.supply_rail_width - self.supply_rail_wire_width # total_space = self.supply_rail_width - self.supply_rail_wire_width
self.supply_rail_space_width = math.floor(0.5*total_space) # self.supply_rail_space_width = math.floor(0.5*total_space)
debug.info(1,"Rail space tracks: {} (on both sides)".format(self.supply_rail_space_width)) # debug.info(1,"Rail space tracks: {} (on both sides)".format(self.supply_rail_space_width))
def compute_supply_rails(self, name, supply_number): def compute_supply_rails(self, name, supply_number):
@ -279,14 +269,13 @@ class supply_router(router):
""" """
self.supply_rails[name]=[] self.supply_rails[name]=[]
self.supply_rail_wires[name]=[]
start_offset = supply_number*self.supply_rail_width start_offset = supply_number
# Horizontal supply rails # Horizontal supply rails
for offset in range(start_offset, self.max_yoffset, 2*self.supply_rail_width): for offset in range(start_offset, self.max_yoffset, 2):
# Seed the function at the location with the given width # Seed the function at the location with the given width
wave = [vector3d(0,offset+i,0) for i in range(self.supply_rail_width)] wave = [vector3d(0,offset,0)]
# While we can keep expanding east in this horizontal track # While we can keep expanding east in this horizontal track
while wave and wave[0].x < self.max_xoffset: while wave and wave[0].x < self.max_xoffset:
added_rail = self.find_supply_rail(name, wave, direction.EAST) added_rail = self.find_supply_rail(name, wave, direction.EAST)
@ -299,9 +288,9 @@ class supply_router(router):
# Vertical supply rails # Vertical supply rails
max_offset = self.rg.ur.x max_offset = self.rg.ur.x
for offset in range(start_offset, self.max_xoffset, 2*self.supply_rail_width): for offset in range(start_offset, self.max_xoffset, 2):
# Seed the function at the location with the given width # Seed the function at the location with the given width
wave = [vector3d(offset+i,0,1) for i in range(self.supply_rail_width)] wave = [vector3d(offset,0,1)]
# While we can keep expanding north in this vertical track # While we can keep expanding north in this vertical track
while wave and wave[0].y < self.max_yoffset: while wave and wave[0].y < self.max_yoffset:
added_rail = self.find_supply_rail(name, wave, direction.NORTH) added_rail = self.find_supply_rail(name, wave, direction.NORTH)
@ -378,11 +367,6 @@ class supply_router(router):
if len(wave_path)>=4*self.rail_track_width: if len(wave_path)>=4*self.rail_track_width:
grid_set = wave_path.get_grids() grid_set = wave_path.get_grids()
self.supply_rails[name].append(grid_set) self.supply_rails[name].append(grid_set)
start_wire_index = self.supply_rail_space_width
end_wire_index = self.supply_rail_width - self.supply_rail_space_width
wire_set = wave_path.get_wire_grids(start_wire_index,end_wire_index)
self.supply_rail_wires[name].append(wire_set)
return True return True
return False return False
@ -417,10 +401,6 @@ class supply_router(router):
rail_set.update(rail) rail_set.update(rail)
self.supply_rail_tracks[pin_name] = rail_set self.supply_rail_tracks[pin_name] = rail_set
wire_set = set()
for rail in self.supply_rail_wires[pin_name]:
wire_set.update(rail)
self.supply_rail_wire_tracks[pin_name] = wire_set
def route_pins_to_rails(self, pin_name): def route_pins_to_rails(self, pin_name):
@ -465,7 +445,7 @@ class supply_router(router):
""" """
debug.info(4,"Add supply rail target {}".format(pin_name)) debug.info(4,"Add supply rail target {}".format(pin_name))
# Add the wire itself as the target # Add the wire itself as the target
self.rg.set_target(self.supply_rail_wire_tracks[pin_name]) self.rg.set_target(self.supply_rail_tracks[pin_name])
# But unblock all the rail tracks including the space # But unblock all the rail tracks including the space
self.rg.set_blocked(self.supply_rail_tracks[pin_name],False) self.rg.set_blocked(self.supply_rail_tracks[pin_name],False)

View File

@ -22,6 +22,9 @@ class no_blockages_test(openram_test):
if False: if False:
from control_logic import control_logic from control_logic import control_logic
cell = control_logic(16) cell = control_logic(16)
layer_stack =("metal3","via3","metal4")
rtr=router(layer_stack, cell)
self.assertTrue(rtr.route())
else: else:
from sram import sram from sram import sram
from sram_config import sram_config from sram_config import sram_config
@ -33,9 +36,6 @@ class no_blockages_test(openram_test):
sram = sram(c, "sram1") sram = sram(c, "sram1")
cell = sram.s cell = sram.s
layer_stack =("metal3","via3","metal4")
rtr=router(layer_stack, cell)
self.assertTrue(rtr.route())
self.local_check(cell,True) self.local_check(cell,True)
# fails if there are any DRC errors on any cells # fails if there are any DRC errors on any cells

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
@unittest.skip("SKIPPING 20_psram_1bank_2mux_test, wide metal supply routing error") #@unittest.skip("SKIPPING 20_psram_1bank_2mux_test, wide metal supply routing error")
class psram_1bank_2mux_test(openram_test): class psram_1bank_2mux_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -29,13 +29,13 @@ class sram_1bank_2mux_1rw_1r_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
c.word_size, c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,
c.num_banks)) c.num_banks))
a = sram(c, "sram") a = sram(c, "sram")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)

View File

@ -23,13 +23,13 @@ class sram_1bank_2mux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
c.word_size, c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,
c.num_banks)) c.num_banks))
a = sram(c, "sram") a = sram(c, "sram")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)

View File

@ -23,13 +23,13 @@ class sram_1bank_4mux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=4 c.words_per_row=4
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
c.word_size, c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,
c.num_banks)) c.num_banks))
a = sram(c, "sram") a = sram(c, "sram")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)

View File

@ -29,13 +29,13 @@ class sram_1bank_8mux_1rw_1r_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
c.word_size, c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,
c.num_banks)) c.num_banks))
a = sram(c, "sram") a = sram(c, "sram")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)

View File

@ -23,13 +23,13 @@ class sram_1bank_8mux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
c.word_size, c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,
c.num_banks)) c.num_banks))
a = sram(c, "sram") a = sram(c, "sram")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)

View File

@ -29,13 +29,13 @@ class sram_1bank_nomux_1rw_1r_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
c.word_size, c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,
c.num_banks)) c.num_banks))
a = sram(c, "sram") a = sram(c, "sram")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)

View File

@ -23,13 +23,13 @@ class sram_1bank_nomux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
c.word_size, c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,
c.num_banks)) c.num_banks))
a = sram(c, "sram") a = sram(c, "sram")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)