From 7e2bef624ea58caa9913487e5bf2148a311e73b4 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 24 Oct 2018 12:32:27 -0700 Subject: [PATCH 01/30] Continue routing rails in same layer after a blockage --- compiler/router/supply_router.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index dd9c3fd1..c1282c04 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -331,11 +331,12 @@ class supply_router(router): # While we can keep expanding east in this horizontal track while wave and wave[0].x < self.max_xoffset: added_rail = self.find_supply_rail(name, wave, direction.EAST) - if added_rail: - wave = added_rail.neighbor(direction.EAST) + if not added_rail: + # Just seed with the next one + wave = [x+vector3d(1,0,0) for x in wave] else: - wave = None - + # Seed with the neighbor of the end of the last rail + wave = added_rail.neighbor(direction.EAST) # Vertical supply rails max_offset = self.rg.ur.x @@ -345,10 +346,12 @@ class supply_router(router): # While we can keep expanding north in this vertical track while wave and wave[0].y < self.max_yoffset: added_rail = self.find_supply_rail(name, wave, direction.NORTH) - if added_rail: - wave = added_rail.neighbor(direction.NORTH) + if not added_rail: + # Just seed with the next one + wave = [x+vector3d(0,1,0) for x in wave] else: - wave = None + # Seed with the neighbor of the end of the last rail + wave = added_rail.neighbor(direction.NORTH) def find_supply_rail(self, name, seed_wave, direct): """ @@ -356,15 +359,18 @@ class supply_router(router): to contain a via, and, if so, add it. """ start_wave = self.find_supply_rail_start(name, seed_wave, direct) + + # This means there were no more unblocked grids in the row/col if not start_wave: return None - + wave_path = self.probe_supply_rail(name, start_wave, direct) - if self.approve_supply_rail(name, wave_path): - return wave_path - else: - return None + self.approve_supply_rail(name, wave_path) + + # Return the rail whether we approved it or not, + # as it will be used to find the next start location + return wave_path def find_supply_rail_start(self, name, seed_wave, direct): """ From dc73e8cb60aa56733024b3610e4b51e049cfe459 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 24 Oct 2018 16:12:27 -0700 Subject: [PATCH 02/30] Odd bug that instances were not properly rotated. --- compiler/base/geometry.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index b766b1af..33bcaaa2 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -147,8 +147,12 @@ class instance(geometry): self.width = 0 self.height = 0 else: - self.width = round_to_grid(mod.width) - self.height = round_to_grid(mod.height) + if mirror in ["R90","R270"] or rotate in [90,270]: + self.width = round_to_grid(mod.height) + self.height = round_to_grid(mod.width) + else: + 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) From 94e5050513948a5baf2c69558640817a9ac975fb Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 24 Oct 2018 16:13:07 -0700 Subject: [PATCH 03/30] Move overlap functions to pin_layout --- compiler/base/pin_layout.py | 125 +++++++++++++++++++ compiler/router/router.py | 238 ++++++++++-------------------------- 2 files changed, 191 insertions(+), 172 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 7565c6ce..143d123d 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -2,6 +2,7 @@ import debug from tech import GDS, drc from vector import vector from tech import layer +import math class pin_layout: """ @@ -274,3 +275,127 @@ class pin_layout: magnification=GDS["zoom"], rotate=None) + + def compute_overlap(self, other): + """ Calculate the rectangular overlap of two rectangles. """ + (r1_ll,r1_ur) = self.rect + (r2_ll,r2_ur) = other.rect + + #ov_ur = vector(min(r1_ur.x,r2_ur.x),min(r1_ur.y,r2_ur.y)) + #ov_ll = vector(max(r1_ll.x,r2_ll.x),max(r1_ll.y,r2_ll.y)) + + dy = min(r1_ur.y,r2_ur.y)-max(r1_ll.y,r2_ll.y) + dx = min(r1_ur.x,r2_ur.x)-max(r1_ll.x,r2_ll.x) + + if dx>=0 and dy>=0: + return [dx,dy] + else: + return [0,0] + + def overlap_length(self, other): + """ + Calculate the intersection segment and determine its length + """ + + if self.contains(other): + return math.inf + elif other.contains(self): + return math.inf + else: + intersections = self.compute_overlap_segment(other) + # This is the common case where two pairs of edges overlap + # at two points, so just find the distance between those two points + if len(intersections)==2: + (p1,p2) = intersections + return math.sqrt(pow(p1[0]-p2[0],2) + pow(p1[1]-p2[1],2)) + else: + # This is where we had a corner intersection or none + return 0 + + + def compute_overlap_segment(self, other): + """ + Calculate the intersection segment of two rectangles + (if any) + """ + (r1_ll,r1_ur) = self.rect + (r2_ll,r2_ur) = other.rect + + # The other corners besides ll and ur + r1_ul = vector(r1_ll.x, r1_ur.y) + r1_lr = vector(r1_ur.x, r1_ll.y) + r2_ul = vector(r2_ll.x, r2_ur.y) + r2_lr = vector(r2_ur.x, r2_ll.y) + + from itertools import tee + def pairwise(iterable): + "s -> (s0,s1), (s1,s2), (s2, s3), ..." + a, b = tee(iterable) + next(b, None) + return zip(a, b) + + # R1 edges CW + r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll] + r1_edges = [] + for (p,q) in pairwise(r1_cw_points): + r1_edges.append([p,q]) + + # R2 edges CW + r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll] + r2_edges = [] + for (p,q) in pairwise(r2_cw_points): + r2_edges.append([p,q]) + + # There are 4 edges on each rectangle + # so just brute force check intersection of each + # Two pairs of them should intersect + intersections = [] + for r1e in r1_edges: + for r2e in r2_edges: + i = self.segment_intersection(r1e, r2e) + if i: + intersections.append(i) + + return intersections + + def on_segment(self, p, q, r): + """ + Given three co-linear points, determine if q lies on segment pr + """ + if q[0] <= max(p[0], r[0]) and \ + q[0] >= min(p[0], r[0]) and \ + q[1] <= max(p[1], r[1]) and \ + q[1] >= min(p[1], r[1]): + return True + + return False + + def segment_intersection(self, s1, s2): + """ + Determine the intersection point of two segments + Return the a segment if they overlap. + Return None if they don't. + """ + (a,b) = s1 + (c,d) = s2 + # Line AB represented as a1x + b1y = c1 + a1 = b.y - a.y + b1 = a.x - b.x + c1 = a1*a.x + b1*a.y + + # Line CD represented as a2x + b2y = c2 + a2 = d.y - c.y + b2 = c.x - d.x + c2 = a2*c.x + b2*c.y + + determinant = a1*b2 - a2*b1 + + if determinant!=0: + x = (b2*c1 - b1*c2)/determinant + y = (a1*c2 - a2*c1)/determinant + + r = [x,y] + if self.on_segment(a, r, b) and self.on_segment(c, r, d): + return [x, y] + + return None diff --git a/compiler/router/router.py b/compiler/router/router.py index 2cb9fb71..f14cd9f3 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -183,18 +183,6 @@ class router: self.retrieve_blockages(layer) - # # def reinit(self): - # # """ - # # Reset the source and destination pins to start a new routing. - # # Convert the source/dest pins to blockages. - # # Convert the routed path to blockages. - # # Keep the other blockages unchanged. - # # """ - # # self.clear_pins() - # # # DO NOT clear the blockages as these don't change - # # self.rg.reinit() - - def find_pins_and_blockages(self, pin_list): """ Find the pins and blockages in the design @@ -248,16 +236,16 @@ class router: # 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 - """ - coordinate = [] - for item in coord: - x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0]) - y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1]) - coordinate += [(x, y)] - return coordinate + # def translate_coordinates(self, coord, mirr, angle, xyShift): + # """ + # Calculate coordinates after flip, rotate, and shift + # """ + # coordinate = [] + # for item in coord: + # x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0]) + # y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1]) + # coordinate += [(x, y)] + # return coordinate def convert_shape_to_units(self, shape): """ @@ -458,9 +446,9 @@ class router: best_coord = None best_overlap = -math.inf for coord in insufficient_list: - full_rect = self.convert_track_to_pin(coord) + full_pin = self.convert_track_to_pin(coord) # Compute the overlap with that rectangle - overlap_rect=self.compute_overlap(pin.rect,full_rect) + overlap_rect=pin.compute_overlap(full_pin) # Determine the min x or y overlap min_overlap = min(overlap_rect) if min_overlap>best_overlap: @@ -497,144 +485,21 @@ class router: (width, spacing) = self.get_layer_width_space(coord.z) # This is the rectangle if we put a pin in the center of the track - track_rect = self.convert_track_to_pin(coord) - overlap_width = self.compute_overlap_width(pin.rect, track_rect) + track_pin = self.convert_track_to_pin(coord) + overlap_length = pin.overlap_length(track_pin) - debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_rect, overlap_width)) + debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length)) # If it overlaps by more than the min width DRC, we can just use the track - if overlap_width==math.inf or snap_val_to_grid(overlap_width) >= snap_val_to_grid(width): - debug.info(3," Overlap: {0} >? {1}".format(overlap_width,spacing)) + if overlap_length==math.inf or snap_val_to_grid(overlap_length) >= snap_val_to_grid(width): + debug.info(3," Overlap: {0} >? {1}".format(overlap_length,spacing)) return (coord, None) # Otherwise, keep track of the partial overlap grids in case we need to patch it later. else: - debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_width,spacing)) + debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,spacing)) return (None, coord) - def compute_overlap(self, r1, r2): - """ Calculate the rectangular overlap of two rectangles. """ - (r1_ll,r1_ur) = r1 - (r2_ll,r2_ur) = r2 - - #ov_ur = vector(min(r1_ur.x,r2_ur.x),min(r1_ur.y,r2_ur.y)) - #ov_ll = vector(max(r1_ll.x,r2_ll.x),max(r1_ll.y,r2_ll.y)) - - dy = min(r1_ur.y,r2_ur.y)-max(r1_ll.y,r2_ll.y) - dx = min(r1_ur.x,r2_ur.x)-max(r1_ll.x,r2_ll.x) - - if dx>0 and dy>0: - return [dx,dy] - else: - return [0,0] - - def compute_overlap_width(self, r1, r2): - """ - Calculate the intersection segment and determine its width. - """ - intersections = self.compute_overlap_segment(r1,r2) - - if len(intersections)==2: - (p1,p2) = intersections - return math.sqrt(pow(p1[0]-p2[0],2) + pow(p1[1]-p2[1],2)) - else: - # we either have no overlap or complete overlap - # Compute the width of the overlap of the two rectangles - overlap_rect=self.compute_overlap(r1, r2) - # Determine the min x or y overlap - min_overlap = min(overlap_rect) - if min_overlap>0: - return math.inf - else: - return 0 - - - def compute_overlap_segment(self, r1, r2): - """ - Calculate the intersection segment of two rectangles - (if any) - """ - (r1_ll,r1_ur) = r1 - (r2_ll,r2_ur) = r2 - - # The other corners besides ll and ur - r1_ul = vector(r1_ll.x, r1_ur.y) - r1_lr = vector(r1_ur.x, r1_ll.y) - r2_ul = vector(r2_ll.x, r2_ur.y) - r2_lr = vector(r2_ur.x, r2_ll.y) - - from itertools import tee - def pairwise(iterable): - "s -> (s0,s1), (s1,s2), (s2, s3), ..." - a, b = tee(iterable) - next(b, None) - return zip(a, b) - - # R1 edges CW - r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll] - r1_edges = [] - for (p,q) in pairwise(r1_cw_points): - r1_edges.append([p,q]) - - # R2 edges CW - r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll] - r2_edges = [] - for (p,q) in pairwise(r2_cw_points): - r2_edges.append([p,q]) - - # There are 4 edges on each rectangle - # so just brute force check intersection of each - # Two pairs of them should intersect - intersections = [] - for r1e in r1_edges: - for r2e in r2_edges: - i = self.segment_intersection(r1e, r2e) - if i: - intersections.append(i) - - return intersections - - def on_segment(self, p, q, r): - """ - Given three co-linear points, determine if q lies on segment pr - """ - if q[0] <= max(p[0], r[0]) and \ - q[0] >= min(p[0], r[0]) and \ - q[1] <= max(p[1], r[1]) and \ - q[1] >= min(p[1], r[1]): - return True - - return False - - def segment_intersection(self, s1, s2): - """ - Determine the intersection point of two segments - Return the a segment if they overlap. - Return None if they don't. - """ - (a,b) = s1 - (c,d) = s2 - # Line AB represented as a1x + b1y = c1 - a1 = b.y - a.y - b1 = a.x - b.x - c1 = a1*a.x + b1*a.y - - # Line CD represented as a2x + b2y = c2 - a2 = d.y - c.y - b2 = c.x - d.x - c2 = a2*c.x + b2*c.y - - determinant = a1*b2 - a2*b1 - - if determinant!=0: - x = (b2*c1 - b1*c2)/determinant - y = (a1*c2 - a2*c1)/determinant - - r = [x,y] - if self.on_segment(a, r, b) and self.on_segment(c, r, d): - return [x, y] - - return None @@ -659,7 +524,8 @@ class router: y = track.y*self.track_width + 0.5*self.track_width - space ur = snap_to_grid(vector(x,y)) - return [ll,ur] + p = pin_layout("", [ll, ur], self.get_layer(track[2])) + return p def convert_track_to_shape(self, track): """ @@ -758,6 +624,8 @@ class router: # Blockages will be a super-set of pins since it uses the inflated pin shape. blockage_in_tracks = self.convert_blockage(pin) blockage_set.update(blockage_in_tracks) + debug.info(2," .pins {}".format(pin_set)) + debug.info(2," .blocks {}".format(blockage_set)) # If we have a blockage, we must remove the grids # Remember, this excludes the pin blockages already @@ -864,10 +732,13 @@ class router: """ Find the minimum rectangle enclosures of the given tracks. """ + # Enumerate every possible enclosure pin_list = [] for seed in tracks: pin_list.append(self.enclose_pin_grids(tracks, seed)) + #return pin_list + # We used to do this, but smaller enclosures can be return self.remove_redundant_shapes(pin_list) def overlap_any_shape(self, pin_list, shape_list): @@ -881,6 +752,27 @@ class router: return False + def find_smallest_overlapping(self, pin_list, shape_list): + """ + Find the smallest area shape in shape_list that overlaps with any + pin in pin_list by a min width. + """ + + smallest_shape = None + for pin in pin_list: + # They may not be all on the same layer... in the future. + zindex=self.get_zindex(pin.layer_num) + (min_width,min_space) = self.get_layer_width_space(zindex) + + # Now compare it with every other shape to check how much they overlap + for other in shape_list: + overlap_length = pin.overlap_length(other) + if overlap_length > min_width: + if smallest_shape == None or other.area() Date: Wed, 24 Oct 2018 16:41:33 -0700 Subject: [PATCH 04/30] Add the minimum pin enclosure that has DRC correct pin connections. --- compiler/router/router.py | 4 +--- compiler/router/supply_router.py | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index f14cd9f3..a3878b5e 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -624,8 +624,6 @@ class router: # Blockages will be a super-set of pins since it uses the inflated pin shape. blockage_in_tracks = self.convert_blockage(pin) blockage_set.update(blockage_in_tracks) - debug.info(2," .pins {}".format(pin_set)) - debug.info(2," .blocks {}".format(blockage_set)) # If we have a blockage, we must remove the grids # Remember, this excludes the pin blockages already @@ -839,7 +837,7 @@ class router: - self.write_debug_gds("pin_debug.gds", True) + #self.write_debug_gds("pin_debug.gds", True) def compute_enclosure(self, pin, enclosure): """ diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index c1282c04..597b6b1d 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -98,8 +98,6 @@ class supply_router(router): return True - - def route_simple_overlaps(self, pin_name): From b1f3bd97e5c49129474bd672b1d5899d580135e7 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 24 Oct 2018 17:01:00 -0700 Subject: [PATCH 05/30] Enable all the 1bank tests. Mostly work in SCMOS. --- compiler/tests/20_sram_1bank_2mux_test.py | 2 +- compiler/tests/20_sram_1bank_4mux_test.py | 2 +- compiler/tests/20_sram_1bank_8mux_test.py | 2 +- compiler/tests/20_sram_1bank_nomux_test.py | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/tests/20_sram_1bank_2mux_test.py b/compiler/tests/20_sram_1bank_2mux_test.py index db018f1e..8c275e7c 100755 --- a/compiler/tests/20_sram_1bank_2mux_test.py +++ b/compiler/tests/20_sram_1bank_2mux_test.py @@ -11,7 +11,7 @@ import globals from globals import OPTS import debug -@unittest.skip("SKIPPING 20_sram_1bank_2mux_test") +#@unittest.skip("SKIPPING 20_sram_1bank_2mux_test") class sram_1bank_2mux_test(openram_test): def runTest(self): diff --git a/compiler/tests/20_sram_1bank_4mux_test.py b/compiler/tests/20_sram_1bank_4mux_test.py index 35416bbe..4ff443dc 100755 --- a/compiler/tests/20_sram_1bank_4mux_test.py +++ b/compiler/tests/20_sram_1bank_4mux_test.py @@ -11,7 +11,7 @@ import globals from globals import OPTS import debug -@unittest.skip("SKIPPING 20_sram_1bank_2mux_test") +#@unittest.skip("SKIPPING 20_sram_1bank_4mux_test") class sram_1bank_4mux_test(openram_test): def runTest(self): diff --git a/compiler/tests/20_sram_1bank_8mux_test.py b/compiler/tests/20_sram_1bank_8mux_test.py index d09165a2..695dcffe 100755 --- a/compiler/tests/20_sram_1bank_8mux_test.py +++ b/compiler/tests/20_sram_1bank_8mux_test.py @@ -11,7 +11,7 @@ import globals from globals import OPTS import debug -@unittest.skip("SKIPPING 20_sram_1bank_8mux_test") +#@unittest.skip("SKIPPING 20_sram_1bank_8mux_test") class sram_1bank_8mux_test(openram_test): def runTest(self): diff --git a/compiler/tests/20_sram_1bank_nomux_test.py b/compiler/tests/20_sram_1bank_nomux_test.py index 26f5e9ba..a89fb4e5 100755 --- a/compiler/tests/20_sram_1bank_nomux_test.py +++ b/compiler/tests/20_sram_1bank_nomux_test.py @@ -11,7 +11,8 @@ import globals from globals import OPTS import debug -class sram_1bank_test(openram_test): +#@unittest.skip("SKIPPING 20_sram_1bank_nomux_test") +class sram_1bank_nomux_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) From 0544d02ca25e8ea9ed928931bb486638e6a1ecf8 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Thu, 25 Oct 2018 13:36:35 -0700 Subject: [PATCH 06/30] Refactor router to have pin_groups for pins and router_tech file --- compiler/router/pin_group.py | 238 +++++++++++++++++++++ compiler/router/router.py | 354 +++---------------------------- compiler/router/router_tech.py | 78 +++++++ compiler/router/supply_router.py | 65 +++--- 4 files changed, 378 insertions(+), 357 deletions(-) create mode 100644 compiler/router/pin_group.py create mode 100644 compiler/router/router_tech.py diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py new file mode 100644 index 00000000..b1599a8e --- /dev/null +++ b/compiler/router/pin_group.py @@ -0,0 +1,238 @@ +from vector3d import vector3d +from tech import drc +import debug + +class pin_group: + """ + A class to represent a group of touching rectangular design pin. + It requires a router to define the track widths and blockages which + determine how pin shapes get mapped to tracks. + """ + def __init__(self, name, pin_shapes, router): + self.name = name + # Flag for when it is routed + self.routed = False + self.shapes = pin_shapes + self.router = router + # These are the corresponding pin grids for each pin group. + self.grids = set() + # The corresponding set of partially blocked grids for each pin group. + # These are blockages for other nets but unblocked for routing this group. + self.blockages = set() + + def set_routed(self, value=True): + self.routed = value + + def is_routed(self): + return self.routed + + def remove_redundant_shapes(self, pin_list): + """ + Remove any pin layout that is contained within another. + """ + local_debug = False + if local_debug: + debug.info(0,"INITIAL:",pin_list) + + # Make a copy of the list to start + new_pin_list = pin_list.copy() + + # This is n^2, but the number is small + for pin1 in pin_list: + for pin2 in pin_list: + # Can't contain yourself + if pin1 == pin2: + continue + if pin2.contains(pin1): + # It may have already been removed by being enclosed in another pin + if pin1 in new_pin_list: + new_pin_list.remove(pin1) + + if local_debug: + debug.info(0,"FINAL :",new_pin_list) + return new_pin_list + + # FIXME: This relies on some technology parameters from router which is not clearn. + def compute_enclosures(self): + """ + Find the minimum rectangle enclosures of the given tracks. + """ + # Enumerate every possible enclosure + pin_list = [] + for seed in self.grids: + (ll, ur) = self.enclose_pin_grids(seed) + enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) + pin_list.append(enclosure) + + #return pin_list + # We used to do this, but smaller enclosures can be + return self.remove_redundant_shapes(pin_list) + + def compute_enclosure(self, pin, enclosure): + """ + Compute an enclosure to connect the pin to the enclosure shape. + This assumes the shape will be the dimension of the pin. + """ + if pin.xoverlaps(enclosure): + # Is it vertical overlap, extend pin shape to enclosure + plc = pin.lc() + prc = pin.rc() + elc = enclosure.lc() + erc = enclosure.rc() + ymin = min(plc.y,elc.y) + ymax = max(plc.y,elc.y) + ll = vector(plc.x, ymin) + ur = vector(prc.x, ymax) + p = pin_layout(pin.name, [ll, ur], pin.layer) + elif pin.yoverlaps(enclosure): + # Is it horizontal overlap, extend pin shape to enclosure + pbc = pin.bc() + puc = pin.uc() + ebc = enclosure.bc() + euc = enclosure.uc() + xmin = min(pbc.x,ebc.x) + xmax = max(pbc.x,ebc.x) + ll = vector(xmin, pbc.y) + ur = vector(xmax, puc.y) + p = pin_layout(pin.name, [ll, ur], pin.layer) + else: + # Neither, so we must do a corner-to corner + pc = pin.center() + ec = enclosure.center() + xmin = min(pc.x, ec.x) + xmax = max(pc.x, ec.x) + ymin = min(pc.y, ec.y) + ymax = max(pc.y, ec.y) + ll = vector(xmin, ymin) + ur = vector(xmax, ymax) + p = pin_layout(pin.name, [ll, ur], pin.layer) + + return p + + def find_smallest_connector(self, enclosure_list): + """ + Compute all of the connectors between non-overlapping pins and enclosures. + Return the smallest. + """ + smallest = None + for pin in self.shapes: + for enclosure in enclosure_list: + new_enclosure = self.compute_enclosure(pin, enclosure) + if smallest == None or new_enclosure.area() min_width: + if smallest_shape == None or other.area() biggest.area(): + biggest = pin + + return pin + + def enclose_pin_grids(self, seed): + """ + This encloses a single pin component with a rectangle + starting with the seed and expanding right until blocked + and then up until blocked. + """ + + # We may have started with an empty set + if not self.grids: + return None + + # Start with the seed + ll = seed + + # Start with the ll and make the widest row + row = [ll] + # Move right while we can + while True: + right = row[-1] + vector3d(1,0,0) + # Can't move if not in the pin shape + if right in self.grids and right not in self.router.blocked_grids: + row.append(right) + else: + break + # Move up while we can + while True: + next_row = [x+vector3d(0,1,0) for x in row] + for cell in next_row: + # Can't move if any cell is not in the pin shape + if cell not in self.grids or cell in self.router.blocked_grids: + break + else: + row = next_row + # Skips the second break + continue + # Breaks from the nested break + break + + # Add a shape from ll to ur + ur = row[-1] + return (ll,ur) + + + def enclose_pin(self): + """ + This will find the biggest rectangle enclosing some grid squares and + put a rectangle over it. It does not enclose grid squares that are blocked + by other shapes. + """ + # Compute the enclosure pin_layout list of the set of tracks + enclosure_list = self.compute_enclosures() + self.enclosure = self.find_smallest_overlapping(enclosure_list) + if not self.enclosure: + self.enclosure = self.find_smallest_connector(enclosure_list) + debug.info(2,"Computed enclosure {0} {1}".format(self.name, self.enclosure)) + + def add_enclosure(self, cell): + """ + Add the enclosure shape to the given cell. + """ + debug.info(2,"Adding enclosure {0} {1}".format(self.name, self.enclosure)) + self.router.cell.add_rect(layer=self.enclosure.layer, + offset=self.enclosure.ll(), + width=self.enclosure.width(), + height=self.enclosure.height()) + + + + diff --git a/compiler/router/router.py b/compiler/router/router.py index a3878b5e..7269e07f 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -1,17 +1,18 @@ import sys import gdsMill -from tech import drc,GDS,layer -from contact import contact +from tech import drc,GDS import math import debug +from router_tech import router_tech from pin_layout import pin_layout +from pin_group import pin_group from vector import vector from vector3d import vector3d from globals import OPTS from pprint import pformat import grid_utils -class router: +class router(router_tech): """ A router class to read an obstruction map from a gds and plan a route on a given layer. This is limited to two layer routes. @@ -23,6 +24,8 @@ class router: 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. """ + router_tech.__init__(self, layers) + self.cell = design # If didn't specify a gds blockage file, write it out to read the gds @@ -37,22 +40,16 @@ class router: 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 + # A map of pin names to a set of pin_layout structures self.pins = {} - # This is a set of all pins so that we don't create blockages for these shapes. + # This is a set of all pins (ignoring names) so that can quickly not create blockages for pins + # (They will be blocked based on the names we are routing) self.all_pins = set() - # This is a set of pin groups. Each group consists of overlapping pin shapes on the same layer. + # A map of pin names to a list of pin groups + # A pin group is a set overlapping pin shapes on the same layer. self.pin_groups = {} - # These are the corresponding pin grids for each pin group. - self.pin_grids = {} - # The corresponding set of partially blocked grids for each pin group. - # These are blockages for other nets but unblocked for this component. - self.pin_blockages = {} ### The blockage data structures # A list of metal shapes (using the same pin_layout structure) that are not pins but blockages. @@ -78,8 +75,6 @@ class router: self.pins = {} self.all_pins = set() self.pin_groups = {} - self.pin_grids = {} - self.pin_blockages = {} # DO NOT clear the blockages as these don't change self.rg.reinit() @@ -88,19 +83,6 @@ class router: """ If we want to route something besides the top-level cell.""" self.top_name = top_name - def get_zindex(self,layer_num): - if layer_num==self.horiz_layer_number: - return 0 - else: - return 1 - - def get_layer(self, zindex): - if zindex==1: - return self.vert_layer_name - elif zindex==0: - return self.horiz_layer_name - else: - debug.error("Invalid zindex {}".format(zindex),-1) def is_wave(self,path): """ @@ -108,40 +90,6 @@ class router: """ return len(path[0])>1 - def set_layers(self, layers): - """ - Allows us to change the layers that we are routing on. First layer - is always horizontal, middle is via, and last is always - vertical. - """ - self.layers = layers - (self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers - - # This is the minimum routed track spacing - via_connect = contact(self.layers, (1, 1)) - self.max_via_size = max(via_connect.width,via_connect.height) - - self.vert_layer_minwidth = drc("minwidth_{0}".format(self.vert_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.horiz_layer_minwidth = drc("minwidth_{0}".format(self.horiz_layer_name)) - self.horiz_layer_spacing = drc(str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name)) - self.horiz_layer_number = layer[self.horiz_layer_name] - - self.horiz_track_width = self.max_via_size + self.horiz_layer_spacing - self.vert_track_width = self.max_via_size + self.vert_layer_spacing - - # We'll keep horizontal and vertical tracks the same for simplicity. - self.track_width = max(self.horiz_track_width,self.vert_track_width) - debug.info(1,"Track width: "+str(self.track_width)) - - self.track_widths = [self.track_width] * 2 - self.track_factor = [1/self.track_width] * 2 - debug.info(1,"Track factor: {0}".format(self.track_factor)) - - # 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] def retrieve_pins(self,pin_name): """ @@ -224,14 +172,16 @@ class router: 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_grids.keys(): - self.set_blockages(self.pin_grids[name],True) + for name in self.pin_groups.keys(): + blockage_grids = {y for x in self.pin_groups[name] for y in x.grids} + self.set_blockages(blockage_grids,True) # 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 # route over them - self.set_blockages(self.pin_grids[pin_name],False) + blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids} + self.set_blockages(blockage_grids,False) # These are the paths that have already been routed. self.set_path_blockages() @@ -458,23 +408,6 @@ class router: return set([best_coord]) - def get_layer_width_space(self, zindex, width=0, length=0): - """ - Return the width and spacing of a given layer - and wire of a given width and length. - """ - 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_width = drc("minwidth_{0}".format(layer_name), width, length) - min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length) - - return (min_width,min_spacing) - def convert_pin_coord_to_tracks(self, pin, coord): """ Given a pin and a track coordinate, determine if the pin overlaps enough. @@ -599,24 +532,18 @@ class router: reduced_classes = combine_classes(equiv_classes) if local_debug: debug.info(0,"FINAL ",reduced_classes) - self.pin_groups[pin_name]=reduced_classes + self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_shapes=x, router=self) for x in reduced_classes] def convert_pins(self, pin_name): """ Convert the pin groups into pin tracks and blockage tracks. """ - try: - self.pin_grids[pin_name] - except: - self.pin_grids[pin_name] = [] - - found_pin = False for pg in self.pin_groups[pin_name]: #print("PG ",pg) # Keep the same groups for each pin pin_set = set() blockage_set = set() - for pin in pg: + for pin in pg.shapes: debug.info(2," Converting {0}".format(pin)) # Determine which tracks the pin overlaps pin_in_tracks=self.convert_pin_to_tracks(pin_name, pin) @@ -644,7 +571,7 @@ class router: debug.error("Unable to find unblocked pin on grid.") # We need to route each of the components, so don't combine the groups - self.pin_grids[pin_name].append(pin_set | blockage_set) + pg.grids = pin_set | blockage_set # Add all of the partial blocked grids to the set for the design # if they are not blocked by other metal @@ -658,143 +585,6 @@ class router: #self.blocked_grids.difference_update(pin_set) - def enclose_pin_grids(self, grids, seed): - """ - This encloses a single pin component with a rectangle - starting with the seed and expanding right until blocked - and then up until blocked. - """ - - # We may have started with an empty set - if not grids: - return None - - # Start with the seed - ll = seed - - # Start with the ll and make the widest row - row = [ll] - # Move right while we can - while True: - right = row[-1] + vector3d(1,0,0) - # Can't move if not in the pin shape - if right in grids and right not in self.blocked_grids: - row.append(right) - else: - break - # Move up while we can - while True: - next_row = [x+vector3d(0,1,0) for x in row] - for cell in next_row: - # Can't move if any cell is not in the pin shape - if cell not in grids or cell in self.blocked_grids: - break - else: - row = next_row - # Skips the second break - continue - # Breaks from the nested break - break - - # Add a shape from ll to ur - ur = row[-1] - return self.compute_pin_enclosure(ll, ur, ll.z) - - def remove_redundant_shapes(self, pin_list): - """ - Remove any pin layout that is contained within another. - """ - local_debug = False - if local_debug: - debug.info(0,"INITIAL:",pin_list) - - # Make a copy of the list to start - new_pin_list = pin_list.copy() - - # This is n^2, but the number is small - for pin1 in pin_list: - for pin2 in pin_list: - # Can't contain yourself - if pin1 == pin2: - continue - if pin2.contains(pin1): - # It may have already been removed by being enclosed in another pin - if pin1 in new_pin_list: - new_pin_list.remove(pin1) - - if local_debug: - debug.info(0,"FINAL :",new_pin_list) - return new_pin_list - - def compute_enclosures(self, tracks): - """ - Find the minimum rectangle enclosures of the given tracks. - """ - # Enumerate every possible enclosure - pin_list = [] - for seed in tracks: - pin_list.append(self.enclose_pin_grids(tracks, seed)) - - #return pin_list - # We used to do this, but smaller enclosures can be - return self.remove_redundant_shapes(pin_list) - - def overlap_any_shape(self, pin_list, shape_list): - """ - Does the given pin overlap any of the shapes in the pin list. - """ - for pin in pin_list: - for other in shape_list: - if pin.overlaps(other): - return True - - return False - - def find_smallest_overlapping(self, pin_list, shape_list): - """ - Find the smallest area shape in shape_list that overlaps with any - pin in pin_list by a min width. - """ - - smallest_shape = None - for pin in pin_list: - # They may not be all on the same layer... in the future. - zindex=self.get_zindex(pin.layer_num) - (min_width,min_space) = self.get_layer_width_space(zindex) - - # Now compare it with every other shape to check how much they overlap - for other in shape_list: - overlap_length = pin.overlap_length(other) - if overlap_length > min_width: - if smallest_shape == None or other.area() biggest.area(): - biggest = pin - - return pin - - def find_smallest_connector(self, pin_list, enclosure_list): - """ - Compute all of the connectors between non-overlapping pins and enclosures. - Return the smallest. - """ - smallest = None - for pin in pin_list: - for enclosure in enclosure_list: - new_enclosure = self.compute_enclosure(pin, enclosure) - if smallest == None or new_enclosure.area()0: + self.create_simple_overlap_enclosure(pin_name, common_set) + pg.set_routed() + + def recurse_simple_overlap_enclosure(self, pin_name, start_set, direct): """ @@ -167,7 +165,9 @@ class supply_router(router): if not new_set: new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST) - enclosure_list = self.compute_enclosures(new_set) + pg = pin_group(name=pin_name, pin_shapes=[], router=self) + pg.grids=new_set + enclosure_list = pg.compute_enclosures() for pin in enclosure_list: debug.info(2,"Adding simple overlap enclosure {0} {1}".format(pin_name, pin)) self.cell.add_rect(layer=pin.layer, @@ -464,23 +464,26 @@ class supply_router(router): self.supply_rail_wire_tracks[pin_name] = wire_set - def route_pins_to_rails(self, pin_name, remaining_component_indices): + def route_pins_to_rails(self, pin_name): """ This will route each of the remaining pin components to the supply rails. After it is done, the cells are added to the pin blockage list. """ - + remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name]) debug.info(1,"Pin {0} has {1} remaining components to route.".format(pin_name, - len(remaining_component_indices))) + remaining_components)) - recent_paths = [] - # For every component - for index in remaining_component_indices: + for index,pg in enumerate(self.pin_groups[pin_name]): + if pg.is_routed(): + continue debug.info(2,"Routing component {0} {1}".format(pin_name, index)) - + + # Clear everything in the routing grid. self.rg.reinit() - + + # This is inefficient since it is non-incremental, but it was + # easier to debug. self.prepare_blockages(pin_name) # Add the single component of the pin as the source @@ -491,16 +494,10 @@ class supply_router(router): # Don't add the other pins, but we could? self.add_supply_rail_target(pin_name) - # Add the previous paths as targets too - #self.add_path_target(recent_paths) - - #print(self.rg.target) - # Actually run the A* router if not self.run_router(detour_scale=5): self.write_debug_gds() - recent_paths.append(self.paths[-1]) def add_supply_rail_target(self, pin_name): From 3407163cf134dab8cd5a7a87ac17031e79c0c66a Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Thu, 25 Oct 2018 14:25:52 -0700 Subject: [PATCH 07/30] Combine adjacent power supply pins finished --- compiler/router/pin_group.py | 77 ++++++++++++++++++++++++++---- compiler/router/router.py | 80 ++++++++++++++------------------ compiler/router/supply_router.py | 2 +- compiler/router/vector3d.py | 14 ++++++ 4 files changed, 119 insertions(+), 54 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index b1599a8e..d6344fb6 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -12,7 +12,7 @@ class pin_group: self.name = name # Flag for when it is routed self.routed = False - self.shapes = pin_shapes + self.pins = pin_shapes self.router = router # These are the corresponding pin grids for each pin group. self.grids = set() @@ -115,7 +115,7 @@ class pin_group: Return the smallest. """ smallest = None - for pin in self.shapes: + for pin in self.pins: for enclosure in enclosure_list: new_enclosure = self.compute_enclosure(pin, enclosure) if smallest == None or new_enclosure.area() Date: Thu, 25 Oct 2018 14:40:39 -0700 Subject: [PATCH 08/30] Fix bug in duplicate remove indices --- compiler/router/router.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index cc6a7944..3019180a 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -167,7 +167,7 @@ class router(router_tech): # Make a copy since we are going to reduce this list pin_groups = self.pin_groups[pin_name].copy() - remove_indices = [] + remove_indices = set() for index1,pg1 in enumerate(self.pin_groups[pin_name]): for index2,pg2 in enumerate(self.pin_groups[pin_name]): @@ -180,8 +180,7 @@ class router(router_tech): combined.grids = pg1.grids | pg2.grids # check if there are any blockage problems?? - remove_indices.append(index1) - remove_indices.append(index2) + remove_indices.update([index1,index2]) pin_groups.append(combined) # Remove them in decreasing order to not invalidate the indices From 4ce6b040fd42ef65864c7d00259f99fe6548f3aa Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 26 Oct 2018 09:25:10 -0700 Subject: [PATCH 09/30] Debugging missing enclosures --- compiler/router/pin_group.py | 113 ++++++++++++++++++++----------- compiler/router/router.py | 46 ++++++------- compiler/router/supply_router.py | 14 ++-- 3 files changed, 101 insertions(+), 72 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index d6344fb6..00664e14 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -1,10 +1,12 @@ +from pin_layout import pin_layout from vector3d import vector3d +from vector import vector from tech import drc import debug class pin_group: """ - A class to represent a group of touching rectangular design pin. + A class to represent a group of rectangular design pin. It requires a router to define the track widths and blockages which determine how pin shapes get mapped to tracks. """ @@ -12,7 +14,9 @@ class pin_group: self.name = name # Flag for when it is routed self.routed = False - self.pins = pin_shapes + # This is a list because we can have a pin group of disconnected sets of pins + # and these are represented by separate lists + self.pins = [pin_shapes] self.router = router # These are the corresponding pin grids for each pin group. self.grids = set() @@ -52,7 +56,7 @@ class pin_group: debug.info(0,"FINAL :",new_pin_list) return new_pin_list - # FIXME: This relies on some technology parameters from router which is not clearn. + # FIXME: This relies on some technology parameters from router which is not clean. def compute_enclosures(self): """ Find the minimum rectangle enclosures of the given tracks. @@ -64,6 +68,7 @@ class pin_group: enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) pin_list.append(enclosure) + print("ENCLOS",pin_list) #return pin_list # We used to do this, but smaller enclosures can be return self.remove_redundant_shapes(pin_list) @@ -115,32 +120,48 @@ class pin_group: Return the smallest. """ smallest = None - for pin in self.pins: - for enclosure in enclosure_list: - new_enclosure = self.compute_enclosure(pin, enclosure) - if smallest == None or new_enclosure.area() min_width: - if smallest_shape == None or other.area() min_width: + if smallest_shape == None or other.area()= self.supply_rail_wire_width**2: - debug.info(2,"Via overlap {0} {1} {2}".format(len(overlap),self.supply_rail_wire_width**2,overlap)) - connections.add(i1) - connections.add(i2) + debug.info(3,"Via overlap {0} {1} {2}".format(len(overlap),self.supply_rail_wire_width**2,overlap)) + connections.update([i1,i2]) via_areas.append(overlap) # Go through and add the vias at the center of the intersection @@ -239,11 +238,12 @@ class supply_router(router): self.add_via(center,self.rail_track_width) # Determien which indices were not connected to anything above - all_indices = set([x for x in range(len(self.supply_rails[name]))]) - missing_indices = all_indices ^ connections + missing_indices = set([x for x in range(len(self.supply_rails[name]))]) + missing_indices.difference_update(connections) + # Go through and remove those disconnected indices # (No via was added, so that doesn't need to be removed) - for rail_index in missing_indices: + for rail_index in sorted(missing_indices, reverse=True): ll = grid_utils.get_lower_left(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)) From 7d74d34c534e672ef644caa43d818124b0d004ec Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 26 Oct 2018 10:40:43 -0700 Subject: [PATCH 10/30] Fix pin_layout contains bug --- compiler/base/pin_layout.py | 14 ++++++++++---- compiler/router/pin_group.py | 9 ++++----- compiler/router/supply_router.py | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 143d123d..bea511e2 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -122,14 +122,20 @@ class pin_layout: (ll,ur) = self.rect (oll,our) = other.rect - - + + # Check if the oll is inside the y range if not (oll.y >= ll.y and oll.y <= ur.y): return False - + # Check if the oll is inside the x range if not (oll.x >= ll.x and oll.x <= ur.x): return False - + # Check if the our is inside the y range + if not (our.y >= ll.y and our.y <= ur.y): + return False + # Check if the our is inside the x range + if not (our.x >= ll.x and our.x <= ur.x): + return False + return True diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 00664e14..9ab52045 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -36,7 +36,7 @@ class pin_group: """ local_debug = False if local_debug: - debug.info(0,"INITIAL:",pin_list) + debug.info(0,"INITIAL: {}".format(pin_list)) # Make a copy of the list to start new_pin_list = pin_list.copy() @@ -48,12 +48,14 @@ class pin_group: if pin1 == pin2: continue if pin2.contains(pin1): + if local_debug: + debug.info(0,"{0} contains {1}".format(pin1,pin2)) # It may have already been removed by being enclosed in another pin if pin1 in new_pin_list: new_pin_list.remove(pin1) if local_debug: - debug.info(0,"FINAL :",new_pin_list) + debug.info(0,"FINAL : {}".format(new_pin_list)) return new_pin_list # FIXME: This relies on some technology parameters from router which is not clean. @@ -68,9 +70,6 @@ class pin_group: enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) pin_list.append(enclosure) - print("ENCLOS",pin_list) - #return pin_list - # We used to do this, but smaller enclosures can be return self.remove_redundant_shapes(pin_list) def compute_enclosure(self, pin, enclosure): diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 093bd1de..4f12e16a 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -71,7 +71,7 @@ class supply_router(router): # Get the pin shapes self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) - self.write_debug_gds("pin_enclosures.gds",stop_program=True) + #self.write_debug_gds("pin_enclosures.gds",stop_program=True) # Add the supply rails in a mesh network and connect H/V with vias # Block everything From 0107e1c050b43ea967a49df09bcbb3bae998c46d Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 26 Oct 2018 13:02:31 -0700 Subject: [PATCH 11/30] Reduce verbosity of utils --- compiler/base/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/base/utils.py b/compiler/base/utils.py index 28c5f997..f9597f39 100644 --- a/compiler/base/utils.py +++ b/compiler/base/utils.py @@ -66,7 +66,7 @@ def get_gds_size(name, gds_filename, units, layer): Open a GDS file and return the size from either the bounding box or a border layer. """ - debug.info(2,"Creating VLSI layout for {}".format(name)) + debug.info(4,"Creating VLSI layout for {}".format(name)) cell_vlsi = gdsMill.VlsiLayout(units=units) reader = gdsMill.Gds2reader(cell_vlsi) reader.loadFromFile(gds_filename) From 851aeae8c4ad6c710b0d6da98483080ea2e81e83 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 10:28:57 -0700 Subject: [PATCH 12/30] Add pins_enclosed function to pin_group --- compiler/router/pin_group.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 9ab52045..032c4fa4 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -30,6 +30,25 @@ class pin_group: def is_routed(self): return self.routed + def pins_enclosed(self): + """ + Check if all of the pin shapes are enclosed. + Does not check if the DRC is correct, but just touching. + """ + for pin_list in self.pins: + pin_is_enclosed=False + for pin in pin_list: + if pin_is_enclosed: + break + for encosure in self.enclosures: + if pin.overlaps(enclosure): + pin_is_enclosed=True + break + else: + return False + + return True + def remove_redundant_shapes(self, pin_list): """ Remove any pin layout that is contained within another. From 6990773ea16edc06e5e7670fc1ba38bab1a5914f Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 10:32:42 -0700 Subject: [PATCH 13/30] Add error check requiring non-zero area pin layouts. --- compiler/base/pin_layout.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index bea511e2..7a7ccd96 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -19,6 +19,10 @@ class pin_layout: self.rect = [vector(rect[0]),vector(rect[1])] # snap the rect to the grid self.rect = [x.snap_to_grid() for x in self.rect] + + debug.check(self.width()>0,"Zero width pin.") + debug.check(self.height()>0,"Zero height pin.") + # if it's a layer number look up the layer name. this assumes a unique layer number. if type(layer_name_num)==int: self.layer = list(layer.keys())[list(layer.values()).index(layer_name_num)] From bbffec863bd61ffe10148e6e877c35d19251ac4b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 10:59:22 -0700 Subject: [PATCH 14/30] Abandon connectors for now and opt for all enclosures --- compiler/router/pin_group.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 032c4fa4..f14abecb 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -260,12 +260,12 @@ class pin_group: smallest = self.find_smallest_overlapping(self.pins[0],enclosure_list) if smallest: self.enclosures=[smallest] - else: - connector=self.find_smallest_connector(enclosure_list) - if connector: - self.enclosures=[connector] - else: - debug.error("Unable to enclose pin {}".format(self.pins),-1) + # else: + # connector=self.find_smallest_connector(enclosure_list) + # if connector: + # self.enclosures=[connector] + # else: + # debug.error("Unable to enclose pin {}".format(self.pins),-1) else: # Multiple pins is hard, so just use all of the enclosure shapes! # FIXME: Find the minimum set of enclosures to reduce number of shapes. From b7655eab1030f1a1c641d40c4ab5db571de01deb Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 11:07:02 -0700 Subject: [PATCH 15/30] Remove bug for combining pin with multiple other pins in a single iteration --- compiler/router/router.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index 24af6e8c..0a0d2625 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -169,21 +169,25 @@ class router(router_tech): remove_indices = set() for index1,pg1 in enumerate(self.pin_groups[pin_name]): + # Cannot combine more than once + if index1 in remove_indices: + continue for index2,pg2 in enumerate(self.pin_groups[pin_name]): - + # Cannot combine with yourself if index1==index2: continue + # Cannot combine more than once + if index2 in remove_indices: + continue if pg1.adjacent(pg2): combined = pin_group(pin_name, [], self) - combined.pins = [pg1.pins, pg2.pins] + combined.pins = [*pg1.pins, *pg2.pins] combined.grids = pg1.grids | pg2.grids - blocked_grids = combined.grids & self.blocked_grids - # Only add this if we can - if len(blocked_grids)==0: - debug.info(2,"Combing {0}:\n {1}\n {2}".format(pin_name, pg1.pins, pg2.pins)) - remove_indices.update([index1,index2]) - pin_groups.append(combined) + debug.info(2,"Combining {0}:\n {1}\n {2}".format(pin_name, pg1.pins, pg2.pins)) + debug.info(2," --> {0}\n {1}\n".format(combined.pins,combined.grids)) + remove_indices.update([index1,index2]) + pin_groups.append(combined) # Remove them in decreasing order to not invalidate the indices for i in sorted(remove_indices, reverse=True): From f19bcace62b1dd8ce2078ac81c9bdc49adce5765 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 11:18:12 -0700 Subject: [PATCH 16/30] Merged in an old stash. --- compiler/router/pin_group.py | 45 ++++++++++++++++-------- compiler/router/router.py | 59 ++++++++++++++++++++++++++++---- compiler/router/supply_router.py | 2 +- 3 files changed, 83 insertions(+), 23 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index f14abecb..124a8ebf 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -16,7 +16,11 @@ class pin_group: self.routed = False # This is a list because we can have a pin group of disconnected sets of pins # and these are represented by separate lists - self.pins = [pin_shapes] + if pin_shapes: + self.pins = [pin_shapes] + else: + self.pins = [] + self.router = router # These are the corresponding pin grids for each pin group. self.grids = set() @@ -53,28 +57,37 @@ class pin_group: """ Remove any pin layout that is contained within another. """ - local_debug = False + local_debug = True if local_debug: debug.info(0,"INITIAL: {}".format(pin_list)) # Make a copy of the list to start new_pin_list = pin_list.copy() - + + remove_indices = set() # This is n^2, but the number is small - for pin1 in pin_list: - for pin2 in pin_list: + for index1,pin1 in enumerate(pin_list): + if index1 in remove_indices: + continue + + for index2,pin2 in enumerate(pin_list): # Can't contain yourself if pin1 == pin2: continue + if index2 in remove_indices: + continue + if pin2.contains(pin1): if local_debug: debug.info(0,"{0} contains {1}".format(pin1,pin2)) - # It may have already been removed by being enclosed in another pin - if pin1 in new_pin_list: - new_pin_list.remove(pin1) + remove_indices.add(index2) + # Remove them in decreasing order to not invalidate the indices + for i in sorted(remove_indices, reverse=True): + del new_pin_list[i] if local_debug: debug.info(0,"FINAL : {}".format(new_pin_list)) + return new_pin_list # FIXME: This relies on some technology parameters from router which is not clean. @@ -106,6 +119,7 @@ class pin_group: ymax = max(plc.y,elc.y) ll = vector(plc.x, ymin) ur = vector(prc.x, ymax) + print(pin,enclosure,ll,ur) p = pin_layout(pin.name, [ll, ur], pin.layer) elif pin.yoverlaps(enclosure): # Is it horizontal overlap, extend pin shape to enclosure @@ -248,13 +262,13 @@ class pin_group: def enclose_pin(self): """ - This will find the biggest rectangle enclosing some grid squares and - put a rectangle over it. It does not enclose grid squares that are blocked - by other shapes. + If there is one set of connected pin shapes, + this will find the smallest rectangle enclosure that overlaps with any pin. + If there is not, it simply returns all the enclosures. """ # Compute the enclosure pin_layout list of the set of tracks enclosure_list = self.compute_enclosures() - + # A single set of connected pins is easy, so use the optimized set if len(self.pins)==1: smallest = self.find_smallest_overlapping(self.pins[0],enclosure_list) @@ -268,7 +282,7 @@ class pin_group: # debug.error("Unable to enclose pin {}".format(self.pins),-1) else: # Multiple pins is hard, so just use all of the enclosure shapes! - # FIXME: Find the minimum set of enclosures to reduce number of shapes. + # At least none of these are redundant shapes though. self.enclosures = enclosure_list debug.info(2,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, self.pins, self.grids, self.enclosures)) @@ -305,6 +319,7 @@ class pin_group: # Keep the same groups for each pin pin_set = set() blockage_set = set() + print("PINLIST:",self.pins) for pin_list in self.pins: for pin in pin_list: debug.info(2," Converting {0}".format(pin)) @@ -318,10 +333,10 @@ class pin_group: # If we have a blockage, we must remove the grids # Remember, this excludes the pin blockages already shared_set = pin_set & router.blocked_grids - if shared_set: + if len(shared_set)>0: debug.info(2,"Removing pins {}".format(shared_set)) shared_set = blockage_set & router.blocked_grids - if shared_set: + if len(shared_set)>0: debug.info(2,"Removing blocks {}".format(shared_set)) pin_set.difference_update(router.blocked_grids) blockage_set.difference_update(router.blocked_grids) diff --git a/compiler/router/router.py b/compiler/router/router.py index 0a0d2625..e819b882 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -155,19 +155,27 @@ class router(router_tech): for pin in pin_list: self.combine_adjacent_pins(pin) #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 + self.separate_adjacent_pins(pin) # Enclose the continguous grid units in a metal rectangle to fix some DRCs self.enclose_pins() - def combine_adjacent_pins(self, pin_name): + + def combine_adjacent_pins_pass(self, pin_name): """ - This checks for simple cases where a pin component already overlaps a supply rail. - It will add an enclosure to ensure the overlap in wide DRC rule cases. - """ - # Make a copy since we are going to reduce this list - pin_groups = self.pin_groups[pin_name].copy() + Find pins that have adjacent routing tracks and merge them into a + single pin_group. The pins themselves may not be touching, but + enclose_pis in the next step will ensure they are touching. + """ + # Make a copy since we are going to add to (and then reduce) this list + pin_groups = self.pin_groups[pin_name].copy() + + # Start as None to signal the first iteration remove_indices = set() + for index1,pg1 in enumerate(self.pin_groups[pin_name]): # Cannot combine more than once if index1 in remove_indices: @@ -180,6 +188,7 @@ class router(router_tech): if index2 in remove_indices: continue + # Combine if at least 1 grid cell is adjacent if pg1.adjacent(pg2): combined = pin_group(pin_name, [], self) combined.pins = [*pg1.pins, *pg2.pins] @@ -189,12 +198,48 @@ class router(router_tech): remove_indices.update([index1,index2]) pin_groups.append(combined) + # Remove them in decreasing order to not invalidate the indices + debug.info(2,"Removing {}".format(sorted(remove_indices))) for i in sorted(remove_indices, reverse=True): del pin_groups[i] - + + # Use the new pin group! self.pin_groups[pin_name] = pin_groups + removed_pairs = len(remove_indices)/2 + debug.info(1, "Combined {0} pin pairs for {1}".format(removed_pairs,pin_name)) + + return(removed_pairs) + + def combine_adjacent_pins(self, pin_name): + """ + Make multiple passes of the combine adjacent pins until we have no + more combinations or hit an iteration limit. + """ + + # Start as None to signal the first iteration + num_removed_pairs = None + + # Just used in case there's a circular combination or something weird + for iteration_count in range(10): + num_removed_pairs = self.combine_adjacent_pins_pass(pin_name) + if num_removed_pairs==0: + break + else: + debug.warning("Did not converge combining adjacent pins in supply router.") + + def separate_adjacent_pins(self, pin_name, separation=1): + """ + This will try to separate all grid pins by the supplied number of separation + tracks (default is to prevent adjacency). + Go through all of the pin groups and check if any other pin group is + within a separation of it. + If so, reduce the pin group grid to not include the adjacent grid. + Try to do this intelligently to keep th pins enclosed. + """ + pass + def prepare_blockages(self, pin_name): """ Reset and add all of the blockages in the design. diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 4f12e16a..093bd1de 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -71,7 +71,7 @@ class supply_router(router): # Get the pin shapes self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) - #self.write_debug_gds("pin_enclosures.gds",stop_program=True) + self.write_debug_gds("pin_enclosures.gds",stop_program=True) # Add the supply rails in a mesh network and connect H/V with vias # Block everything From cd87df8f7682a1fd7396e1f81487a269c52532b9 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 11:27:59 -0700 Subject: [PATCH 17/30] Clean up enclosure code --- compiler/router/pin_group.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 124a8ebf..57bb3419 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -267,25 +267,19 @@ class pin_group: If there is not, it simply returns all the enclosures. """ # Compute the enclosure pin_layout list of the set of tracks - enclosure_list = self.compute_enclosures() + self.enclosures = self.compute_enclosures() # A single set of connected pins is easy, so use the optimized set if len(self.pins)==1: + enclosure_list = self.enclosures smallest = self.find_smallest_overlapping(self.pins[0],enclosure_list) if smallest: self.enclosures=[smallest] - # else: - # connector=self.find_smallest_connector(enclosure_list) - # if connector: - # self.enclosures=[connector] - # else: - # debug.error("Unable to enclose pin {}".format(self.pins),-1) - else: - # Multiple pins is hard, so just use all of the enclosure shapes! - # At least none of these are redundant shapes though. - self.enclosures = enclosure_list - debug.info(2,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, self.pins, self.grids, self.enclosures)) + debug.info(2,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, + self.pins, + self.grids, + self.enclosures)) def add_enclosure(self, cell): From fa272be3bdfef4d68aab728fc93964f46290028b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 13:49:29 -0700 Subject: [PATCH 18/30] Enumerate more enclosures. --- compiler/router/direction.py | 23 +++++++++++++++++++++ compiler/router/grid_utils.py | 18 +++-------------- compiler/router/pin_group.py | 38 +++++++++++++++++++++++------------ compiler/router/router.py | 15 +++++++------- 4 files changed, 58 insertions(+), 36 deletions(-) diff --git a/compiler/router/direction.py b/compiler/router/direction.py index 95980618..c3de59a2 100644 --- a/compiler/router/direction.py +++ b/compiler/router/direction.py @@ -1,4 +1,5 @@ from enum import Enum +from vector3d import vector3d class direction(Enum): NORTH = 1 @@ -7,3 +8,25 @@ class direction(Enum): WEST = 4 UP = 5 DOWN = 6 + + + def get_offset(direct): + """ + Returns the vector offset for a given direction. + """ + if direct==direction.NORTH: + offset = vector3d(0,1,0) + elif direct==direction.SOUTH: + offset = vector3d(0,-1,0) + elif direct==direction.EAST: + offset = vector3d(1,0,0) + elif direct==direction.WEST: + offset = vector3d(-1,0,0) + elif direct==direction.UP: + offset = vector3d(0,0,1) + elif direct==direction.DOWN: + offset = vector3d(0,0,-1) + else: + debug.error("Invalid direction {}".format(dirct)) + + return offset diff --git a/compiler/router/grid_utils.py b/compiler/router/grid_utils.py index 62caebe9..748933b6 100644 --- a/compiler/router/grid_utils.py +++ b/compiler/router/grid_utils.py @@ -6,25 +6,13 @@ import debug from direction import direction from vector3d import vector3d + def increment_set(curset, direct): """ Return the cells incremented in given direction """ - if direct==direction.NORTH: - offset = vector3d(0,1,0) - elif direct==direction.SOUTH: - offset = vector3d(0,-1,0) - elif direct==direction.EAST: - offset = vector3d(1,0,0) - elif direct==direction.WEST: - offset = vector3d(-1,0,0) - elif direct==direction.UP: - offset = vector3d(0,0,1) - elif direct==direction.DOWN: - offset = vector3d(0,0,-1) - else: - debug.error("Invalid direction {}".format(dirct)) - + offset = direction.get_offset(direct) + newset = set() for c in curset: newc = c+offset diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 57bb3419..57191d63 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -1,3 +1,4 @@ +from direction import direction from pin_layout import pin_layout from vector3d import vector3d from vector import vector @@ -57,7 +58,7 @@ class pin_group: """ Remove any pin layout that is contained within another. """ - local_debug = True + local_debug = False if local_debug: debug.info(0,"INITIAL: {}".format(pin_list)) @@ -67,6 +68,7 @@ class pin_group: remove_indices = set() # This is n^2, but the number is small for index1,pin1 in enumerate(pin_list): + # If we remove this pin, it can't contain other pins if index1 in remove_indices: continue @@ -74,6 +76,7 @@ class pin_group: # Can't contain yourself if pin1 == pin2: continue + # If we already removed it, can't remove it again... if index2 in remove_indices: continue @@ -81,6 +84,7 @@ class pin_group: if local_debug: debug.info(0,"{0} contains {1}".format(pin1,pin2)) remove_indices.add(index2) + # Remove them in decreasing order to not invalidate the indices for i in sorted(remove_indices, reverse=True): del new_pin_list[i] @@ -98,15 +102,19 @@ class pin_group: # Enumerate every possible enclosure pin_list = [] for seed in self.grids: - (ll, ur) = self.enclose_pin_grids(seed) + (ll, ur) = self.enclose_pin_grids(seed, direction.NORTH, direction.EAST) + enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) + pin_list.append(enclosure) + + (ll, ur) = self.enclose_pin_grids(seed, direction.EAST, direction.NORTH) enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) pin_list.append(enclosure) return self.remove_redundant_shapes(pin_list) - def compute_enclosure(self, pin, enclosure): + def compute_connector(self, pin, enclosure): """ - Compute an enclosure to connect the pin to the enclosure shape. + Compute a shape to connect the pin to the enclosure shape. This assumes the shape will be the dimension of the pin. """ if pin.xoverlaps(enclosure): @@ -155,7 +163,7 @@ class pin_group: for pin_list in self.pins: for pin in pin_list: for enclosure in enclosure_list: - new_enclosure = self.compute_enclosure(pin, enclosure) + new_enclosure = self.compute_connector(pin, enclosure) if smallest == None or new_enclosure.area() {0}\n {1}\n".format(combined.pins,combined.grids)) remove_indices.update([index1,index2]) @@ -210,7 +210,7 @@ class router(router_tech): removed_pairs = len(remove_indices)/2 debug.info(1, "Combined {0} pin pairs for {1}".format(removed_pairs,pin_name)) - return(removed_pairs) + return removed_pairs def combine_adjacent_pins(self, pin_name): """ @@ -564,7 +564,8 @@ class router(router_tech): Analyze the shapes of a pin and combine them into groups which are connected. """ pin_set = self.pins[pin_name] - local_debug=False + local_debug = False + # Put each pin in an equivalence class of it's own equiv_classes = [set([x]) for x in pin_set] if local_debug: @@ -595,6 +596,8 @@ class router(router_tech): def combine_classes(equiv_classes): """ Recursive function to combine classes. """ + local_debug = False + if local_debug: debug.info(0,"\nRECURSE:\n",pformat(equiv_classes)) if len(equiv_classes)==1: @@ -634,10 +637,6 @@ class router(router_tech): put a rectangle over it. It does not enclose grid squares that are blocked by other shapes. """ - # These are used for debugging - self.connector_enclosure = [] - self.enclosures = [] - for pin_name in self.pin_groups.keys(): debug.info(1,"Enclosing pins for {}".format(pin_name)) for pg in self.pin_groups[pin_name]: From c4163d3401987b671a43b129351668a95fa7a107 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Oct 2018 13:50:56 -0700 Subject: [PATCH 19/30] Remove debug statements. --- compiler/router/pin_group.py | 1 - compiler/router/supply_router.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 57191d63..b742d035 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -127,7 +127,6 @@ class pin_group: ymax = max(plc.y,elc.y) ll = vector(plc.x, ymin) ur = vector(prc.x, ymax) - print(pin,enclosure,ll,ur) p = pin_layout(pin.name, [ll, ur], pin.layer) elif pin.yoverlaps(enclosure): # Is it horizontal overlap, extend pin shape to enclosure diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 093bd1de..4f12e16a 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -71,7 +71,7 @@ class supply_router(router): # Get the pin shapes self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) - self.write_debug_gds("pin_enclosures.gds",stop_program=True) + #self.write_debug_gds("pin_enclosures.gds",stop_program=True) # Add the supply rails in a mesh network and connect H/V with vias # Block everything From 1344a8f7f1a7140a17798859773594d568b59bd2 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Tue, 30 Oct 2018 12:24:13 -0700 Subject: [PATCH 20/30] Add remove adjacent feature for wide metal spacing --- compiler/router/direction.py | 7 ++ compiler/router/grid_path.py | 15 +--- compiler/router/pin_group.py | 140 +++++++++++++++++++++++-------- compiler/router/router.py | 87 ++++++++++++++++--- compiler/router/supply_router.py | 9 +- compiler/router/vector3d.py | 4 + 6 files changed, 197 insertions(+), 65 deletions(-) diff --git a/compiler/router/direction.py b/compiler/router/direction.py index c3de59a2..ab5873b4 100644 --- a/compiler/router/direction.py +++ b/compiler/router/direction.py @@ -30,3 +30,10 @@ class direction(Enum): debug.error("Invalid direction {}".format(dirct)) return offset + + def cardinal_directions(): + return [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST] + + def cardinal_offsets(): + return [direction.get_offset(d) for d in direction.cardinal_directions()] + diff --git a/compiler/router/grid_path.py b/compiler/router/grid_path.py index 437b6acb..250e485d 100644 --- a/compiler/router/grid_path.py +++ b/compiler/router/grid_path.py @@ -172,20 +172,7 @@ class grid_path: return neighbors def neighbor(self, d): - if d==direction.EAST: - offset = vector3d(1,0,0) - elif d==direction.WEST: - offset = vector3d(-1,0,0) - elif d==direction.NORTH: - offset = vector3d(0,1,0) - elif d==direction.SOUTH: - offset = vector3d(0,-1,0) - elif d==direction.UP: - offset = vector3d(0,0,1) - elif d==direction.DOWN: - offset = vector3d(0,0,-1) - else: - debug.error("Invalid direction {}".format(d),-1) + offset = direction.get_offset(d) newwave = [point + offset for point in self.pathlist[-1]] diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index b742d035..6b2e925f 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -15,6 +15,9 @@ class pin_group: self.name = name # Flag for when it is routed self.routed = False + # Flag for when it is enclosed + self.enclosed = False + # This is a list because we can have a pin group of disconnected sets of pins # and these are represented by separate lists if pin_shapes: @@ -25,10 +28,40 @@ class pin_group: self.router = router # These are the corresponding pin grids for each pin group. self.grids = set() + # These are the secondary grids that could or could not be part of the pin + self.secondary_grids = set() + # The corresponding set of partially blocked grids for each pin group. # These are blockages for other nets but unblocked for routing this group. self.blockages = set() + def __str__(self): + """ override print function output """ + total_string = "(pg {} ".format(self.name) + + pin_string = "\n pins={}".format(self.pins) + total_string += pin_string + + grids_string = "\n grids={}".format(self.grids) + total_string += grids_string + + grids_string = "\n secondary={}".format(self.secondary_grids) + total_string += grids_string + + if self.enclosed: + enlosure_string = "\n enclose={}".format(self.enclosures) + total_string += enclosure_string + + total_string += ")" + return total_string + + def __repr__(self): + """ override repr function output """ + return str(self) + + def size(self): + return len(self.grids) + def set_routed(self, value=True): self.routed = value @@ -277,22 +310,41 @@ class pin_group: this will find the smallest rectangle enclosure that overlaps with any pin. If there is not, it simply returns all the enclosures. """ + self.enclosed = True + # Compute the enclosure pin_layout list of the set of tracks self.enclosures = self.compute_enclosures() # A single set of connected pins is easy, so use the optimized set - if len(self.pins)==1: - enclosure_list = self.enclosures - smallest = self.find_smallest_overlapping(self.pins[0],enclosure_list) - if smallest: - self.enclosures=[smallest] - - debug.info(2,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, + # if len(self.pins)==1: + # enclosure_list = self.enclosures + # smallest = self.find_smallest_overlapping(self.pins[0],enclosure_list) + # if smallest: + # self.enclosures=[smallest] + + # Save the list of all grids + #self.all_grids = self.grids.copy() + + # Remove the grids that are not covered by the enclosures + # FIXME: We could probably just store what grids each enclosure overlaps when + # it was created. + #for enclosure in self.enclosures: + # enclosure_in_tracks=router.convert_pin_to_tracks(self.name, enclosure) + # self.grids.difference_update(enclosure_in_tracks) + + debug.info(3,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, self.pins, self.grids, self.enclosures)) - + def combine_pins(self, pg1, pg2): + """ + Combine two pin groups into one. + """ + self.pins = [*pg1.pins, *pg2.pins] # Join the two lists of pins + self.grids = pg1.grids | pg2.grids # OR the set of grid locations + self.secondary_grids = pg1.secondary_grids | pg2.secondary_grids + def add_enclosure(self, cell): """ Add the enclosure shape to the given cell. @@ -305,23 +357,57 @@ class pin_group: height=enclosure.height()) - + def perimeter_grids(self): + """ + Return a list of the grids on the perimeter. + This assumes that we have a single contiguous shape. + """ + perimeter_set = set() + cardinal_offsets = direction.cardinal_offsets() + for g1 in self.grids: + neighbor_grids = [g1 + offset for offset in cardinal_offsets] + neighbor_count = sum([x in self.grids for x in neighbor_grids]) + # If we aren't completely enclosed, we are on the perimeter + if neighbor_count < 4: + perimeter_set.add(g1) + + return perimeter_set def adjacent(self, other): """ Chck if the two pin groups have at least one adjacent pin grid. """ # We could optimize this to just check the boundaries - for g1 in self.grids: - for g2 in other.grids: + for g1 in self.perimeter_grids(): + for g2 in other.perimeter_grids(): if g1.adjacent(g2): return True return False + + def adjacent_grids(self, other, separation): + """ + Determine the sets of grids that are within a separation distance + of any grid in the other set. + """ + # We could optimize this to just check the boundaries + g1_grids = set() + g2_grids = set() + for g1 in self.grids: + for g2 in other.grids: + if g1.distance(g2) <= separation: + g1_grids.add(g1) + g2_grids.add(g2) + + return g1_grids,g2_grids + def convert_pin(self, router): - #print("PG ",pg) - # Keep the same groups for each pin + """ + Convert the list of pin shapes into sets of routing grids. + The secondary set of grids are "optional" pin shapes that could be + should be either blocked or part of the pin. + """ pin_set = set() blockage_set = set() @@ -334,19 +420,6 @@ class pin_group: # Blockages will be a super-set of pins since it uses the inflated pin shape. blockage_in_tracks = router.convert_blockage(pin) blockage_set.update(blockage_in_tracks) - - # If we have a blockage, we must remove the grids - # Remember, this excludes the pin blockages already - shared_set = pin_set & router.blocked_grids - if len(shared_set)>0: - debug.info(2,"Removing pins {}".format(shared_set)) - shared_set = blockage_set & router.blocked_grids - if len(shared_set)>0: - debug.info(2,"Removing blocks {}".format(shared_set)) - pin_set.difference_update(router.blocked_grids) - blockage_set.difference_update(router.blocked_grids) - debug.info(2," pins {}".format(pin_set)) - debug.info(2," blocks {}".format(blockage_set)) # At least one of the groups must have some valid tracks if (len(pin_set)==0 and len(blockage_set)==0): @@ -355,14 +428,9 @@ class pin_group: # We need to route each of the components, so don't combine the groups self.grids = pin_set | blockage_set + # Remember the secondary grids for removing adjacent pins in wide metal spacing + self.secondary_grids = blockage_set - pin_set - # Add all of the partial blocked grids to the set for the design - # if they are not blocked by other metal - #partial_set = blockage_set - pin_set - #self.blockages = partial_set - - # We should not have added the pins to the blockages, - # but remove them just in case - # Partial set may still be in the blockages if there were - # other shapes disconnected from the pins that were also overlapping - #route.blocked_grids.difference_update(pin_set) + debug.info(2," pins {}".format(self.grids)) + debug.info(2," secondary {}".format(self.secondary_grids)) + diff --git a/compiler/router/router.py b/compiler/router/router.py index 861da04c..ee6a9300 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -48,7 +48,6 @@ class router(router_tech): self.all_pins = set() # A map of pin names to a list of pin groups - # A pin group is a set overlapping pin shapes on the same layer. self.pin_groups = {} ### The blockage data structures @@ -157,10 +156,14 @@ class router(router_tech): #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 - self.separate_adjacent_pins(pin) - + # Must be done before enclosing pins + self.separate_adjacent_pins(self.supply_rail_space_width) + # For debug + #self.separate_adjacent_pins(1) + # Enclose the continguous grid units in a metal rectangle to fix some DRCs self.enclose_pins() + #self.write_debug_gds("debug_enclose_pins.gds",stop_program=True) def combine_adjacent_pins_pass(self, pin_name): @@ -191,13 +194,13 @@ class router(router_tech): # Combine if at least 1 grid cell is adjacent if pg1.adjacent(pg2): combined = pin_group(pin_name, [], self) - combined.pins = [*pg1.pins, *pg2.pins] # Join the two lists of pins - combined.grids = pg1.grids | pg2.grids # OR the set of grid locations - debug.info(2,"Combining {0}:\n {1}\n {2}".format(pin_name, pg1.pins, pg2.pins)) - debug.info(2," --> {0}\n {1}\n".format(combined.pins,combined.grids)) + combined.combine_pins(pg1, pg2) + debug.info(2,"Combining {0} {1} {2}:".format(pin_name, index1, index2)) + debug.info(2, " {0}\n {1}".format(pg1.pins, pg2.pins)) + debug.info(2," --> {0}\n {1}".format(combined.pins,combined.grids)) remove_indices.update([index1,index2]) pin_groups.append(combined) - + break # Remove them in decreasing order to not invalidate the indices debug.info(2,"Removing {}".format(sorted(remove_indices))) @@ -207,7 +210,7 @@ class router(router_tech): # Use the new pin group! self.pin_groups[pin_name] = pin_groups - removed_pairs = len(remove_indices)/2 + removed_pairs = int(len(remove_indices)/2) debug.info(1, "Combined {0} pin pairs for {1}".format(removed_pairs,pin_name)) return removed_pairs @@ -229,17 +232,77 @@ class router(router_tech): else: debug.warning("Did not converge combining adjacent pins in supply router.") - def separate_adjacent_pins(self, pin_name, separation=1): + def separate_adjacent_pins(self, separation): """ This will try to separate all grid pins by the supplied 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() + for pin_name1 in pin_names: + for pin_name2 in pin_names: + if pin_name1==pin_name2: + continue + self.separate_adjacent_pin(pin_name1, pin_name2, separation) + + def separate_adjacent_pin(self, pin_name1, pin_name2, separation): + """ Go through all of the pin groups and check if any other pin group is within a separation of it. If so, reduce the pin group grid to not include the adjacent grid. Try to do this intelligently to keep th pins enclosed. """ - pass + debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2)) + for index1,pg1 in enumerate(self.pin_groups[pin_name1]): + for index2,pg2 in enumerate(self.pin_groups[pin_name2]): + # FIXME: Use separation distance and edge grids only + grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation) + # These should have the same length, so... + if len(grids_g1)>0: + debug.info(1,"Adjacent grids {0} {1} {2} {3}".format(index1,grids_g1,index2,grids_g2)) + self.remove_adjacent_grid(pg1, grids_g1, pg2, grids_g2) + def remove_adjacent_grid(self, pg1, grids1, pg2, grids2): + """ + Remove one of the adjacent grids in a heuristic manner. + """ + # Determine the bigger and smaller group + if pg1.size()>pg2.size(): + bigger = pg1 + bigger_grids = grids1 + smaller = pg2 + smaller_grids = grids2 + else: + bigger = pg2 + bigger_grids = grids2 + smaller = pg1 + smaller_grids = grids1 + + # First, see if we can remove grids that are in the secondary grids + # i.e. they aren't necessary to the pin grids + if bigger_grids.issubset(bigger.secondary_grids): + debug.info(1,"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(1,"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. + debug.warning("Removing arbitrary grids from a pin group {} {}".format(bigger, bigger_grids)) + debug.check(len(bigger.grids)>len(bigger_grids),"Zero size pin group after adjacency removal {} {}".format(bigger, bigger_grids)) + bigger.grids.difference_update(bigger_grids) + self.blocked_grids.update(bigger_grids) + + + def prepare_blockages(self, pin_name): """ Reset and add all of the blockages in the design. @@ -975,6 +1038,8 @@ class router(router_tech): if show_enclosures: for key in self.pin_groups.keys(): for pg in self.pin_groups[key]: + if not pg.enclosed: + continue for pin in pg.enclosures: #print("enclosure: ",pin.name,pin.ll(),pin.width(),pin.height()) self.cell.add_rect(layer="text", diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 4f12e16a..6c40c788 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -41,6 +41,7 @@ class supply_router(router): # Power rail width in grid units. self.rail_track_width = 2 + def create_routing_grid(self): """ @@ -69,6 +70,9 @@ class supply_router(router): # but this is simplest for now. self.create_routing_grid() + # Compute the grid dimensions + self.compute_supply_rail_dimensions() + # Get the pin shapes self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) #self.write_debug_gds("pin_enclosures.gds",stop_program=True) @@ -87,7 +91,7 @@ class supply_router(router): self.route_simple_overlaps(vdd_name) self.route_simple_overlaps(gnd_name) - #self.write_debug_gds("debug_simple_route.gds",stop_program=True) + self.write_debug_gds("debug_simple_route.gds",stop_program=False) # Route the supply pins to the supply rails # Route vdd first since we want it to be shorter @@ -436,9 +440,6 @@ class supply_router(router): Must be done with lower left at 0,0 """ - # Compute the grid dimensions - self.compute_supply_rail_dimensions() - # Compute the grid locations of the supply rails self.compute_supply_rails(name, supply_number) diff --git a/compiler/router/vector3d.py b/compiler/router/vector3d.py index e7008036..a6e61078 100644 --- a/compiler/router/vector3d.py +++ b/compiler/router/vector3d.py @@ -163,6 +163,10 @@ class vector3d(): """ Min of both values """ return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z)) + def distance(self, other): + """ Return the planar distance between two values """ + return abs(self.x-other.x)+abs(self.y-other.y) + def adjacent(self, other): """ Is the one grid adjacent in any planar direction to the other """ From 7099ee76e9312892f559e6bc7b7c3922362185a6 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Tue, 30 Oct 2018 16:52:11 -0700 Subject: [PATCH 21/30] Remove blocked grids from pins and secondary grids --- compiler/router/pin_group.py | 19 ++++++++++++++++--- compiler/router/router.py | 3 ++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 6b2e925f..55e31ab4 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -106,8 +106,9 @@ class pin_group: continue for index2,pin2 in enumerate(pin_list): - # Can't contain yourself - if pin1 == pin2: + # Can't contain yourself, but compare the indices and not the pins + # so you can remove duplicate copies. + if index1==index2: continue # If we already removed it, can't remove it again... if index2 in remove_indices: @@ -420,7 +421,19 @@ class pin_group: # Blockages will be a super-set of pins since it uses the inflated pin shape. blockage_in_tracks = router.convert_blockage(pin) blockage_set.update(blockage_in_tracks) - + + # If we have a blockage, we must remove the grids + # Remember, this excludes the pin blockages already + shared_set = pin_set & router.blocked_grids + if len(shared_set)>0: + debug.info(2,"Removing pins {}".format(shared_set)) + pin_set.difference_update(router.blocked_grids) + + shared_set = blockage_set & router.blocked_grids + if len(shared_set)>0: + debug.info(2,"Removing blocks {}".format(shared_set)) + blockage_set.difference_update(router.blocked_grids) + # At least one of the groups must have some valid tracks if (len(pin_set)==0 and len(blockage_set)==0): self.write_debug_gds("blocked_pin.gds") diff --git a/compiler/router/router.py b/compiler/router/router.py index ee6a9300..dde66a82 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -135,7 +135,8 @@ class router(router_tech): Find the pins and blockages in the design """ # This finds the pin shapes and sorts them into "groups" that are connected - # This must come before the blockages, so we can ignore metal shapes that are blockages. + # This must come before the blockages, so we can not count the pins themselves + # as blockages. for pin in pin_list: self.find_pins(pin) From fc45242ccbc2e7d164914ec114623c13b8ba6f1b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Tue, 30 Oct 2018 17:41:29 -0700 Subject: [PATCH 22/30] Allow contains to contain copy. Add connectors when pin doesn't overlap grids. --- compiler/base/pin_layout.py | 6 +++++- compiler/router/pin_group.py | 36 ++++++++++++-------------------- compiler/router/router.py | 2 +- compiler/router/supply_router.py | 2 +- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 7a7ccd96..5199265b 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -120,10 +120,14 @@ class pin_layout: def contains(self, other): """ Check if a shape contains another rectangle """ + # If it is the same shape entirely, it is contained! + if self == other: + return True + # Can only overlap on the same layer if self.layer != other.layer: return False - + (ll,ur) = self.rect (oll,our) = other.rect diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 55e31ab4..9203ed11 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -187,18 +187,17 @@ class pin_group: return p - def find_smallest_connector(self, enclosure_list): + def find_smallest_connector(self, pin_list, shape_list): """ - Compute all of the connectors between non-overlapping pins and enclosures. + Compute all of the connectors between the overlapping pins and enclosure shape list.. Return the smallest. """ smallest = None - for pin_list in self.pins: - for pin in pin_list: - for enclosure in enclosure_list: - new_enclosure = self.compute_connector(pin, enclosure) - if smallest == None or new_enclosure.area() {0}\n {1}".format(combined.pins,combined.grids)) remove_indices.update([index1,index2]) pin_groups.append(combined) diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 6c40c788..84e59b04 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -91,7 +91,7 @@ class supply_router(router): self.route_simple_overlaps(vdd_name) self.route_simple_overlaps(gnd_name) - self.write_debug_gds("debug_simple_route.gds",stop_program=False) + #self.write_debug_gds("debug_simple_route.gds",stop_program=False) # Route the supply pins to the supply rails # Route vdd first since we want it to be shorter From c511d886bf0b224fba209f1879b740226092d3e9 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 31 Oct 2018 15:35:39 -0700 Subject: [PATCH 23/30] Added new enclosure connector algorithm using edge sorting. --- compiler/base/pin_layout.py | 34 ++++---- compiler/router/pin_group.py | 156 +++++++++++++++++++++++++++++++++-- compiler/router/router.py | 2 +- 3 files changed, 171 insertions(+), 21 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 5199265b..9dfbc443 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -118,6 +118,20 @@ class pin_layout: return y_overlaps + def xcontains(self, other): + """ Check if shape contains the x overlap """ + (ll,ur) = self.rect + (oll,our) = other.rect + + return (oll.x >= ll.x and our.x <= ur.x) + + def ycontains(self, other): + """ Check if shape contains the y overlap """ + (ll,ur) = self.rect + (oll,our) = other.rect + + return (oll.y >= ll.y and our.y <= ur.y) + def contains(self, other): """ Check if a shape contains another rectangle """ # If it is the same shape entirely, it is contained! @@ -127,23 +141,13 @@ class pin_layout: # Can only overlap on the same layer if self.layer != other.layer: return False - - (ll,ur) = self.rect - (oll,our) = other.rect - - # Check if the oll is inside the y range - if not (oll.y >= ll.y and oll.y <= ur.y): + + if not self.xcontains(other): return False - # Check if the oll is inside the x range - if not (oll.x >= ll.x and oll.x <= ur.x): + + if not self.ycontains(other): return False - # Check if the our is inside the y range - if not (our.y >= ll.y and our.y <= ur.y): - return False - # Check if the our is inside the x range - if not (our.x >= ll.x and our.x <= ur.x): - return False - + return True diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 9203ed11..61ebf410 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -114,10 +114,10 @@ class pin_group: if index2 in remove_indices: continue - if pin2.contains(pin1): + if pin1.contains(pin2): if local_debug: debug.info(0,"{0} contains {1}".format(pin1,pin2)) - remove_indices.add(index2) + remove_indices.add(index2) # Remove them in decreasing order to not invalidate the indices for i in sorted(remove_indices, reverse=True): @@ -144,7 +144,7 @@ class pin_group: enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) pin_list.append(enclosure) - return self.remove_redundant_shapes(pin_list) + return pin_list def compute_connector(self, pin, enclosure): """ @@ -187,6 +187,138 @@ class pin_group: return p + def find_above_connector(self, pin, enclosures): + """ + Find the enclosure that is to above the pin + and make a connector to it's upper edge. + """ + # Create the list of shapes that contain the pin edge + edge_list = [] + for shape in enclosures: + if shape.xcontains(pin): + edge_list.append(shape) + + # Sort them by their bottom edge + edge_list.sort(key=lambda x: x.by(), reverse=True) + + # Find the bottom edge that is next to the pin's top edge + above_item = None + for item in edge_list: + if item.by()>=pin.uy(): + above_item = item + else: + break + + # There was nothing + if above_item==None: + return None + # If it already overlaps, no connector needed + if above_item.overlaps(pin): + return None + + # Otherwise, make a connector to the item + p = self.compute_connector(pin, above_item) + return p + + def find_below_connector(self, pin, enclosures): + """ + Find the enclosure that is below the pin + and make a connector to it's upper edge. + """ + # Create the list of shapes that contain the pin edge + edge_list = [] + for shape in enclosures: + if shape.xcontains(pin): + edge_list.append(shape) + + # Sort them by their upper edge + edge_list.sort(key=lambda x: x.uy()) + + # Find the upper edge that is next to the pin's bottom edge + bottom_item = None + for item in edge_list: + if item.uy()<=pin.by(): + bottom_item = item + else: + break + + # There was nothing to the left + if bottom_item==None: + return None + # If it already overlaps, no connector needed + if bottom_item.overlaps(pin): + return None + + # Otherwise, make a connector to the item + p = self.compute_connector(pin, bottom_item) + return p + + def find_left_connector(self, pin, enclosures): + """ + Find the enclosure that is to the left of the pin + and make a connector to it's right edge. + """ + # Create the list of shapes that contain the pin edge + edge_list = [] + for shape in enclosures: + if shape.ycontains(pin): + edge_list.append(shape) + + # Sort them by their right edge + edge_list.sort(key=lambda x: x.rx()) + + # Find the right edge that is to the pin's left edge + left_item = None + for item in edge_list: + if item.rx()<=pin.lx(): + left_item = item + else: + break + + # There was nothing to the left + if left_item==None: + return None + # If it already overlaps, no connector needed + if left_item.overlaps(pin): + return None + + # Otherwise, make a connector to the item + p = self.compute_connector(pin, left_item) + return p + + def find_right_connector(self, pin, enclosures): + """ + Find the enclosure that is to the right of the pin + and make a connector to it's left edge. + """ + # Create the list of shapes that contain the pin edge + edge_list = [] + for shape in enclosures: + if shape.ycontains(pin): + edge_list.append(shape) + + # Sort them by their right edge + edge_list.sort(key=lambda x: x.lx(), reverse=True) + + # Find the left edge that is next to the pin's right edge + right_item = None + for item in edge_list: + if item.lx()>=pin.rx(): + right_item = item + else: + break + + # There was nothing to the right + if right_item==None: + return None + # If it already overlaps, no connector needed + if right_item.overlaps(pin): + return None + + # Otherwise, make a connector to the item + p = self.compute_connector(pin, right_item) + return p + def find_smallest_connector(self, pin_list, shape_list): """ Compute all of the connectors between the overlapping pins and enclosure shape list.. @@ -313,16 +445,30 @@ class pin_group: self.enclosed = True # Compute the enclosure pin_layout list of the set of tracks - self.enclosures = self.compute_enclosures() + redundant_enclosures = self.compute_enclosures() + + # Now simplify the enclosure list + self.enclosures = self.remove_redundant_shapes(redundant_enclosures) + + for pin_list in self.pins: + for pin in pin_list: + left_connector = self.find_left_connector(pin, self.enclosures) + right_connector = self.find_right_connector(pin, self.enclosures) + above_connector = self.find_above_connector(pin, self.enclosures) + below_connector = self.find_below_connector(pin, self.enclosures) + for connector in [left_connector, right_connector, above_connector, below_connector]: + if connector: + self.enclosures.append(connector) # Now, make sure each pin touches an enclosure. If not, add a connector. + # This could only happen when there was no enclosure in any cardinal direction from a pin for pin_list in self.pins: if not self.overlap_any_shape(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)) self.enclosures.append(connector) - + debug.info(3,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, self.pins, self.grids, diff --git a/compiler/router/router.py b/compiler/router/router.py index 5a879e69..e7340178 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -707,7 +707,7 @@ class router(router_tech): pg.enclose_pin() pg.add_enclosure(self.cell) - #self.write_debug_gds("pin_debug.gds", True) + #self.write_debug_gds("pin_debug.gds", False) def add_source(self, pin_name): """ From 2eedc703d1cc045eab2ffc0a92ffea68eb012339 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 31 Oct 2018 16:13:28 -0700 Subject: [PATCH 24/30] Rename function in pin_group --- compiler/router/pin_group.py | 2 +- compiler/router/router.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 61ebf410..39fe12c5 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -474,7 +474,7 @@ class pin_group: self.grids, self.enclosures)) - def combine_pins(self, pg1, pg2): + def combine_groups(self, pg1, pg2): """ Combine two pin groups into one. """ diff --git a/compiler/router/router.py b/compiler/router/router.py index e7340178..c9d1a2c0 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -195,9 +195,9 @@ class router(router_tech): # Combine if at least 1 grid cell is adjacent if pg1.adjacent(pg2): combined = pin_group(pin_name, [], self) - combined.combine_pins(pg1, pg2) + combined.combine_groups(pg1, pg2) debug.info(2,"Combining {0} {1} {2}:".format(pin_name, index1, index2)) - debug.info(2, "\n {0}\n {1}".format(pg1.pins, pg2.pins)) + debug.info(2, " {0}\n {1}".format(pg1.pins, pg2.pins)) debug.info(2," --> {0}\n {1}".format(combined.pins,combined.grids)) remove_indices.update([index1,index2]) pin_groups.append(combined) From b24c8a42a13c8e6eb8a9b5c495848ae703233673 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Thu, 1 Nov 2018 11:31:24 -0700 Subject: [PATCH 25/30] Remove redundant pins in pin_group constructor. Clean up some code and comments. --- compiler/base/pin_layout.py | 9 +++++++- compiler/router/pin_group.py | 35 ++++++++++++++++++++++---------- compiler/router/router.py | 11 +++++++--- compiler/router/supply_router.py | 2 +- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 9dfbc443..c5434246 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -149,7 +149,14 @@ class pin_layout: return False return True - + + def contained_by_any(self, shape_list): + """ Checks if shape is contained by any in the list """ + for shape in shape_list: + if shape.contains(self): + return True + return False + def overlaps(self, other): """ Check if a shape overlaps with a rectangle """ diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 39fe12c5..7897fdbf 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -10,21 +10,22 @@ class pin_group: A class to represent a group of rectangular design pin. It requires a router to define the track widths and blockages which determine how pin shapes get mapped to tracks. + It is initially constructed with a single set of (touching) pins. """ - def __init__(self, name, pin_shapes, router): + def __init__(self, name, pin_set, router): self.name = name # Flag for when it is routed self.routed = False # Flag for when it is enclosed self.enclosed = False + # Remove any redundant pins (i.e. contained in other pins) + irredundant_pin_set = self.remove_redundant_shapes(list(pin_set)) + # This is a list because we can have a pin group of disconnected sets of pins # and these are represented by separate lists - if pin_shapes: - self.pins = [pin_shapes] - else: - self.pins = [] - + self.pins = [set(irredundant_pin_set)] + self.router = router # These are the corresponding pin grids for each pin group. self.grids = set() @@ -35,6 +36,9 @@ class pin_group: # These are blockages for other nets but unblocked for routing this group. self.blockages = set() + # This is a set of pin_layout shapes to cover the grids + self.enclosures = set() + def __str__(self): """ override print function output """ total_string = "(pg {} ".format(self.name) @@ -90,6 +94,7 @@ class pin_group: def remove_redundant_shapes(self, pin_list): """ Remove any pin layout that is contained within another. + Returns a new list without modifying pin_list. """ local_debug = False if local_debug: @@ -144,7 +149,11 @@ class pin_group: enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) pin_list.append(enclosure) - return pin_list + + # Now simplify the enclosure list + new_pin_list = self.remove_redundant_shapes(pin_list) + + return new_pin_list def compute_connector(self, pin, enclosure): """ @@ -445,13 +454,15 @@ class pin_group: self.enclosed = True # Compute the enclosure pin_layout list of the set of tracks - redundant_enclosures = self.compute_enclosures() - - # Now simplify the enclosure list - self.enclosures = self.remove_redundant_shapes(redundant_enclosures) + self.enclosures = self.compute_enclosures() for pin_list in self.pins: for pin in pin_list: + + # If it is contained, it won't need a connector + if pin.contained_by_any(self.enclosures): + continue + left_connector = self.find_left_connector(pin, self.enclosures) right_connector = self.find_right_connector(pin, self.enclosures) above_connector = self.find_above_connector(pin, self.enclosures) @@ -553,9 +564,11 @@ class pin_group: debug.info(2," Converting {0}".format(pin)) # Determine which tracks the pin overlaps pin_in_tracks=router.convert_pin_to_tracks(self.name, pin) + pin_set.update(pin_in_tracks) # Blockages will be a super-set of pins since it uses the inflated pin shape. blockage_in_tracks = router.convert_blockage(pin) + blockage_set.update(blockage_in_tracks) # If we have a blockage, we must remove the grids diff --git a/compiler/router/router.py b/compiler/router/router.py index c9d1a2c0..f2cb6f22 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -98,11 +98,16 @@ class router(router_tech): pin_set = set() for shape in shape_list: (name,layer,boundary)=shape - rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] + # GDSMill boundaries are in (left, bottom, right, top) order + # so repack and snap to the grid + ll = vector(boundary[0],boundary[1]).snap_to_grid() + ur = vector(boundary[2],boundary[3]).snap_to_grid() + rect = [ll,ur] pin = pin_layout(pin_name, rect, layer) pin_set.add(pin) debug.check(len(pin_set)>0,"Did not find any pin shapes for {0}.".format(str(pin_name))) + self.pins[pin_name] = pin_set self.all_pins.update(pin_set) @@ -411,7 +416,7 @@ class router(router_tech): p.set_blocked(value) def get_blockage_tracks(self, ll, ur, z): - debug.info(4,"Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) + debug.info(3,"Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) block_list = [] for x in range(int(ll[0]),int(ur[0])+1): @@ -684,7 +689,7 @@ class router(router_tech): reduced_classes = combine_classes(equiv_classes) if local_debug: debug.info(0,"FINAL ",reduced_classes) - self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_shapes=x, router=self) for x in reduced_classes] + self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_set=x, router=self) for x in reduced_classes] def convert_pins(self, pin_name): """ diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 84e59b04..1e13fd12 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -169,7 +169,7 @@ class supply_router(router): if not new_set: new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST) - pg = pin_group(name=pin_name, pin_shapes=[], router=self) + pg = pin_group(name=pin_name, pin_set=[], router=self) pg.grids=new_set enclosure_list = pg.compute_enclosures() for pin in enclosure_list: From 4e09f0a944eff56b4875cd697a8a59548720a55b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 2 Nov 2018 10:58:00 -0700 Subject: [PATCH 26/30] Change layer text to comment to avoid glade reserved keyword --- technology/freepdk45/tf/FreePDK45.tf | 12 ++++++------ technology/freepdk45/tf/layers.map | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/technology/freepdk45/tf/FreePDK45.tf b/technology/freepdk45/tf/FreePDK45.tf index 0021e644..f0bfc606 100644 --- a/technology/freepdk45/tf/FreePDK45.tf +++ b/technology/freepdk45/tf/FreePDK45.tf @@ -172,9 +172,9 @@ layerDefinitions( ( align drawing ) ( hardFence drawing ) ( softFence drawing ) - ( text drawing ) - ( text drawing1 ) - ( text drawing2 ) + ( comment drawing ) + ( comment drawing1 ) + ( comment drawing2 ) ( border drawing ) ( device drawing ) ( device label ) @@ -379,9 +379,9 @@ layerDefinitions( ( align drawing align t t t t nil ) ( hardFence drawing hardFence t t t t nil ) ( softFence drawing softFence t t t t nil ) - ( text drawing text t t t t t ) - ( text drawing1 text1 t t t t nil ) - ( text drawing2 text2 t t t t nil ) + ( comment drawing comment t t t t t ) + ( comment drawing1 comment1 t t t t nil ) + ( comment drawing2 comment2 t t t t nil ) ( border drawing border t t t t nil ) ( device drawing device t t t t nil ) ( device label deviceLbl t t t t nil ) diff --git a/technology/freepdk45/tf/layers.map b/technology/freepdk45/tf/layers.map index 8c0c18d2..1bc4d413 100644 --- a/technology/freepdk45/tf/layers.map +++ b/technology/freepdk45/tf/layers.map @@ -27,4 +27,4 @@ via8 drawing 26 0 metal9 drawing 27 0 via9 drawing 28 0 metal10 drawing 29 0 -text drawing 239 0 +comment drawing 239 0 From 4d30f214dad49e121e84a37d942005c545f28793 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 2 Nov 2018 11:11:32 -0700 Subject: [PATCH 27/30] Add expanded blockages for paths an enclosures to handle wide metal spacing rules. --- compiler/router/direction.py | 27 +++++- compiler/router/grid_utils.py | 144 ++++++++++++++++++++----------- compiler/router/pin_group.py | 75 ++++++++++++++-- compiler/router/router.py | 38 ++++---- compiler/router/supply_router.py | 82 ++++-------------- 5 files changed, 219 insertions(+), 147 deletions(-) diff --git a/compiler/router/direction.py b/compiler/router/direction.py index ab5873b4..52d4207f 100644 --- a/compiler/router/direction.py +++ b/compiler/router/direction.py @@ -8,6 +8,10 @@ class direction(Enum): WEST = 4 UP = 5 DOWN = 6 + NORTHEAST = 7 + NORTHWEST = 8 + SOUTHEAST = 9 + SOUTHWEST = 10 def get_offset(direct): @@ -26,8 +30,16 @@ class direction(Enum): offset = vector3d(0,0,1) elif direct==direction.DOWN: offset = vector3d(0,0,-1) + elif direct==direction.NORTHEAST: + offset = vector3d(1,1,0) + elif direct==direction.NORTHWEST: + offset = vector3d(-1,1,0) + elif direct==direction.SOUTHEAST: + offset = vector3d(1,-1,0) + elif direct==direction.SOUTHWEST: + offset = vector3d(-1,-1,0) else: - debug.error("Invalid direction {}".format(dirct)) + debug.error("Invalid direction {}".format(direct)) return offset @@ -37,3 +49,16 @@ class direction(Enum): def cardinal_offsets(): return [direction.get_offset(d) for d in direction.cardinal_directions()] + def all_directions(): + return [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST, + direction.NORTHEAST, direction.NORTHWEST, direction.SOUTHEAST, direction.SOUTHWEST] + + def all_offsets(): + return [direction.get_offset(d) for d in direction.all_directions()] + + def all_neighbors(cell): + return [cell+x for x in direction.all_offsets()] + + def cardinal_neighbors(cell): + return [cell+x for x in direction.cardinal_offsets()] + diff --git a/compiler/router/grid_utils.py b/compiler/router/grid_utils.py index 748933b6..23fe23ea 100644 --- a/compiler/router/grid_utils.py +++ b/compiler/router/grid_utils.py @@ -8,17 +8,18 @@ from vector3d import vector3d def increment_set(curset, direct): - """ - Return the cells incremented in given direction - """ - offset = direction.get_offset(direct) + """ + Return the cells incremented in given direction + """ + offset = direction.get_offset(direct) + + newset = set() + for c in curset: + newc = c+offset + newset.add(newc) + + return newset - newset = set() - for c in curset: - newc = c+offset - newset.add(newc) - - return newset def remove_border(curset, direct): """ @@ -26,7 +27,7 @@ def remove_border(curset, direct): """ border = get_border(curset, direct) curset.difference_update(border) - + def get_upper_right(curset): ur = None @@ -43,48 +44,48 @@ def get_lower_left(curset): return ll def get_border( curset, direct): - """ - Return the furthest cell(s) in a given direction. - """ - - # find direction-most cell(s) - maxc = [] - if direct==direction.NORTH: - for c in curset: - if len(maxc)==0 or c.y>maxc[0].y: - maxc = [c] - elif c.y==maxc[0].y: - maxc.append(c) - elif direct==direct.SOUTH: - for c in curset: - if len(maxc)==0 or c.ymaxc[0].x: - maxc = [c] - elif c.x==maxc[0].x: - maxc.append(c) - elif direct==direct.WEST: - for c in curset: - if len(maxc)==0 or c.xmaxc[0].y: + maxc = [c] + elif c.y==maxc[0].y: + maxc.append(c) + elif direct==direct.SOUTH: + for c in curset: + if len(maxc)==0 or c.ymaxc[0].x: + maxc = [c] + elif c.x==maxc[0].x: + maxc.append(c) + elif direct==direct.WEST: + for c in curset: + if len(maxc)==0 or c.x0: debug.info(2,"Removing pins {}".format(shared_set)) - pin_set.difference_update(router.blocked_grids) + pin_set.difference_update(self.router.blocked_grids) - shared_set = blockage_set & router.blocked_grids + shared_set = blockage_set & self.router.blocked_grids if len(shared_set)>0: debug.info(2,"Removing blocks {}".format(shared_set)) - blockage_set.difference_update(router.blocked_grids) + blockage_set.difference_update(self.router.blocked_grids) # At least one of the groups must have some valid tracks if (len(pin_set)==0 and len(blockage_set)==0): @@ -596,3 +598,60 @@ class pin_group: debug.info(2," pins {}".format(self.grids)) debug.info(2," secondary {}".format(self.secondary_grids)) + def recurse_simple_overlap_enclosure(self, start_set, direct): + """ + Recursive function to return set of tracks that connects to + the actual supply rail wire in a given direction (or terminating + when any track is no longer in the supply rail. + """ + next_set = grid_utils.expand_border(start_set, direct) + + supply_tracks = self.router.supply_rail_tracks[self.name] + supply_wire_tracks = self.router.supply_rail_wire_tracks[self.name] + + supply_overlap = next_set & supply_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 len(wire_overlap)==len(start_set): + 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 + elif len(supply_overlap)==len(start_set): + recurse_set = self.recurse_simple_overlap_enclosure(supply_overlap, direct) + new_set = start_set | supply_overlap | recurse_set + else: + # If we got no next set, we are done, can't expand! + new_set = set() + + return new_set + + def create_simple_overlap_enclosure(self, start_set): + """ + This takes a set of tracks that overlap a supply rail and creates an enclosure + that is ensured to overlap the supply rail wire. + It then adds rectangle(s) for the enclosure. + """ + + additional_set = set() + # Check the layer of any element in the pin to determine which direction to route it + e = next(iter(start_set)) + new_set = start_set.copy() + if e.z==0: + new_set = self.recurse_simple_overlap_enclosure(start_set, direction.NORTH) + if not new_set: + new_set = self.recurse_simple_overlap_enclosure(start_set, direction.SOUTH) + else: + new_set = self.recurse_simple_overlap_enclosure(start_set, direction.EAST) + if not new_set: + 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 + self.grids.update(new_set) + + # Add the inflated set so we don't get wide metal spacing issues (if it exists) + self.blockages.update(grid_utils.inflate_set(new_set,self.router.supply_rail_space_width)) + + # Add the polygon enclosures and set this pin group as routed + self.set_routed() + self.enclosures = self.compute_enclosures() + diff --git a/compiler/router/router.py b/compiler/router/router.py index f2cb6f22..2432e8c2 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -59,6 +59,8 @@ class router(router_tech): ### The routed data structures # A list of paths that have been "routed" self.paths = [] + # A list of path blockages (they might be expanded for wide metal DRC) + self.path_blockages = [] # The boundary will determine the limits to the size of the routing grid self.boundary = self.layout.measureBoundary(self.top_name) @@ -326,10 +328,16 @@ class router(router_tech): self.set_supply_rail_blocked(True) # Block all of the pin components (some will be unblocked if they're a source/target) + # Also block the previous routes for name in self.pin_groups.keys(): blockage_grids = {y for x in self.pin_groups[name] for y in x.grids} self.set_blockages(blockage_grids,True) + blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages} + self.set_blockages(blockage_grids,True) + # FIXME: These duplicate a bit of work + # These are the paths that have already been routed. + self.set_path_blockages() # 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 @@ -337,8 +345,6 @@ class router(router_tech): blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids} self.set_blockages(blockage_grids,False) - # These are the paths that have already been routed. - self.set_path_blockages() # def translate_coordinates(self, coord, mirr, angle, xyShift): # """ @@ -387,16 +393,6 @@ class router(router_tech): # z direction return 2 - - def add_path_blockages(self): - """ - Go through all of the past paths and add them as blockages. - This is so we don't have to write/reload the GDS. - """ - for path in self.paths: - for grid in path: - self.rg.set_blocked(grid) - def clear_blockages(self): """ Clear all blockages on the grid. @@ -411,9 +407,9 @@ class router(router_tech): def set_path_blockages(self,value=True): """ Flag the paths as blockages """ # These are the paths that have already been routed. - # This adds the initial blockges of the design - for p in self.paths: - p.set_blocked(value) + for path_set in self.path_blockages: + for c in path_set: + self.rg.set_blocked(c,value) def get_blockage_tracks(self, ll, ur, z): debug.info(3,"Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) @@ -696,7 +692,7 @@ class router(router_tech): Convert the pin groups into pin tracks and blockage tracks. """ for pg in self.pin_groups[pin_name]: - pg.convert_pin(self) + pg.convert_pin() @@ -918,13 +914,6 @@ class router(router_tech): return newpath - def add_path_blockages(self): - """ - Go through all of the past paths and add them as blockages. - This is so we don't have to write/reload the GDS. - """ - for path in self.paths: - self.rg.block_path(path) def run_router(self, detour_scale): """ @@ -936,6 +925,9 @@ class router(router_tech): debug.info(2,"Found path: cost={0} ".format(cost)) debug.info(3,str(path)) self.paths.append(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(inflated_path) self.add_route(path) else: self.write_debug_gds("failed_route.gds") diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 1e13fd12..1a7a77cf 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -99,7 +99,7 @@ class supply_router(router): self.route_pins_to_rails(gnd_name) #self.write_debug_gds("debug_pin_routes.gds",stop_program=True) - #self.write_debug_gds("final.gds") + #self.write_debug_gds("final.gds",False) return True @@ -110,77 +110,31 @@ class supply_router(router): This checks for simple cases where a pin component already overlaps a supply rail. It will add an enclosure to ensure the overlap in wide DRC rule cases. """ + debug.info(1,"Routing simple overlap pins for {0}".format(pin_name)) + + # These are the wire tracks + wire_tracks = self.supply_rail_wire_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]: if pg.is_routed(): continue - common_set = supply_tracks & pg.grids - - if len(common_set)>0: - self.create_simple_overlap_enclosure(pin_name, common_set) + # First, check if we just overlap, if so, we are done. + overlap_grids = wire_tracks & pg.grids + if len(overlap_grids)>0: pg.set_routed() + 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) - def recurse_simple_overlap_enclosure(self, pin_name, start_set, direct): - """ - Recursive function to return set of tracks that connects to - the actual supply rail wire in a given direction (or terminating - when any track is no longer in the supply rail. - """ - next_set = grid_utils.expand_border(start_set, direct) - - supply_tracks = self.supply_rail_tracks[pin_name] - supply_wire_tracks = self.supply_rail_wire_tracks[pin_name] - - supply_overlap = next_set & supply_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 len(wire_overlap)==len(start_set): - 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 - elif len(supply_overlap)==len(start_set): - recurse_set = self.recurse_simple_overlap_enclosure(pin_name, supply_overlap, direct) - new_set = start_set | supply_overlap | recurse_set - else: - # If we got no next set, we are done, can't expand! - new_set = set() - - return new_set - - def create_simple_overlap_enclosure(self, pin_name, start_set): - """ - This takes a set of tracks that overlap a supply rail and creates an enclosure - that is ensured to overlap the supply rail wire. - It then adds rectangle(s) for the enclosure. - """ - additional_set = set() - # Check the layer of any element in the pin to determine which direction to route it - e = next(iter(start_set)) - new_set = start_set.copy() - if e.z==0: - new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.NORTH) - if not new_set: - new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.SOUTH) - else: - new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.EAST) - if not new_set: - new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST) - - pg = pin_group(name=pin_name, pin_set=[], router=self) - pg.grids=new_set - enclosure_list = pg.compute_enclosures() - for pin in enclosure_list: - debug.info(2,"Adding simple overlap enclosure {0} {1}".format(pin_name, pin)) - self.cell.add_rect(layer=pin.layer, - offset=pin.ll(), - width=pin.width(), - height=pin.height()) - - - def finalize_supply_rails(self, name): """ @@ -478,6 +432,7 @@ class supply_router(router): for index,pg in enumerate(self.pin_groups[pin_name]): if pg.is_routed(): continue + debug.info(2,"Routing component {0} {1}".format(pin_name, index)) # Clear everything in the routing grid. @@ -498,7 +453,6 @@ class supply_router(router): # Actually run the A* router if not self.run_router(detour_scale=5): self.write_debug_gds() - def add_supply_rail_target(self, pin_name): From 866eaa8b022c5583f05b89e0fe0ee5b2e053e37b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 2 Nov 2018 11:50:28 -0700 Subject: [PATCH 28/30] Add debug message when routes are diagonal. --- compiler/base/route.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/base/route.py b/compiler/base/route.py index 0397e383..0b596a1a 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -69,7 +69,7 @@ class route(design): via_size = [self.num_vias]*2 self.obj.add_via(self.layer_stack,via_offset,size=via_size,rotate=90) elif p0.x != p1.x and p0.y != p1.y: # diagonal! - debug.error("Non-changing direction!") + debug.error("Non-changing direction! {}".format(self.path)) else: # this will draw an extra corner at the end but that is ok self.draw_corner_wire(p1) From 74c3de2812587526f21629f903bed377499ec8bd Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 2 Nov 2018 14:57:40 -0700 Subject: [PATCH 29/30] Remove diagonal routing bug. Cleanup. --- compiler/base/route.py | 8 ++----- compiler/router/direction.py | 11 +++++---- compiler/router/grid_cell.py | 9 ++++---- compiler/router/grid_path.py | 6 ++--- compiler/router/router.py | 45 +++++++++++++++++++++--------------- 5 files changed, 43 insertions(+), 36 deletions(-) diff --git a/compiler/base/route.py b/compiler/base/route.py index 0b596a1a..09925e07 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -62,14 +62,10 @@ class route(design): plist = list(pairwise(self.path)) for p0,p1 in plist: if p0.z != p1.z: # via - # offset if not rotated - #via_offset = vector(p0.x+0.5*self.c.width,p0.y+0.5*self.c.height) - # offset if rotated - via_offset = vector(p0.x+0.5*self.c.height,p0.y-0.5*self.c.width) via_size = [self.num_vias]*2 - self.obj.add_via(self.layer_stack,via_offset,size=via_size,rotate=90) + self.obj.add_via_center(self.layer_stack,vector(p0.x,p0.y),size=via_size,rotate=90) elif p0.x != p1.x and p0.y != p1.y: # diagonal! - debug.error("Non-changing direction! {}".format(self.path)) + debug.error("Diagonal route! {}".format(self.path),-3) else: # this will draw an extra corner at the end but that is ok self.draw_corner_wire(p1) diff --git a/compiler/router/direction.py b/compiler/router/direction.py index 52d4207f..8a6681a7 100644 --- a/compiler/router/direction.py +++ b/compiler/router/direction.py @@ -43,11 +43,14 @@ class direction(Enum): return offset - def cardinal_directions(): - return [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST] + def cardinal_directions(up_down_too=False): + temp_dirs = [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST] + if up_down_too: + temp_dirs.extend([direction.UP, direction.DOWN]) + return temp_dirs - def cardinal_offsets(): - return [direction.get_offset(d) for d in direction.cardinal_directions()] + def cardinal_offsets(up_down_too=False): + return [direction.get_offset(d) for d in direction.cardinal_directions(up_down_too)] def all_directions(): return [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST, diff --git a/compiler/router/grid_cell.py b/compiler/router/grid_cell.py index 3f145ef4..cb78116c 100644 --- a/compiler/router/grid_cell.py +++ b/compiler/router/grid_cell.py @@ -22,6 +22,11 @@ class grid_cell: self.source=False self.target=False + def get_cost(self): + # We can display the cost of the frontier + if self.min_cost > 0: + return self.min_cost + def get_type(self): if self.blocked: @@ -36,8 +41,4 @@ class grid_cell: if self.path: return "P" - # We can display the cost of the frontier - if self.min_cost > 0: - return self.min_cost - return None diff --git a/compiler/router/grid_path.py b/compiler/router/grid_path.py index 250e485d..cbe739ef 100644 --- a/compiler/router/grid_path.py +++ b/compiler/router/grid_path.py @@ -150,7 +150,7 @@ class grid_path: return cost - def expand_dirs(self,up_down_too=True): + def expand_dirs(self): """ Expand from the end in each of the four cardinal directions plus up or down but not expanding to blocked cells. Expands in all @@ -162,9 +162,7 @@ class grid_path: """ neighbors = [] - for d in list(direction): - if not up_down_too and (d==direction.UP or d==direction.DOWN): - continue + for d in direction.cardinal_directions(True): n = self.neighbor(d) if n: neighbors.append(n) diff --git a/compiler/router/router.py b/compiler/router/router.py index 2432e8c2..b9aa2518 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -337,7 +337,7 @@ class router(router_tech): # FIXME: These duplicate a bit of work # These are the paths that have already been routed. - self.set_path_blockages() + self.set_blockages(self.path_blockages) # 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 @@ -404,13 +404,6 @@ class router(router_tech): """ Flag the blockages in the grid """ self.rg.set_blocked(blockages, value) - def set_path_blockages(self,value=True): - """ Flag the paths as blockages """ - # These are the paths that have already been routed. - for path_set in self.path_blockages: - for c in path_set: - self.rg.set_blocked(c,value) - def get_blockage_tracks(self, ll, ur, z): debug.info(3,"Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) @@ -924,11 +917,13 @@ class router(router_tech): if path: debug.info(2,"Found path: cost={0} ".format(cost)) debug.info(3,str(path)) + self.paths.append(path) + self.add_route(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(inflated_path) - self.add_route(path) else: self.write_debug_gds("failed_route.gds") # clean up so we can try a reroute @@ -985,16 +980,30 @@ class router(router_tech): # midpoint offset off=vector((shape[1].x+shape[0].x)/2, (shape[1].y+shape[0].y)/2) - if g[2]==1: - # Upper layer is upper right label - type_off=off+partial_track - else: - # Lower layer is lower left label - type_off=off-partial_track if t!=None: + if g[2]==1: + # Upper layer is upper right label + type_off=off+partial_track + else: + # Lower layer is lower left label + type_off=off-partial_track self.cell.add_label(text=str(t), layer="text", offset=type_off) + + t=self.rg.map[g].get_cost() + partial_track=vector(self.track_width/6.0,0) + if t!=None: + if g[2]==1: + # Upper layer is right label + type_off=off+partial_track + else: + # Lower layer is left label + type_off=off-partial_track + self.cell.add_label(text=str(t), + layer="text", + offset=type_off) + self.cell.add_label(text="{0},{1}".format(g[0],g[1]), layer="text", offset=shape[0], @@ -1008,9 +1017,9 @@ class router(router_tech): """ debug.info(0,"Adding router info") - show_blockages = True - show_blockage_grids = True - show_enclosures = True + show_blockages = False + show_blockage_grids = False + show_enclosures = False show_all_grids = True if show_all_grids: From 6dd959b638677487a234c87eb07630acde37f553 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 2 Nov 2018 16:34:26 -0700 Subject: [PATCH 30/30] Fix error in 8mux test. Fix comment in all tests. --- compiler/tests/00_code_format_check_test.py | 2 +- compiler/tests/01_library_drc_test.py | 2 +- compiler/tests/02_library_lvs_test.py | 2 +- compiler/tests/03_contact_test.py | 2 +- compiler/tests/03_path_test.py | 2 +- compiler/tests/03_ptx_1finger_nmos_test.py | 2 +- compiler/tests/03_ptx_1finger_pmos_test.py | 2 +- compiler/tests/03_ptx_3finger_nmos_test.py | 2 +- compiler/tests/03_ptx_3finger_pmos_test.py | 2 +- compiler/tests/03_ptx_4finger_nmos_test.py | 2 +- compiler/tests/03_ptx_4finger_pmos_test.py | 2 +- compiler/tests/03_wire_test.py | 2 +- compiler/tests/04_pbitcell_test.py | 2 +- compiler/tests/04_pinv_10x_test.py | 2 +- compiler/tests/04_pinv_1x_beta_test.py | 2 +- compiler/tests/04_pinv_1x_test.py | 2 +- compiler/tests/04_pinv_2x_test.py | 2 +- compiler/tests/04_pinvbuf_test.py | 2 +- compiler/tests/04_pnand2_test.py | 2 +- compiler/tests/04_pnand3_test.py | 2 +- compiler/tests/04_pnor2_test.py | 2 +- compiler/tests/04_precharge_test.py | 2 +- compiler/tests/04_replica_pbitcell_test.py | 2 +- compiler/tests/04_single_level_column_mux_test.py | 2 +- compiler/tests/05_bitcell_1rw_1r_array_test.py | 2 +- compiler/tests/05_bitcell_array_test.py | 2 +- compiler/tests/05_pbitcell_array_test.py | 2 +- compiler/tests/06_hierarchical_decoder_test.py | 2 +- compiler/tests/06_hierarchical_predecode2x4_test.py | 2 +- compiler/tests/06_hierarchical_predecode3x8_test.py | 2 +- compiler/tests/07_single_level_column_mux_array_test.py | 2 +- compiler/tests/08_precharge_array_test.py | 2 +- compiler/tests/08_wordline_driver_test.py | 2 +- compiler/tests/09_sense_amp_array_test.py | 2 +- compiler/tests/10_write_driver_array_test.py | 2 +- compiler/tests/11_dff_array_test.py | 2 +- compiler/tests/11_dff_buf_array_test.py | 2 +- compiler/tests/11_dff_buf_test.py | 2 +- compiler/tests/11_dff_inv_array_test.py | 2 +- compiler/tests/11_dff_inv_test.py | 2 +- compiler/tests/12_tri_gate_array_test.py | 2 +- compiler/tests/13_delay_chain_test.py | 2 +- compiler/tests/14_replica_bitline_test.py | 2 +- compiler/tests/16_control_logic_test.py | 2 +- compiler/tests/19_bank_select_test.py | 2 +- compiler/tests/19_multi_bank_test.py | 2 +- compiler/tests/19_pmulti_bank_test.py | 2 +- compiler/tests/19_psingle_bank_test.py | 2 +- compiler/tests/19_single_bank_test.py | 2 +- compiler/tests/20_psram_1bank_nomux_test.py | 2 +- compiler/tests/20_sram_1bank_2mux_test.py | 2 +- compiler/tests/20_sram_1bank_4mux_test.py | 2 +- compiler/tests/20_sram_1bank_8mux_test.py | 2 +- compiler/tests/20_sram_1bank_nomux_test.py | 2 +- compiler/tests/20_sram_2bank_test.py | 2 +- compiler/tests/20_sram_4bank_test.py | 2 +- compiler/tests/21_hspice_delay_test.py | 2 +- compiler/tests/21_hspice_setuphold_test.py | 2 +- compiler/tests/21_ngspice_delay_test.py | 2 +- compiler/tests/21_ngspice_setuphold_test.py | 2 +- compiler/tests/22_psram_1bank_2mux_func_test.py | 2 +- compiler/tests/22_psram_1bank_4mux_func_test.py | 4 ++-- compiler/tests/22_psram_1bank_8mux_func_test.py | 3 ++- compiler/tests/22_psram_1bank_nomux_func_test.py | 2 +- compiler/tests/22_sram_1bank_2mux_func_test.py | 2 +- compiler/tests/22_sram_1bank_4mux_func_test.py | 2 +- compiler/tests/22_sram_1bank_8mux_func_test.py | 3 ++- compiler/tests/22_sram_1bank_nomux_func_test.py | 2 +- compiler/tests/23_lib_sram_model_test.py | 2 +- compiler/tests/23_lib_sram_prune_test.py | 2 +- compiler/tests/23_lib_sram_test.py | 2 +- compiler/tests/24_lef_sram_test.py | 2 +- compiler/tests/25_verilog_sram_test.py | 2 +- compiler/tests/26_pex_test.py | 2 +- compiler/tests/27_worst_case_delay_test.py | 2 +- compiler/tests/30_openram_test.py | 2 +- 76 files changed, 79 insertions(+), 77 deletions(-) diff --git a/compiler/tests/00_code_format_check_test.py b/compiler/tests/00_code_format_check_test.py index 026f7e2b..869e81bd 100755 --- a/compiler/tests/00_code_format_check_test.py +++ b/compiler/tests/00_code_format_check_test.py @@ -116,7 +116,7 @@ def check_print_output(file_name): return(count) -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/01_library_drc_test.py b/compiler/tests/01_library_drc_test.py index b809c14d..046e6378 100755 --- a/compiler/tests/01_library_drc_test.py +++ b/compiler/tests/01_library_drc_test.py @@ -39,7 +39,7 @@ def setup_files(): return (gds_dir, gds_files) -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/02_library_lvs_test.py index 0b35f159..0367c5f2 100755 --- a/compiler/tests/02_library_lvs_test.py +++ b/compiler/tests/02_library_lvs_test.py @@ -59,7 +59,7 @@ def setup_files(): return (gds_dir, sp_dir, allnames) -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_contact_test.py b/compiler/tests/03_contact_test.py index 2fab1c4e..33aa45ae 100755 --- a/compiler/tests/03_contact_test.py +++ b/compiler/tests/03_contact_test.py @@ -43,7 +43,7 @@ class contact_test(openram_test): -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index f70d00be..915c5c78 100755 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -84,7 +84,7 @@ class path_test(openram_test): -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_ptx_1finger_nmos_test.py b/compiler/tests/03_ptx_1finger_nmos_test.py index 727c24f0..9a81810e 100755 --- a/compiler/tests/03_ptx_1finger_nmos_test.py +++ b/compiler/tests/03_ptx_1finger_nmos_test.py @@ -25,7 +25,7 @@ class ptx_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_ptx_1finger_pmos_test.py b/compiler/tests/03_ptx_1finger_pmos_test.py index 04b9ab64..a3ed99ff 100755 --- a/compiler/tests/03_ptx_1finger_pmos_test.py +++ b/compiler/tests/03_ptx_1finger_pmos_test.py @@ -25,7 +25,7 @@ class ptx_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py index 20343b2e..e1febdbc 100755 --- a/compiler/tests/03_ptx_3finger_nmos_test.py +++ b/compiler/tests/03_ptx_3finger_nmos_test.py @@ -27,7 +27,7 @@ class ptx_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py index 37933702..af9a5d42 100755 --- a/compiler/tests/03_ptx_3finger_pmos_test.py +++ b/compiler/tests/03_ptx_3finger_pmos_test.py @@ -27,7 +27,7 @@ class ptx_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_ptx_4finger_nmos_test.py b/compiler/tests/03_ptx_4finger_nmos_test.py index 09788a5e..08a20898 100755 --- a/compiler/tests/03_ptx_4finger_nmos_test.py +++ b/compiler/tests/03_ptx_4finger_nmos_test.py @@ -27,7 +27,7 @@ class ptx_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_ptx_4finger_pmos_test.py b/compiler/tests/03_ptx_4finger_pmos_test.py index f43d7dc7..01857eda 100755 --- a/compiler/tests/03_ptx_4finger_pmos_test.py +++ b/compiler/tests/03_ptx_4finger_pmos_test.py @@ -27,7 +27,7 @@ class ptx_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/03_wire_test.py b/compiler/tests/03_wire_test.py index 557fee5b..1b18e14b 100755 --- a/compiler/tests/03_wire_test.py +++ b/compiler/tests/03_wire_test.py @@ -121,7 +121,7 @@ class wire_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index 0b6bd8f5..e5dbbc5e 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -94,7 +94,7 @@ class pbitcell_test(openram_test): -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py index 3a7f846a..d457d2a9 100755 --- a/compiler/tests/04_pinv_10x_test.py +++ b/compiler/tests/04_pinv_10x_test.py @@ -25,7 +25,7 @@ class pinv_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py index c1bb6aba..77ff5454 100755 --- a/compiler/tests/04_pinv_1x_beta_test.py +++ b/compiler/tests/04_pinv_1x_beta_test.py @@ -24,7 +24,7 @@ class pinv_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py index 555aa0e5..49cb1cb1 100755 --- a/compiler/tests/04_pinv_1x_test.py +++ b/compiler/tests/04_pinv_1x_test.py @@ -23,7 +23,7 @@ class pinv_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py index 6882a719..84bc55ee 100755 --- a/compiler/tests/04_pinv_2x_test.py +++ b/compiler/tests/04_pinv_2x_test.py @@ -25,7 +25,7 @@ class pinv_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py index 9c55ebe3..d35f1ec7 100755 --- a/compiler/tests/04_pinvbuf_test.py +++ b/compiler/tests/04_pinvbuf_test.py @@ -23,7 +23,7 @@ class pinvbuf_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index b6739e4e..a2ac9288 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -27,7 +27,7 @@ class pnand2_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index db3817f5..f6daedda 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -27,7 +27,7 @@ class pnand3_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index 978c03ad..ce4b19ae 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -26,7 +26,7 @@ class pnor2_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 02de2efd..e5419dab 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -39,7 +39,7 @@ class precharge_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py index 7a803d1c..ce9f00b9 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_test.py @@ -37,7 +37,7 @@ class replica_pbitcell_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index 3a7d6399..c43b15fd 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -41,7 +41,7 @@ class single_level_column_mux_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/05_bitcell_1rw_1r_array_test.py b/compiler/tests/05_bitcell_1rw_1r_array_test.py index 68dcc409..1223085e 100755 --- a/compiler/tests/05_bitcell_1rw_1r_array_test.py +++ b/compiler/tests/05_bitcell_1rw_1r_array_test.py @@ -29,7 +29,7 @@ class bitcell_1rw_1r_array_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/05_bitcell_array_test.py b/compiler/tests/05_bitcell_array_test.py index 4ea5c65a..93668e05 100755 --- a/compiler/tests/05_bitcell_array_test.py +++ b/compiler/tests/05_bitcell_array_test.py @@ -25,7 +25,7 @@ class array_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/05_pbitcell_array_test.py b/compiler/tests/05_pbitcell_array_test.py index 4fc75ac5..4da5bec9 100755 --- a/compiler/tests/05_pbitcell_array_test.py +++ b/compiler/tests/05_pbitcell_array_test.py @@ -44,7 +44,7 @@ class pbitcell_array_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index 513e07a8..09201149 100755 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -69,7 +69,7 @@ class hierarchical_decoder_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index bcfd207a..e16916d6 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -35,7 +35,7 @@ class hierarchical_predecode2x4_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index b89f4bea..ed5da57c 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -35,7 +35,7 @@ class hierarchical_predecode3x8_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index 63f69bc5..800292b6 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -54,7 +54,7 @@ class single_level_column_mux_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index be8fc9d7..5ea9931b 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -39,7 +39,7 @@ class precharge_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index 7f0ca275..369b6774 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -37,7 +37,7 @@ class wordline_driver_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index af2c974c..a18631f9 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -42,7 +42,7 @@ class sense_amp_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index ab9dc615..fa374181 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -42,7 +42,7 @@ class write_driver_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/11_dff_array_test.py b/compiler/tests/11_dff_array_test.py index a55c6407..eed41dda 100755 --- a/compiler/tests/11_dff_array_test.py +++ b/compiler/tests/11_dff_array_test.py @@ -31,7 +31,7 @@ class dff_array_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/11_dff_buf_array_test.py b/compiler/tests/11_dff_buf_array_test.py index f0b75552..d2932cac 100755 --- a/compiler/tests/11_dff_buf_array_test.py +++ b/compiler/tests/11_dff_buf_array_test.py @@ -31,7 +31,7 @@ class dff_buf_array_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/11_dff_buf_test.py b/compiler/tests/11_dff_buf_test.py index f434f768..c9c25f16 100755 --- a/compiler/tests/11_dff_buf_test.py +++ b/compiler/tests/11_dff_buf_test.py @@ -23,7 +23,7 @@ class dff_buf_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/11_dff_inv_array_test.py b/compiler/tests/11_dff_inv_array_test.py index 2196a3f2..ed03e6bc 100755 --- a/compiler/tests/11_dff_inv_array_test.py +++ b/compiler/tests/11_dff_inv_array_test.py @@ -31,7 +31,7 @@ class dff_inv_array_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/11_dff_inv_test.py b/compiler/tests/11_dff_inv_test.py index 43d49246..53a92852 100755 --- a/compiler/tests/11_dff_inv_test.py +++ b/compiler/tests/11_dff_inv_test.py @@ -23,7 +23,7 @@ class dff_inv_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/12_tri_gate_array_test.py b/compiler/tests/12_tri_gate_array_test.py index 4f9cfa3e..cb789155 100755 --- a/compiler/tests/12_tri_gate_array_test.py +++ b/compiler/tests/12_tri_gate_array_test.py @@ -27,7 +27,7 @@ class tri_gate_array_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py index 2cc745c2..1052f0de 100755 --- a/compiler/tests/13_delay_chain_test.py +++ b/compiler/tests/13_delay_chain_test.py @@ -23,7 +23,7 @@ class delay_chain_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/14_replica_bitline_test.py b/compiler/tests/14_replica_bitline_test.py index 6797bc65..9853b581 100755 --- a/compiler/tests/14_replica_bitline_test.py +++ b/compiler/tests/14_replica_bitline_test.py @@ -70,7 +70,7 @@ class replica_bitline_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/16_control_logic_test.py b/compiler/tests/16_control_logic_test.py index 7a4ff768..ef435c4c 100755 --- a/compiler/tests/16_control_logic_test.py +++ b/compiler/tests/16_control_logic_test.py @@ -53,7 +53,7 @@ class control_logic_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py index 23b7ec46..1245926b 100755 --- a/compiler/tests/19_bank_select_test.py +++ b/compiler/tests/19_bank_select_test.py @@ -40,7 +40,7 @@ class bank_select_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index 4fceafec..9bf32423 100755 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -49,7 +49,7 @@ class multi_bank_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/19_pmulti_bank_test.py b/compiler/tests/19_pmulti_bank_test.py index 03544587..32d3917a 100755 --- a/compiler/tests/19_pmulti_bank_test.py +++ b/compiler/tests/19_pmulti_bank_test.py @@ -54,7 +54,7 @@ class multi_bank_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index d45283e0..dee59175 100755 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -137,7 +137,7 @@ class psingle_bank_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index 3c32b30d..da411d1f 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -48,7 +48,7 @@ class single_bank_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/20_psram_1bank_nomux_test.py b/compiler/tests/20_psram_1bank_nomux_test.py index 6106763c..a2992cba 100755 --- a/compiler/tests/20_psram_1bank_nomux_test.py +++ b/compiler/tests/20_psram_1bank_nomux_test.py @@ -128,7 +128,7 @@ class sram_1bank_test(openram_test): """ globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/20_sram_1bank_2mux_test.py b/compiler/tests/20_sram_1bank_2mux_test.py index 8c275e7c..2c8e28f0 100755 --- a/compiler/tests/20_sram_1bank_2mux_test.py +++ b/compiler/tests/20_sram_1bank_2mux_test.py @@ -29,7 +29,7 @@ class sram_1bank_2mux_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/20_sram_1bank_4mux_test.py b/compiler/tests/20_sram_1bank_4mux_test.py index 4ff443dc..489ff354 100755 --- a/compiler/tests/20_sram_1bank_4mux_test.py +++ b/compiler/tests/20_sram_1bank_4mux_test.py @@ -29,7 +29,7 @@ class sram_1bank_4mux_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/20_sram_1bank_8mux_test.py b/compiler/tests/20_sram_1bank_8mux_test.py index 695dcffe..2595582f 100755 --- a/compiler/tests/20_sram_1bank_8mux_test.py +++ b/compiler/tests/20_sram_1bank_8mux_test.py @@ -29,7 +29,7 @@ class sram_1bank_8mux_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/20_sram_1bank_nomux_test.py b/compiler/tests/20_sram_1bank_nomux_test.py index a89fb4e5..783bcad2 100755 --- a/compiler/tests/20_sram_1bank_nomux_test.py +++ b/compiler/tests/20_sram_1bank_nomux_test.py @@ -29,7 +29,7 @@ class sram_1bank_nomux_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index ff9fbaea..ab8c6ec2 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -48,7 +48,7 @@ class sram_2bank_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/20_sram_4bank_test.py b/compiler/tests/20_sram_4bank_test.py index fb34d3b0..25649e8e 100755 --- a/compiler/tests/20_sram_4bank_test.py +++ b/compiler/tests/20_sram_4bank_test.py @@ -47,7 +47,7 @@ class sram_4bank_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index a5aca3e8..5facb482 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -81,7 +81,7 @@ class timing_sram_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py index 9bfdb24b..faa8617d 100755 --- a/compiler/tests/21_hspice_setuphold_test.py +++ b/compiler/tests/21_hspice_setuphold_test.py @@ -52,7 +52,7 @@ class timing_setup_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 45a9b7f6..3ef27fc5 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -81,7 +81,7 @@ class timing_sram_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/21_ngspice_setuphold_test.py b/compiler/tests/21_ngspice_setuphold_test.py index d58bfc50..924d05a5 100755 --- a/compiler/tests/21_ngspice_setuphold_test.py +++ b/compiler/tests/21_ngspice_setuphold_test.py @@ -53,7 +53,7 @@ class timing_setup_test(openram_test): reload(characterizer) globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_psram_1bank_2mux_func_test.py b/compiler/tests/22_psram_1bank_2mux_func_test.py index d8233d08..1e1367ed 100755 --- a/compiler/tests/22_psram_1bank_2mux_func_test.py +++ b/compiler/tests/22_psram_1bank_2mux_func_test.py @@ -49,7 +49,7 @@ class psram_1bank_2mux_func_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_psram_1bank_4mux_func_test.py b/compiler/tests/22_psram_1bank_4mux_func_test.py index 1ae684d9..d62e2855 100755 --- a/compiler/tests/22_psram_1bank_4mux_func_test.py +++ b/compiler/tests/22_psram_1bank_4mux_func_test.py @@ -11,7 +11,7 @@ import globals from globals import OPTS import debug -@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test") +#@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test") class psram_1bank_4mux_func_test(openram_test): def runTest(self): @@ -49,7 +49,7 @@ class psram_1bank_4mux_func_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_psram_1bank_8mux_func_test.py b/compiler/tests/22_psram_1bank_8mux_func_test.py index d81e76f9..02ea2f3b 100755 --- a/compiler/tests/22_psram_1bank_8mux_func_test.py +++ b/compiler/tests/22_psram_1bank_8mux_func_test.py @@ -37,6 +37,7 @@ class psram_1bank_8mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = sram(c, name="sram") + tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) @@ -48,7 +49,7 @@ class psram_1bank_8mux_func_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_psram_1bank_nomux_func_test.py b/compiler/tests/22_psram_1bank_nomux_func_test.py index 681e24d5..ce852dff 100755 --- a/compiler/tests/22_psram_1bank_nomux_func_test.py +++ b/compiler/tests/22_psram_1bank_nomux_func_test.py @@ -49,7 +49,7 @@ class psram_1bank_nomux_func_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py index 7779ed4f..8b195c95 100755 --- a/compiler/tests/22_sram_1bank_2mux_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_func_test.py @@ -47,7 +47,7 @@ class sram_1bank_2mux_func_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py index c16b86fe..cf972843 100755 --- a/compiler/tests/22_sram_1bank_4mux_func_test.py +++ b/compiler/tests/22_sram_1bank_4mux_func_test.py @@ -47,7 +47,7 @@ class sram_1bank_4mux_func_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py index be8e538f..61c0efb7 100755 --- a/compiler/tests/22_sram_1bank_8mux_func_test.py +++ b/compiler/tests/22_sram_1bank_8mux_func_test.py @@ -38,6 +38,7 @@ class sram_1bank_8mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = sram(c, name="sram") + tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) @@ -49,7 +50,7 @@ class sram_1bank_8mux_func_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py index 52d63f4a..43d640ab 100755 --- a/compiler/tests/22_sram_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_func_test.py @@ -47,7 +47,7 @@ class sram_1bank_nomux_func_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index 8d5064d5..b111a57d 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -44,7 +44,7 @@ class lib_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index 952072aa..7f0a9c47 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -55,7 +55,7 @@ class lib_test(openram_test): reload(characterizer) globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 1b2d317c..5534598e 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -54,7 +54,7 @@ class lib_test(openram_test): reload(characterizer) globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index f66104b6..d4bf2619 100755 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -42,7 +42,7 @@ class lef_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index 48ba29e8..eebeb258 100755 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -38,7 +38,7 @@ class verilog_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/26_pex_test.py b/compiler/tests/26_pex_test.py index edb344f9..d374e485 100755 --- a/compiler/tests/26_pex_test.py +++ b/compiler/tests/26_pex_test.py @@ -306,7 +306,7 @@ class sram_func_test(openram_test): sti_file.file.close() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/27_worst_case_delay_test.py b/compiler/tests/27_worst_case_delay_test.py index 42a07bef..52dd3422 100755 --- a/compiler/tests/27_worst_case_delay_test.py +++ b/compiler/tests/27_worst_case_delay_test.py @@ -73,7 +73,7 @@ class worst_case_timing_sram_test(openram_test): globals.end_openram() -# instantiate a copdsay of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] diff --git a/compiler/tests/30_openram_test.py b/compiler/tests/30_openram_test.py index 038a2e15..7450dfba 100755 --- a/compiler/tests/30_openram_test.py +++ b/compiler/tests/30_openram_test.py @@ -83,7 +83,7 @@ class openram_test(openram_test): globals.end_openram() -# instantiate a copy of the class to actually run the test +# run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:]