mirror of https://github.com/VLSIDA/OpenRAM.git
Fix power ring routing boundary bug.
This commit is contained in:
parent
7e7670581c
commit
01a73b31e1
|
|
@ -1322,7 +1322,7 @@ class layout():
|
||||||
|
|
||||||
self.bbox = [self.bounding_box.ll(), self.bounding_box.ur()]
|
self.bbox = [self.bounding_box.ll(), self.bounding_box.ur()]
|
||||||
|
|
||||||
def get_bbox(self, side="all", big_margin=0, little_margin=0):
|
def get_bbox(self, side="all", margin=0):
|
||||||
"""
|
"""
|
||||||
Get the bounding box from the GDS
|
Get the bounding box from the GDS
|
||||||
"""
|
"""
|
||||||
|
|
@ -1349,27 +1349,18 @@ class layout():
|
||||||
ll_offset = vector(0, 0)
|
ll_offset = vector(0, 0)
|
||||||
ur_offset = vector(0, 0)
|
ur_offset = vector(0, 0)
|
||||||
if side in ["ring", "top", "all"]:
|
if side in ["ring", "top", "all"]:
|
||||||
ur_offset += vector(0, big_margin)
|
ur_offset += vector(0, margin)
|
||||||
else:
|
|
||||||
ur_offset += vector(0, little_margin)
|
|
||||||
if side in ["ring", "bottom", "all"]:
|
if side in ["ring", "bottom", "all"]:
|
||||||
ll_offset += vector(0, big_margin)
|
ll_offset += vector(0, margin)
|
||||||
else:
|
|
||||||
ll_offset += vector(0, little_margin)
|
|
||||||
if side in ["ring", "left", "all"]:
|
if side in ["ring", "left", "all"]:
|
||||||
ll_offset += vector(big_margin, 0)
|
ll_offset += vector(margin, 0)
|
||||||
else:
|
|
||||||
ll_offset += vector(little_margin, 0)
|
|
||||||
if side in ["ring", "right", "all"]:
|
if side in ["ring", "right", "all"]:
|
||||||
ur_offset += vector(big_margin, 0)
|
ur_offset += vector(margin, 0)
|
||||||
else:
|
|
||||||
ur_offset += vector(little_margin, 0)
|
|
||||||
bbox = (ll - ll_offset, ur + ur_offset)
|
bbox = (ll - ll_offset, ur + ur_offset)
|
||||||
size = ur - ll
|
size = ur - ll
|
||||||
debug.info(1, "Size: {0} x {1} with perimeter big margin {2} little margin {3}".format(size.x,
|
debug.info(1, "Size: {0} x {1} with perimeter margin {2}".format(size.x,
|
||||||
size.y,
|
size.y,
|
||||||
big_margin,
|
margin))
|
||||||
little_margin))
|
|
||||||
|
|
||||||
return bbox
|
return bbox
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,10 @@ class delay_chain(design.design):
|
||||||
# The routing to connect the loads is over the first and last cells
|
# The routing to connect the loads is over the first and last cells
|
||||||
# We have an even number of drivers and must only do every other
|
# We have an even number of drivers and must only do every other
|
||||||
# supply rail
|
# supply rail
|
||||||
|
if OPTS.experimental_power:
|
||||||
|
self.route_horizontal_pins("vdd")
|
||||||
|
self.route_horizontal_pins("gnd")
|
||||||
|
else:
|
||||||
for inst in self.driver_inst_list:
|
for inst in self.driver_inst_list:
|
||||||
load_list = self.load_inst_map[inst]
|
load_list = self.load_inst_map[inst]
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ class wordline_driver_array(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Experiment with power straps
|
# Experiment with power straps
|
||||||
if OPTS.experimental_power:
|
if OPTS.tech_name=="sky130" or OPTS.experimental_power:
|
||||||
if layer_props.wordline_driver.vertical_supply:
|
if layer_props.wordline_driver.vertical_supply:
|
||||||
self.route_vertical_pins("vdd", insts=self.wld_inst)
|
self.route_vertical_pins("vdd", insts=self.wld_inst)
|
||||||
self.route_vertical_pins("gnd", insts=self.wld_inst)
|
self.route_vertical_pins("gnd", insts=self.wld_inst)
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,16 @@ class grid:
|
||||||
self.add_map(n)
|
self.add_map(n)
|
||||||
return self.map[n].blocked
|
return self.map[n].blocked
|
||||||
|
|
||||||
|
def is_inside(self, n):
|
||||||
|
if not isinstance(n, vector3d):
|
||||||
|
for item in n:
|
||||||
|
if self.is_inside(item):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return n.x >= self.ll.x and n.x <= self.ur.x and n.y >= self.ll.y and n.y <= self.ur.y
|
||||||
|
|
||||||
def set_path(self, n, value=True):
|
def set_path(self, n, value=True):
|
||||||
if isinstance(n, (list, tuple, set, frozenset)):
|
if isinstance(n, (list, tuple, set, frozenset)):
|
||||||
for item in n:
|
for item in n:
|
||||||
|
|
@ -128,7 +138,7 @@ class grid:
|
||||||
"""
|
"""
|
||||||
Side specifies which side.
|
Side specifies which side.
|
||||||
Layer specifies horizontal (0) or vertical (1)
|
Layer specifies horizontal (0) or vertical (1)
|
||||||
Width specifies how wide the perimter "stripe" should be.
|
Width specifies how wide the perimeter "stripe" should be.
|
||||||
Works from the inside out from the bbox (ll, ur)
|
Works from the inside out from the bbox (ll, ur)
|
||||||
"""
|
"""
|
||||||
if "ring" in side:
|
if "ring" in side:
|
||||||
|
|
|
||||||
|
|
@ -92,12 +92,19 @@ class router(router_tech):
|
||||||
def get_bbox(self):
|
def get_bbox(self):
|
||||||
return self.bbox
|
return self.bbox
|
||||||
|
|
||||||
def create_routing_grid(self, router_type):
|
def create_routing_grid(self, router_type=None):
|
||||||
"""
|
"""
|
||||||
Create a sprase routing grid with A* expansion functions.
|
Create (or recreate) a sprase routing grid with A* expansion functions.
|
||||||
"""
|
"""
|
||||||
|
debug.check(router_type or hasattr(self, "router_type"), "Must specify a routing grid type.")
|
||||||
|
|
||||||
self.init_bbox(self.bbox, self.margin)
|
self.init_bbox(self.bbox, self.margin)
|
||||||
|
|
||||||
|
if router_type:
|
||||||
|
self.router_type = router_type
|
||||||
self.rg = router_type(self.ll, self.ur, self.track_width)
|
self.rg = router_type(self.ll, self.ur, self.track_width)
|
||||||
|
else:
|
||||||
|
self.rg = self.router_type(self.ll, self.ur, self.track_width)
|
||||||
|
|
||||||
def clear_pins(self):
|
def clear_pins(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -927,40 +934,34 @@ class router(router_tech):
|
||||||
|
|
||||||
def add_ring_supply_pin(self, name, width=3, space=2):
|
def add_ring_supply_pin(self, name, width=3, space=2):
|
||||||
"""
|
"""
|
||||||
Adds a ring supply pin that goes inside the given bbox.
|
Adds a ring supply pin that goes outside the given bbox.
|
||||||
"""
|
"""
|
||||||
pg = pin_group(name, [], self)
|
pg = pin_group(name, [], self)
|
||||||
# Offset two spaces inside and one between the rings
|
|
||||||
# Units are in routing grids
|
|
||||||
if name == "gnd":
|
|
||||||
offset = width + 2 * space
|
|
||||||
else:
|
|
||||||
offset = space
|
|
||||||
|
|
||||||
# LEFT
|
# LEFT
|
||||||
left_grids = set(self.rg.get_perimeter_list(side="left_ring",
|
left_grids = set(self.rg.get_perimeter_list(side="left_ring",
|
||||||
width=width,
|
width=width,
|
||||||
margin=self.margin,
|
margin=self.margin,
|
||||||
offset=offset,
|
offset=space,
|
||||||
layers=[1]))
|
layers=[1]))
|
||||||
|
|
||||||
# RIGHT
|
# RIGHT
|
||||||
right_grids = set(self.rg.get_perimeter_list(side="right_ring",
|
right_grids = set(self.rg.get_perimeter_list(side="right_ring",
|
||||||
width=width,
|
width=width,
|
||||||
margin=self.margin,
|
margin=self.margin,
|
||||||
offset=offset,
|
offset=space,
|
||||||
layers=[1]))
|
layers=[1]))
|
||||||
# TOP
|
# TOP
|
||||||
top_grids = set(self.rg.get_perimeter_list(side="top_ring",
|
top_grids = set(self.rg.get_perimeter_list(side="top_ring",
|
||||||
width=width,
|
width=width,
|
||||||
margin=self.margin,
|
margin=self.margin,
|
||||||
offset=offset,
|
offset=space,
|
||||||
layers=[0]))
|
layers=[0]))
|
||||||
# BOTTOM
|
# BOTTOM
|
||||||
bottom_grids = set(self.rg.get_perimeter_list(side="bottom_ring",
|
bottom_grids = set(self.rg.get_perimeter_list(side="bottom_ring",
|
||||||
width=width,
|
width=width,
|
||||||
margin=self.margin,
|
margin=self.margin,
|
||||||
offset=offset,
|
offset=space,
|
||||||
layers=[0]))
|
layers=[0]))
|
||||||
|
|
||||||
horizontal_layer_grids = left_grids | right_grids
|
horizontal_layer_grids = left_grids | right_grids
|
||||||
|
|
@ -972,6 +973,7 @@ class router(router_tech):
|
||||||
|
|
||||||
# Add vias in the overlap points
|
# Add vias in the overlap points
|
||||||
horizontal_corner_grids = vertical_layer_grids & horizontal_layer_grids
|
horizontal_corner_grids = vertical_layer_grids & horizontal_layer_grids
|
||||||
|
corners = []
|
||||||
for g in horizontal_corner_grids:
|
for g in horizontal_corner_grids:
|
||||||
self.add_via(g)
|
self.add_via(g)
|
||||||
|
|
||||||
|
|
@ -984,6 +986,15 @@ class router(router_tech):
|
||||||
self.pin_groups[name].append(pg)
|
self.pin_groups[name].append(pg)
|
||||||
self.new_pins[name] = pg.pins
|
self.new_pins[name] = pg.pins
|
||||||
|
|
||||||
|
# Update the bbox so that it now includes the new pins
|
||||||
|
for p in pg.pins:
|
||||||
|
if p.lx() < self.ll.x or p.by() < self.ll.y:
|
||||||
|
self.ll = p.ll()
|
||||||
|
if p.rx() > self.ur.x or p.uy() > self.ur.y:
|
||||||
|
self.ur = p.ur()
|
||||||
|
self.bbox = (self.ll, self.ur)
|
||||||
|
self.create_routing_grid()
|
||||||
|
|
||||||
def get_new_pins(self, name):
|
def get_new_pins(self, name):
|
||||||
return self.new_pins[name]
|
return self.new_pins[name]
|
||||||
|
|
||||||
|
|
@ -1274,11 +1285,18 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
debug.info(2, "Adding router info")
|
debug.info(2, "Adding router info")
|
||||||
|
|
||||||
|
show_bbox = False
|
||||||
show_blockages = False
|
show_blockages = False
|
||||||
show_blockage_grids = False
|
show_blockage_grids = False
|
||||||
show_enclosures = False
|
show_enclosures = False
|
||||||
show_all_grids = True
|
show_all_grids = True
|
||||||
|
|
||||||
|
if show_bbox:
|
||||||
|
self.cell.add_rect(layer="text",
|
||||||
|
offset=vector(self.ll.x, self.ll.y),
|
||||||
|
width=self.ur.x - self.ll.x,
|
||||||
|
height=self.ur.y - self.ll.y)
|
||||||
|
|
||||||
if show_all_grids:
|
if show_all_grids:
|
||||||
for g in self.rg.map:
|
for g in self.rg.map:
|
||||||
self.annotate_grid(g)
|
self.annotate_grid(g)
|
||||||
|
|
|
||||||
|
|
@ -119,10 +119,11 @@ class signal_grid(grid):
|
||||||
# Expand all directions.
|
# Expand all directions.
|
||||||
neighbors = curpath.expand_dirs()
|
neighbors = curpath.expand_dirs()
|
||||||
|
|
||||||
|
# Filter the out of region ones
|
||||||
# Filter the blocked ones
|
# Filter the blocked ones
|
||||||
unblocked_neighbors = [x for x in neighbors if not self.is_blocked(x)]
|
valid_neighbors = [x for x in neighbors if self.is_inside(x) and not self.is_blocked(x)]
|
||||||
|
|
||||||
return unblocked_neighbors
|
return valid_neighbors
|
||||||
|
|
||||||
def hpwl(self, src, dest):
|
def hpwl(self, src, dest):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ class supply_tree_router(router):
|
||||||
bbox=bbox,
|
bbox=bbox,
|
||||||
route_track_width=self.route_track_width)
|
route_track_width=self.route_track_width)
|
||||||
|
|
||||||
|
|
||||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||||
"""
|
"""
|
||||||
Route the two nets in a single layer.
|
Route the two nets in a single layer.
|
||||||
|
|
@ -75,6 +76,9 @@ class supply_tree_router(router):
|
||||||
self.add_ring_supply_pin(self.vdd_name)
|
self.add_ring_supply_pin(self.vdd_name)
|
||||||
self.add_ring_supply_pin(self.gnd_name)
|
self.add_ring_supply_pin(self.gnd_name)
|
||||||
|
|
||||||
|
#self.write_debug_gds("initial_tree_router.gds",False)
|
||||||
|
#breakpoint()
|
||||||
|
|
||||||
# Route the supply pins to the supply rails
|
# Route the supply pins to the supply rails
|
||||||
# Route vdd first since we want it to be shorter
|
# Route vdd first since we want it to be shorter
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
|
|
@ -82,8 +86,6 @@ class supply_tree_router(router):
|
||||||
self.route_pins(gnd_name)
|
self.route_pins(gnd_name)
|
||||||
print_time("Maze routing supplies", datetime.now(), start_time, 3)
|
print_time("Maze routing supplies", datetime.now(), start_time, 3)
|
||||||
|
|
||||||
# self.write_debug_gds("final_tree_router.gds",False)
|
|
||||||
|
|
||||||
# Did we route everything??
|
# Did we route everything??
|
||||||
if not self.check_all_routed(vdd_name):
|
if not self.check_all_routed(vdd_name):
|
||||||
return False
|
return False
|
||||||
|
|
@ -144,15 +146,15 @@ class supply_tree_router(router):
|
||||||
|
|
||||||
# Route MST components
|
# Route MST components
|
||||||
for index, (src, dest) in enumerate(connections):
|
for index, (src, dest) in enumerate(connections):
|
||||||
if not (index % 100):
|
if not (index % 25):
|
||||||
debug.info(1, "{0} supply segments routed, {1} remaining.".format(index, len(connections) - index))
|
debug.info(1, "{0} supply segments routed, {1} remaining.".format(index, len(connections) - index))
|
||||||
self.route_signal(pin_name, src, dest)
|
self.route_signal(pin_name, src, dest)
|
||||||
# if pin_name == "gnd":
|
if False and pin_name == "gnd":
|
||||||
# print("\nSRC {}: ".format(src) + str(self.pin_groups[pin_name][src].grids) + str(self.pin_groups[pin_name][src].blockages))
|
print("\nSRC {}: ".format(src) + str(self.pin_groups[pin_name][src].grids) + str(self.pin_groups[pin_name][src].blockages))
|
||||||
# print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages))
|
print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages))
|
||||||
# self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False)
|
self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False)
|
||||||
|
|
||||||
#self.write_debug_gds("final.gds", True)
|
#self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False)
|
||||||
#return
|
#return
|
||||||
|
|
||||||
def route_signal(self, pin_name, src_idx, dest_idx):
|
def route_signal(self, pin_name, src_idx, dest_idx):
|
||||||
|
|
@ -161,7 +163,7 @@ class supply_tree_router(router):
|
||||||
# Second pass, clear prior pin blockages so that you can route over other metal
|
# Second pass, clear prior pin blockages so that you can route over other metal
|
||||||
# of the same supply. Otherwise, this can create a lot of circular routes due to accidental overlaps.
|
# of the same supply. Otherwise, this can create a lot of circular routes due to accidental overlaps.
|
||||||
for unblock_routes in [False, True]:
|
for unblock_routes in [False, True]:
|
||||||
for detour_scale in [5 * pow(2, x) for x in range(5)]:
|
for detour_scale in [2 * pow(2, x) for x in range(5)]:
|
||||||
debug.info(2, "Routing {0} to {1} with scale {2}".format(src_idx, dest_idx, detour_scale))
|
debug.info(2, "Routing {0} to {1} with scale {2}".format(src_idx, dest_idx, detour_scale))
|
||||||
|
|
||||||
# Clear everything in the routing grid.
|
# Clear everything in the routing grid.
|
||||||
|
|
@ -187,6 +189,8 @@ class supply_tree_router(router):
|
||||||
# Actually run the A* router
|
# Actually run the A* router
|
||||||
if self.run_router(detour_scale=detour_scale):
|
if self.run_router(detour_scale=detour_scale):
|
||||||
return
|
return
|
||||||
|
if detour_scale > 2:
|
||||||
|
self.write_debug_gds("route_{0}_{1}_d{2}.gds".format(src_idx, dest_idx, detour_scale), False)
|
||||||
|
|
||||||
self.write_debug_gds("debug_route.gds", True)
|
self.write_debug_gds("debug_route.gds", True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -336,31 +336,27 @@ class sram_1bank(sram_base):
|
||||||
# Some technologies have an isolation
|
# Some technologies have an isolation
|
||||||
self.add_dnwell(inflate=2.5)
|
self.add_dnwell(inflate=2.5)
|
||||||
|
|
||||||
|
# Route the supplies together and/or to the ring/stripes.
|
||||||
|
# This is done with the original bbox since the escape routes need to
|
||||||
|
# be outside of the ring for OpenLane
|
||||||
|
rt = router_tech(self.supply_stack, 1)
|
||||||
|
init_bbox = self.get_bbox(side="ring",
|
||||||
|
margin=rt.track_width)
|
||||||
|
|
||||||
# We need the initial bbox for the supply rings later
|
# We need the initial bbox for the supply rings later
|
||||||
# because the perimeter pins will change the bbox
|
# because the perimeter pins will change the bbox
|
||||||
# Route the pins to the perimeter
|
# Route the pins to the perimeter
|
||||||
pre_bbox = None
|
|
||||||
if OPTS.perimeter_pins:
|
if OPTS.perimeter_pins:
|
||||||
rt = router_tech(self.supply_stack, 1)
|
# We now route the escape routes far enough out so that they will
|
||||||
|
# reach past the power ring or stripes on the sides
|
||||||
if OPTS.supply_pin_type in ["ring", "left", "right", "top", "bottom"]:
|
# The power rings are 4 tracks wide with 2 tracks spacing, so space it
|
||||||
big_margin = 12 * rt.track_width
|
# 11 tracks out
|
||||||
little_margin = 2 * rt.track_width
|
bbox = self.get_bbox(side="ring",
|
||||||
else:
|
margin=11*rt.track_width)
|
||||||
big_margin = 6 * rt.track_width
|
|
||||||
little_margin = 0
|
|
||||||
|
|
||||||
pre_bbox = self.get_bbox(side="ring",
|
|
||||||
big_margin=rt.track_width)
|
|
||||||
|
|
||||||
bbox = self.get_bbox(side=OPTS.supply_pin_type,
|
|
||||||
big_margin=big_margin,
|
|
||||||
little_margin=little_margin)
|
|
||||||
self.route_escape_pins(bbox)
|
self.route_escape_pins(bbox)
|
||||||
|
|
||||||
# Route the supplies first since the MST is not blockage aware
|
self.route_supplies(init_bbox)
|
||||||
# and signals can route to anywhere on sides (it is flexible)
|
|
||||||
self.route_supplies(pre_bbox)
|
|
||||||
|
|
||||||
def route_dffs(self, add_routes=True):
|
def route_dffs(self, add_routes=True):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,7 @@ class sram_base(design, verilog, lef):
|
||||||
for inst in self.insts:
|
for inst in self.insts:
|
||||||
self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name])
|
self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name])
|
||||||
|
|
||||||
|
# Pick the router type
|
||||||
if not OPTS.route_supplies:
|
if not OPTS.route_supplies:
|
||||||
# Do not route the power supply (leave as must-connect pins)
|
# Do not route the power supply (leave as must-connect pins)
|
||||||
return
|
return
|
||||||
|
|
@ -250,6 +251,7 @@ class sram_base(design, verilog, lef):
|
||||||
from supply_grid_router import supply_grid_router as router
|
from supply_grid_router import supply_grid_router as router
|
||||||
else:
|
else:
|
||||||
from supply_tree_router import supply_tree_router as router
|
from supply_tree_router import supply_tree_router as router
|
||||||
|
|
||||||
rtr=router(layers=self.supply_stack,
|
rtr=router(layers=self.supply_stack,
|
||||||
design=self,
|
design=self,
|
||||||
bbox=bbox,
|
bbox=bbox,
|
||||||
|
|
@ -257,6 +259,8 @@ class sram_base(design, verilog, lef):
|
||||||
|
|
||||||
rtr.route()
|
rtr.route()
|
||||||
|
|
||||||
|
# This removes the original pre-supply routing pins and replaces them
|
||||||
|
# with the ring or peripheral power pins
|
||||||
if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]:
|
if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]:
|
||||||
# Find the lowest leftest pin for vdd and gnd
|
# Find the lowest leftest pin for vdd and gnd
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue