mirror of https://github.com/VLSIDA/OpenRAM.git
Cleanup exit route. Pins are on perimeter mostly.
This commit is contained in:
parent
ae1c889235
commit
52119fe3b3
|
|
@ -473,6 +473,17 @@ class layout():
|
|||
"""
|
||||
self.pin_map = {}
|
||||
|
||||
def replace_layout_pin(self, text, pin):
|
||||
"""
|
||||
Remove the old pin and replace with a new one
|
||||
"""
|
||||
self.remove_layout_pin(text)
|
||||
self.add_layout_pin(text=text,
|
||||
layer=pin.layer,
|
||||
offset=pin.ll(),
|
||||
width=pin.width(),
|
||||
height=pin.height())
|
||||
|
||||
def add_layout_pin(self, text, layer, offset, width=None, height=None):
|
||||
"""
|
||||
Create a labeled pin
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector3d import vector3d
|
||||
from itertools import tee
|
||||
from grid import grid
|
||||
from grid_cell import grid_cell
|
||||
from direction import direction
|
||||
|
||||
|
||||
class grid_path:
|
||||
"""
|
||||
A grid path is a list of lists of grid cells.
|
||||
|
|
@ -29,8 +28,7 @@ class grid_path:
|
|||
self.pathlist = []
|
||||
|
||||
def __str__(self):
|
||||
#import pprint
|
||||
p = str(self.pathlist) #pprint.pformat(self.pathlist)
|
||||
p = str(self.pathlist)
|
||||
if self.name != "":
|
||||
return (str(self.name) + " : " + p)
|
||||
return p
|
||||
|
|
@ -188,12 +186,10 @@ class grid_path:
|
|||
|
||||
return newwave
|
||||
|
||||
|
||||
def set_layer(self, zindex):
|
||||
new_pathlist = [vector3d(item.x, item.y, zindex) for wave in self.pathlist for item in wave]
|
||||
self.pathlist = new_pathlist
|
||||
|
||||
|
||||
def overlap(self, other):
|
||||
"""
|
||||
Return the overlap waves ignoring different layers
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
Some utility functions for sets of grid cells.
|
||||
"""
|
||||
|
||||
import debug
|
||||
import math
|
||||
from direction import direction
|
||||
from vector3d import vector3d
|
||||
|
|
@ -44,6 +43,7 @@ def get_upper_right(curset):
|
|||
ur = p
|
||||
return ur
|
||||
|
||||
|
||||
def get_lower_left(curset):
|
||||
ll = None
|
||||
for p in curset:
|
||||
|
|
@ -51,7 +51,8 @@ def get_lower_left(curset):
|
|||
ll = p
|
||||
return ll
|
||||
|
||||
def get_border( curset, direct):
|
||||
|
||||
def get_border(curset, direct):
|
||||
"""
|
||||
Return the furthest cell(s) in a given direction.
|
||||
"""
|
||||
|
|
@ -86,6 +87,7 @@ def get_border( curset, direct):
|
|||
newset = set(maxc)
|
||||
return newset
|
||||
|
||||
|
||||
def expand_border(curset, direct):
|
||||
"""
|
||||
Expand the current set of sells in a given direction.
|
||||
|
|
@ -95,6 +97,7 @@ def expand_border(curset, direct):
|
|||
next_border_set = increment_set(border_set, direct)
|
||||
return next_border_set
|
||||
|
||||
|
||||
def expand_borders(curset):
|
||||
"""
|
||||
Return the expansions in planar directions.
|
||||
|
|
@ -106,6 +109,7 @@ def expand_borders(curset):
|
|||
|
||||
return(north_set, east_set, south_set, west_set)
|
||||
|
||||
|
||||
def inflate_cell(cell, distance):
|
||||
"""
|
||||
Expand the current cell in all directions and return the set.
|
||||
|
|
@ -122,6 +126,7 @@ def inflate_cell(cell, distance):
|
|||
|
||||
return newset
|
||||
|
||||
|
||||
def inflate_set(curset, distance):
|
||||
"""
|
||||
Expand the set in all directions by the given number of grids.
|
||||
|
|
@ -136,6 +141,7 @@ def inflate_set(curset, distance):
|
|||
# Recurse with less depth
|
||||
return inflate_set(newset,distance-1)
|
||||
|
||||
|
||||
def flatten_set(curset):
|
||||
"""
|
||||
Flatten until we have a set of vector3d objects.
|
||||
|
|
@ -149,7 +155,6 @@ def flatten_set(curset):
|
|||
return newset
|
||||
|
||||
|
||||
|
||||
def distance_set(coord, curset):
|
||||
"""
|
||||
Return the distance from a coordinate to any item in the set
|
||||
|
|
|
|||
|
|
@ -493,7 +493,6 @@ class pin_group:
|
|||
debug.error("Could not find a connector for {} with {}".format(self.pins,
|
||||
self.enclosures))
|
||||
self.router.write_debug_gds("no_connector.gds")
|
||||
import pdb; pdb.set_trace()
|
||||
self.enclosures.append(connector)
|
||||
|
||||
# At this point, the pins are overlapping,
|
||||
|
|
|
|||
|
|
@ -1022,11 +1022,10 @@ class router(router_tech):
|
|||
if path:
|
||||
debug.info(2, "Found path: cost={0} {1}".format(cost, str(path)))
|
||||
|
||||
self.paths.append(path)
|
||||
self.paths.append(grid_utils.flatten_set(path))
|
||||
self.add_route(path)
|
||||
|
||||
path_set = grid_utils.flatten_set(path)
|
||||
self.path_blockages.append(path_set)
|
||||
self.path_blockages.append(self.paths[-1])
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
@ -1133,7 +1132,7 @@ class router(router_tech):
|
|||
show_all_grids = True
|
||||
|
||||
if show_all_grids:
|
||||
self.rg.add_all_grids()
|
||||
#self.rg.add_all_grids()
|
||||
for g in self.rg.map:
|
||||
self.annotate_grid(g)
|
||||
|
||||
|
|
@ -1167,6 +1166,14 @@ class router(router_tech):
|
|||
width=pin.width(),
|
||||
height=pin.height())
|
||||
|
||||
def get_perimeter_pin(self):
|
||||
""" Return the shape of the last routed path that was on the perimeter """
|
||||
for v in self.paths[-1]:
|
||||
if self.rg.is_target(v):
|
||||
return self.convert_track_to_pin(v)
|
||||
|
||||
return None
|
||||
|
||||
def get_pin(self, pin_name):
|
||||
""" Return the lowest, leftest pin group """
|
||||
keep_pin = None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from globals import print_time
|
||||
from router import router
|
||||
from datetime import datetime
|
||||
from supply_grid import supply_grid
|
||||
|
||||
class signal_exit_router(router):
|
||||
"""
|
||||
A router that routes signals to perimeter and makes pins.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=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, 1)
|
||||
|
||||
def create_routing_grid(self):
|
||||
"""
|
||||
Create a sprase routing grid with A* expansion functions.
|
||||
"""
|
||||
size = self.ur - self.ll
|
||||
debug.info(1,"Size: {0} x {1}".format(size.x, size.y))
|
||||
self.rg = supply_grid(self.ll, self.ur, self.track_width)
|
||||
|
||||
def exit_route(self, pin_list):
|
||||
"""
|
||||
Takes a list of tuples (name, side) and routes them. After routing,
|
||||
it removes the old pin and places a new one on the perimeter.
|
||||
"""
|
||||
pin_names = [x[0] for x in pin_list]
|
||||
|
||||
# Clear the pins if we have previously routed
|
||||
if (hasattr(self,'rg')):
|
||||
self.clear_pins()
|
||||
else:
|
||||
self.create_routing_grid()
|
||||
|
||||
# Get the pin shapes
|
||||
start_time = datetime.now()
|
||||
self.find_pins_and_blockages(pin_names)
|
||||
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
||||
|
||||
# Route the supply pins to the supply rails
|
||||
# Route vdd first since we want it to be shorter
|
||||
start_time = datetime.now()
|
||||
for pin_name, side in pin_list:
|
||||
self.route_signal(pin_name, side)
|
||||
|
||||
print_time("Maze routing pins",datetime.now(), start_time, 3)
|
||||
|
||||
return True
|
||||
|
||||
def route_signal(self, pin_name, side):
|
||||
|
||||
for detour_scale in [5 * pow(2, x) for x in range(5)]:
|
||||
debug.info(1, "Exit routing {0} with scale {1}".format(pin_name, detour_scale))
|
||||
|
||||
# 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
|
||||
# which unmarks it as a blockage too
|
||||
self.add_source(pin_name)
|
||||
|
||||
# Marks the grid cells all along the perimeter as a target
|
||||
self.add_perimeter_target(side)
|
||||
|
||||
# Actually run the A* router
|
||||
if self.run_router(detour_scale=detour_scale):
|
||||
new_pin = self.get_perimeter_pin()
|
||||
self.cell.replace_layout_pin(pin_name, new_pin)
|
||||
return
|
||||
|
||||
self.write_debug_gds("debug_route.gds", True)
|
||||
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ from datetime import datetime
|
|||
import grid_utils
|
||||
from scipy.sparse import csr_matrix
|
||||
from scipy.sparse.csgraph import minimum_spanning_tree
|
||||
|
||||
from signal_grid import signal_grid
|
||||
|
||||
class supply_tree_router(router):
|
||||
"""
|
||||
|
|
@ -36,9 +36,7 @@ class supply_tree_router(router):
|
|||
"""
|
||||
size = self.ur - self.ll
|
||||
debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
|
||||
|
||||
import signal_grid
|
||||
self.rg = signal_grid.signal_grid(self.ll, self.ur, self.route_track_width)
|
||||
self.rg = signal_grid(self.ll, self.ur, self.route_track_width)
|
||||
|
||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
from vector import vector
|
||||
from sram_base import sram_base
|
||||
from contact import m2_via
|
||||
from globals import OPTS
|
||||
import channel_route
|
||||
|
||||
|
||||
|
|
@ -106,7 +105,7 @@ class sram_1bank(sram_base):
|
|||
# We need to temporarily add some pins for the x offsets
|
||||
# but we'll remove them so that they have the right y
|
||||
# offsets after the DFF placement.
|
||||
self.add_layout_pins()
|
||||
self.add_layout_pins(exit_route=False)
|
||||
self.route_dffs(add_routes=False)
|
||||
self.remove_layout_pins()
|
||||
|
||||
|
|
@ -245,7 +244,7 @@ class sram_1bank(sram_base):
|
|||
self.data_pos[port] = vector(x_offset, y_offset)
|
||||
self.spare_wen_pos[port] = vector(x_offset, y_offset)
|
||||
|
||||
def add_layout_pins(self):
|
||||
def add_layout_pins(self, exit_route=True):
|
||||
"""
|
||||
Add the top-level pins for a single bank SRAM with control.
|
||||
"""
|
||||
|
|
@ -312,14 +311,16 @@ class sram_1bank(sram_base):
|
|||
"spare_wen{0}[{1}]".format(port, bit))
|
||||
all_pins.append(("spare_wen{0}[{1}]".format(port, bit), bottom_or_top))
|
||||
|
||||
if OPTS.perimeter_pins:
|
||||
if exit_route:
|
||||
from signal_exit_router import signal_exit_router as router
|
||||
rtr=router(self.m3_stack, self)
|
||||
rtr.route(all_pins)
|
||||
rtr.exit_route(all_pins)
|
||||
|
||||
def route_layout(self):
|
||||
""" Route a single bank SRAM """
|
||||
|
||||
self.route_supplies()
|
||||
|
||||
self.add_layout_pins()
|
||||
|
||||
self.route_clk()
|
||||
|
|
@ -329,6 +330,7 @@ class sram_1bank(sram_base):
|
|||
self.route_row_addr_dff()
|
||||
|
||||
self.route_dffs()
|
||||
|
||||
|
||||
def route_dffs(self, add_routes=True):
|
||||
|
||||
|
|
@ -364,16 +366,6 @@ class sram_1bank(sram_base):
|
|||
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||
route_map.extend(list(zip(bank_pins, dff_pins)))
|
||||
|
||||
if port in self.readwrite_ports and OPTS.perimeter_pins:
|
||||
# outputs from sense amp
|
||||
# These are the output pins which had their pin placed on the perimeter, so route from the
|
||||
# sense amp which should not align with write driver input
|
||||
sram_names = ["dout{0}[{1}]".format(port, x) for x in range(self.word_size + self.num_spare_cols)]
|
||||
sram_pins = [self.get_pin(x) for x in sram_names]
|
||||
bank_names = ["dout{0}_{1}".format(port, x) for x in range(self.word_size + self.num_spare_cols)]
|
||||
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||
route_map.extend(list(zip(bank_pins, sram_pins)))
|
||||
|
||||
# spare wen dff
|
||||
if self.num_spare_cols > 0 and port in self.write_ports:
|
||||
dff_names = ["dout_{}".format(x) for x in range(self.num_spare_cols)]
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ class sram_base(design, verilog, lef):
|
|||
|
||||
start_time = datetime.datetime.now()
|
||||
self.route_layout()
|
||||
self.route_supplies()
|
||||
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Routing", datetime.datetime.now(), start_time)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue