mirror of https://github.com/VLSIDA/OpenRAM.git
Add left stripe power routes to tree router as option.
This commit is contained in:
parent
d3f4810d1b
commit
f48b0b8f41
|
|
@ -122,34 +122,44 @@ class grid:
|
|||
self.set_target(n)
|
||||
# self.set_blocked(n, False)
|
||||
|
||||
def add_perimeter_target(self, side="all"):
|
||||
debug.info(3, "Adding perimeter target")
|
||||
|
||||
def get_perimeter_list(self, side="left", layers=[0, 1], width=1, margin=0, offset=0):
|
||||
"""
|
||||
Side specifies which side.
|
||||
Layer specifies horizontal (0) or vertical (1)
|
||||
Width specifies how wide the perimter "stripe" should be.
|
||||
"""
|
||||
perimeter_list = []
|
||||
# Add the left/right columns
|
||||
if side=="all" or side=="left":
|
||||
x = self.ll.x
|
||||
for y in range(self.ll.y, self.ur.y, 1):
|
||||
perimeter_list.append(vector3d(x, y, 0))
|
||||
perimeter_list.append(vector3d(x, y, 1))
|
||||
for x in range(self.ll.x + offset, self.ll.x + width + offset, 1):
|
||||
for y in range(self.ll.y + margin, self.ur.y - margin, 1):
|
||||
for layer in layers:
|
||||
perimeter_list.append(vector3d(x, y, layer))
|
||||
|
||||
if side=="all" or side=="right":
|
||||
x = self.ur.x
|
||||
for y in range(self.ll.y, self.ur.y, 1):
|
||||
perimeter_list.append(vector3d(x, y, 0))
|
||||
perimeter_list.append(vector3d(x, y, 1))
|
||||
for x in range(self.ur.x - width - offset, self.ur.x - offset, 1):
|
||||
for y in range(self.ll.y + margin, self.ur.y - margin, 1):
|
||||
for layer in layers:
|
||||
perimeter_list.append(vector3d(x, y, layer))
|
||||
|
||||
if side=="all" or side=="bottom":
|
||||
y = self.ll.y
|
||||
for x in range(self.ll.x, self.ur.x, 1):
|
||||
perimeter_list.append(vector3d(x, y, 0))
|
||||
perimeter_list.append(vector3d(x, y, 1))
|
||||
for y in range(self.ll.y + offset, self.ll.y + width + offset, 1):
|
||||
for x in range(self.ll.x + margin, self.ur.x - margin, 1):
|
||||
for layer in layers:
|
||||
perimeter_list.append(vector3d(x, y, layer))
|
||||
|
||||
if side=="all" or side=="top":
|
||||
y = self.ur.y
|
||||
for x in range(self.ll.x, self.ur.x, 1):
|
||||
perimeter_list.append(vector3d(x, y, 0))
|
||||
perimeter_list.append(vector3d(x, y, 1))
|
||||
for y in range(self.ur.y - width - offset, self.ur.y - offset, 1):
|
||||
for x in range(self.ll.x + margin, self.ur.x - margin, 1):
|
||||
for layer in layers:
|
||||
perimeter_list.append(vector3d(x, y, layer))
|
||||
|
||||
return perimeter_list
|
||||
|
||||
def add_perimeter_target(self, side="all", layers=[0, 1]):
|
||||
debug.info(3, "Adding perimeter target")
|
||||
|
||||
perimeter_list = self.get_perimeter_list(side, layers)
|
||||
|
||||
self.set_target(perimeter_list)
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ class pin_group:
|
|||
# Now simplify the enclosure list
|
||||
new_pin_list = self.remove_redundant_shapes(pin_list)
|
||||
|
||||
# Now add the right name
|
||||
for pin in new_pin_list:
|
||||
pin.name = self.name
|
||||
|
||||
debug.check(len(new_pin_list) > 0,
|
||||
"Did not find any enclosures.")
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class router(router_tech):
|
|||
route on a given layer. This is limited to two layer routes.
|
||||
It populates blockages on a grid class.
|
||||
"""
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None, margin=0, route_track_width=1):
|
||||
def __init__(self, layers, design, bbox=None, margin=0, route_track_width=1):
|
||||
"""
|
||||
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
|
||||
|
|
@ -39,19 +39,7 @@ class router(router_tech):
|
|||
|
||||
self.cell = design
|
||||
|
||||
# If didn't specify a gds blockage file, write it out to read the gds
|
||||
# This isn't efficient, but easy for now
|
||||
# start_time = datetime.now()
|
||||
if not gds_filename:
|
||||
gds_filename = OPTS.openram_temp+"temp.gds"
|
||||
self.cell.gds_write(gds_filename)
|
||||
|
||||
# Load the gds file and read in all the shapes
|
||||
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||
self.reader = gdsMill.Gds2reader(self.layout)
|
||||
self.reader.loadFromFile(gds_filename)
|
||||
self.top_name = self.layout.rootStructureName
|
||||
# print_time("GDS read",datetime.now(), start_time)
|
||||
self.gds_filename = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
# The pin data structures
|
||||
# A map of pin names to a set of pin_layout structures
|
||||
|
|
@ -91,6 +79,16 @@ class router(router_tech):
|
|||
"""
|
||||
Initialize the ll,ur values with the paramter or using the layout boundary.
|
||||
"""
|
||||
|
||||
# If didn't specify a gds blockage file, write it out to read the gds
|
||||
# This isn't efficient, but easy for now
|
||||
# Load the gds file and read in all the shapes
|
||||
self.cell.gds_write(self.gds_filename)
|
||||
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||
self.reader = gdsMill.Gds2reader(self.layout)
|
||||
self.reader.loadFromFile(self.gds_filename)
|
||||
self.top_name = self.layout.rootStructureName
|
||||
|
||||
if not bbox:
|
||||
# The boundary will determine the limits to the size
|
||||
# of the routing grid
|
||||
|
|
@ -178,6 +176,17 @@ class router(router_tech):
|
|||
"""
|
||||
Find the pins and blockages in the design
|
||||
"""
|
||||
|
||||
# If didn't specify a gds blockage file, write it out to read the gds
|
||||
# This isn't efficient, but easy for now
|
||||
# Load the gds file and read in all the shapes
|
||||
self.cell.gds_write(self.gds_filename)
|
||||
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||
self.reader = gdsMill.Gds2reader(self.layout)
|
||||
self.reader.loadFromFile(self.gds_filename)
|
||||
self.top_name = self.layout.rootStructureName
|
||||
# print_time("GDS read",datetime.now(), start_time)
|
||||
|
||||
# This finds the pin shapes and sorts them into "groups" that
|
||||
# are connected. This must come before the blockages, so we
|
||||
# can not count the pins themselves
|
||||
|
|
@ -881,6 +890,26 @@ class router(router_tech):
|
|||
# Clearing the blockage of this pin requires the inflated pins
|
||||
self.clear_blockages(pin_name)
|
||||
|
||||
def add_side_supply_pin(self, name, side="left", width=2):
|
||||
"""
|
||||
Adds a supply pin to the perimeter and resizes the bounding box.
|
||||
"""
|
||||
pg = pin_group(name, [], self)
|
||||
if name == "vdd":
|
||||
offset = width
|
||||
else:
|
||||
offset = 0
|
||||
|
||||
pg.grids = set(self.rg.get_perimeter_list(side=side,
|
||||
width=width,
|
||||
margin=self.margin,
|
||||
offset=offset,
|
||||
layers=[1]))
|
||||
pg.enclosures = pg.compute_enclosures()
|
||||
pg.pins = set(pg.enclosures)
|
||||
self.cell.pin_map[name].update(pg.pins)
|
||||
self.pin_groups[name].append(pg)
|
||||
|
||||
def add_perimeter_target(self, side="all"):
|
||||
"""
|
||||
This will mark all the cells on the perimeter of the original layout as a target.
|
||||
|
|
@ -1229,23 +1258,6 @@ class router(router_tech):
|
|||
|
||||
return keep_pin
|
||||
|
||||
def get_left_pins(self, pin_name):
|
||||
""" Return the leftest pin(s) group """
|
||||
|
||||
keep_pins = []
|
||||
for index, pg in enumerate(self.pin_groups[pin_name]):
|
||||
for pin in pg.enclosures:
|
||||
if not keep_pins:
|
||||
keep_pins = [pin]
|
||||
else:
|
||||
# Only need to check first since they are all the same left value
|
||||
if pin.lx() == keep_pins[0].lx():
|
||||
keep_pins.append(pin)
|
||||
elif pin.lx() < keep_pins[0].lx():
|
||||
keep_pins = [pin]
|
||||
|
||||
return keep_pins
|
||||
|
||||
def check_all_routed(self, pin_name):
|
||||
"""
|
||||
Check that all pin groups are routed.
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class router_tech:
|
|||
|
||||
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
|
||||
|
||||
min_width = drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf)
|
||||
min_width = self.route_track_width * drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf)
|
||||
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.route_track_width * min_wire_width, math.inf)
|
||||
|
||||
return (min_width, min_spacing)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class signal_escape_router(router):
|
|||
A router that routes signals to perimeter and makes pins.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, bbox=None, margin=0, gds_filename=None):
|
||||
def __init__(self, layers, design, bbox=None, margin=0):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
|
|
@ -25,7 +25,6 @@ class signal_escape_router(router):
|
|||
router.__init__(self,
|
||||
layers=layers,
|
||||
design=design,
|
||||
gds_filename=gds_filename,
|
||||
bbox=bbox,
|
||||
margin=margin)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ class signal_router(router):
|
|||
route on a given layer. This is limited to two layer routes.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
||||
def __init__(self, layers, design, bbox=None):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
"""
|
||||
router.__init__(self, layers, design, gds_filename, bbox)
|
||||
router.__init__(self, layers, design, bbox)
|
||||
|
||||
def route(self, src, dest, detour_scale=5):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class supply_grid_router(router):
|
|||
routes a grid to connect the supply on the two layers.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
||||
def __init__(self, layers, design, margin=0, bbox=None):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
|
|
@ -29,9 +29,9 @@ class supply_grid_router(router):
|
|||
start_time = datetime.now()
|
||||
|
||||
# Power rail width in minimum wire widths
|
||||
self.route_track_width = 2
|
||||
self.route_track_width = 1
|
||||
|
||||
router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width)
|
||||
router.__init__(self, layers, design, bbox=bbox, margin=margin, route_track_width=self.route_track_width)
|
||||
|
||||
# The list of supply rails (grid sets) that may be routed
|
||||
self.supply_rails = {}
|
||||
|
|
@ -357,7 +357,8 @@ class supply_grid_router(router):
|
|||
|
||||
# This is inefficient since it is non-incremental, but it was
|
||||
# easier to debug.
|
||||
self.prepare_blockages(pin_name)
|
||||
self.prepare_blockages()
|
||||
self.clear_blockages(self.vdd_name)
|
||||
|
||||
# Add the single component of the pin as the source
|
||||
# which unmarks it as a blockage too
|
||||
|
|
@ -369,7 +370,7 @@ class supply_grid_router(router):
|
|||
|
||||
# Actually run the A* router
|
||||
if not self.run_router(detour_scale=5):
|
||||
self.write_debug_gds("debug_route.gds", False)
|
||||
self.write_debug_gds("debug_route.gds")
|
||||
|
||||
# if index==3 and pin_name=="vdd":
|
||||
# self.write_debug_gds("route.gds",False)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class supply_tree_router(router):
|
|||
routes a grid to connect the supply on the two layers.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
||||
def __init__(self, layers, design, bbox=None, side_pin=None):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
|
|
@ -31,11 +31,19 @@ class supply_tree_router(router):
|
|||
# for prettier routes.
|
||||
self.route_track_width = 1
|
||||
|
||||
router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width)
|
||||
# The pin escape router already made the bounding box big enough,
|
||||
# so we can use the regular bbox here.
|
||||
self.side_pin = side_pin
|
||||
router.__init__(self,
|
||||
layers,
|
||||
design,
|
||||
bbox=bbox,
|
||||
route_track_width=self.route_track_width)
|
||||
|
||||
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.
|
||||
Setting pin stripe will make a power rail on the left side.
|
||||
"""
|
||||
debug.info(1, "Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
||||
self.vdd_name = vdd_name
|
||||
|
|
@ -50,11 +58,17 @@ class supply_tree_router(router):
|
|||
# but this is simplest for now.
|
||||
self.create_routing_grid(signal_grid)
|
||||
|
||||
# Get the pin shapes
|
||||
start_time = datetime.now()
|
||||
|
||||
# Get the pin shapes
|
||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||
print_time("Finding pins and blockages", datetime.now(), start_time, 3)
|
||||
|
||||
# Add side pins if enabled
|
||||
if self.side_pin:
|
||||
self.add_side_supply_pin(self.vdd_name)
|
||||
self.add_side_supply_pin(self.gnd_name)
|
||||
|
||||
# Route the supply pins to the supply rails
|
||||
# Route vdd first since we want it to be shorter
|
||||
start_time = datetime.now()
|
||||
|
|
|
|||
|
|
@ -226,14 +226,6 @@ class sram_base(design, verilog, lef):
|
|||
for inst in self.insts:
|
||||
self.copy_power_pins(inst, pin_name)
|
||||
|
||||
if not OPTS.route_supplies:
|
||||
# Do not route the power supply (leave as must-connect pins)
|
||||
return
|
||||
elif OPTS.route_supplies == "grid":
|
||||
from supply_grid_router import supply_grid_router as router
|
||||
else:
|
||||
from supply_tree_router import supply_tree_router as router
|
||||
|
||||
try:
|
||||
from tech import power_grid
|
||||
grid_stack = power_grid
|
||||
|
|
@ -242,14 +234,44 @@ class sram_base(design, verilog, lef):
|
|||
# Route a M3/M4 grid
|
||||
grid_stack = self.m3_stack
|
||||
|
||||
rtr=router(grid_stack, self)
|
||||
# lowest_coord = self.find_lowest_coords()
|
||||
# highest_coord = self.find_highest_coords()
|
||||
|
||||
# # Add two rails to the side
|
||||
# if OPTS.route_supplies == "side":
|
||||
# supply_pins = {}
|
||||
# # Find the lowest leftest pin for vdd and gnd
|
||||
# for (pin_name, pin_index) in [("vdd", 0), ("gnd", 1)]:
|
||||
# pin_width = 8 * getattr(self, "{}_width".format(grid_stack[2]))
|
||||
# pin_space = 2 * getattr(self, "{}_space".format(grid_stack[2]))
|
||||
# supply_pitch = pin_width + pin_space
|
||||
|
||||
# # Add side power rails on left from bottom to top
|
||||
# # These have a temporary name and will be connected later.
|
||||
# # They are here to reserve space now and ensure other pins go beyond
|
||||
# # their perimeter.
|
||||
# supply_height = highest_coord.y - lowest_coord.y
|
||||
|
||||
# supply_pins[pin_name] = self.add_layout_pin(text=pin_name,
|
||||
# layer=grid_stack[2],
|
||||
# offset=lowest_coord + vector(pin_index * supply_pitch, 0),
|
||||
# width=pin_width,
|
||||
# height=supply_height)
|
||||
|
||||
if not OPTS.route_supplies:
|
||||
# Do not route the power supply (leave as must-connect pins)
|
||||
return
|
||||
elif OPTS.route_supplies == "grid":
|
||||
from supply_grid_router import supply_grid_router as router
|
||||
else:
|
||||
from supply_tree_router import supply_tree_router as router
|
||||
|
||||
rtr=router(grid_stack, self, side_pin=(OPTS.route_supplies == "side"))
|
||||
rtr.route()
|
||||
|
||||
lowest_coord = self.find_lowest_coords()
|
||||
highest_coord = self.find_highest_coords()
|
||||
|
||||
if OPTS.route_supplies == "side":
|
||||
# Find the lowest leftest pin for vdd and gnd
|
||||
for (pin_name, pin_index) in [("vdd", 0), ("gnd", 1)]:
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin in self.get_pins(pin_name):
|
||||
self.add_rect(pin.layer,
|
||||
|
|
@ -260,43 +282,34 @@ class sram_base(design, verilog, lef):
|
|||
# Remove the pin shape(s)
|
||||
self.remove_layout_pin(pin_name)
|
||||
|
||||
# Either add two long rails or a simple pin
|
||||
if OPTS.route_supplies == "side":
|
||||
# Get the leftest pins
|
||||
pins = rtr.get_left_pins(pin_name)
|
||||
|
||||
pin_width = 2 * getattr(self, "{}_width".format(pins[0].layer))
|
||||
pin_space = 2 * getattr(self, "{}_space".format(pins[0].layer))
|
||||
supply_pitch = pin_width + pin_space
|
||||
|
||||
# Add side power rails on left from bottom to top
|
||||
# These have a temporary name and will be connected later.
|
||||
# They are here to reserve space now and ensure other pins go beyond
|
||||
# their perimeter.
|
||||
supply_height = highest_coord.y - lowest_coord.y
|
||||
supply_pin = self.add_layout_pin(text=pin_name,
|
||||
layer="m4",
|
||||
offset=lowest_coord + vector(pin_index * supply_pitch, 0),
|
||||
width=pin_width,
|
||||
height=supply_height)
|
||||
|
||||
route_width = pins[0].rx() - lowest_coord.x
|
||||
for pin in pins:
|
||||
pin_offset = vector(lowest_coord.x, pin.by())
|
||||
self.add_rect(pin.layer,
|
||||
pin_offset,
|
||||
route_width,
|
||||
pin.height())
|
||||
center_offset = vector(supply_pin.cx(),
|
||||
pin.cy())
|
||||
self.add_via_center(layers=self.m3_stack,
|
||||
offset=center_offset)
|
||||
else:
|
||||
# Get the lowest, leftest pin
|
||||
pin = rtr.get_ll_pins(pin_name)
|
||||
pin = rtr.get_ll_pin(pin_name)
|
||||
self.add_layout_pin(pin_name,
|
||||
pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
elif OPTS.route_supplies == "tree":
|
||||
# Update these as we may have routed outside the region (perimeter pins)
|
||||
lowest_coord = self.find_lowest_coords()
|
||||
|
||||
# Find the lowest leftest pin for vdd and gnd
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin in self.get_pins(pin_name):
|
||||
self.add_rect(pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
# Remove the pin shape(s)
|
||||
self.remove_layout_pin(pin_name)
|
||||
|
||||
# Get the lowest, leftest pin
|
||||
pin = rtr.get_ll_pin(pin_name)
|
||||
|
||||
pin_width = 2 * getattr(self, "{}_width".format(pin.layer))
|
||||
pin_space = 2 * getattr(self, "{}_space".format(pin.layer))
|
||||
|
||||
# Add it as an IO pin to the perimeter
|
||||
route_width = pin.rx() - lowest_coord.x
|
||||
|
|
@ -311,6 +324,9 @@ class sram_base(design, verilog, lef):
|
|||
pin_offset,
|
||||
pin_width,
|
||||
pin.height())
|
||||
else:
|
||||
# Grid is left with many top level pins
|
||||
pass
|
||||
|
||||
def route_escape_pins(self):
|
||||
"""
|
||||
|
|
@ -355,7 +371,7 @@ class sram_base(design, verilog, lef):
|
|||
from signal_escape_router import signal_escape_router as router
|
||||
rtr=router(layers=self.m3_stack,
|
||||
design=self,
|
||||
margin=4 * self.m3_pitch)
|
||||
margin=8 * self.m3_pitch)
|
||||
rtr.escape_route(pins_to_route)
|
||||
|
||||
def compute_bus_sizes(self):
|
||||
|
|
|
|||
Loading…
Reference in New Issue