Cleanup exit route. Pins are on perimeter mostly.

This commit is contained in:
mrg 2020-12-22 15:56:51 -08:00
parent ae1c889235
commit 52119fe3b3
9 changed files with 131 additions and 34 deletions

View File

@ -473,6 +473,17 @@ class layout():
""" """
self.pin_map = {} 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): def add_layout_pin(self, text, layer, offset, width=None, height=None):
""" """
Create a labeled pin Create a labeled pin

View File

@ -5,13 +5,12 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import debug
from vector3d import vector3d from vector3d import vector3d
from itertools import tee from itertools import tee
from grid import grid from grid import grid
from grid_cell import grid_cell
from direction import direction from direction import direction
class grid_path: class grid_path:
""" """
A grid path is a list of lists of grid cells. A grid path is a list of lists of grid cells.
@ -29,8 +28,7 @@ class grid_path:
self.pathlist = [] self.pathlist = []
def __str__(self): def __str__(self):
#import pprint p = str(self.pathlist)
p = str(self.pathlist) #pprint.pformat(self.pathlist)
if self.name != "": if self.name != "":
return (str(self.name) + " : " + p) return (str(self.name) + " : " + p)
return p return p
@ -188,12 +186,10 @@ class grid_path:
return newwave return newwave
def set_layer(self, zindex): def set_layer(self, zindex):
new_pathlist = [vector3d(item.x, item.y, zindex) for wave in self.pathlist for item in wave] new_pathlist = [vector3d(item.x, item.y, zindex) for wave in self.pathlist for item in wave]
self.pathlist = new_pathlist self.pathlist = new_pathlist
def overlap(self, other): def overlap(self, other):
""" """
Return the overlap waves ignoring different layers Return the overlap waves ignoring different layers

View File

@ -9,7 +9,6 @@
Some utility functions for sets of grid cells. Some utility functions for sets of grid cells.
""" """
import debug
import math import math
from direction import direction from direction import direction
from vector3d import vector3d from vector3d import vector3d
@ -44,6 +43,7 @@ def get_upper_right(curset):
ur = p ur = p
return ur return ur
def get_lower_left(curset): def get_lower_left(curset):
ll = None ll = None
for p in curset: for p in curset:
@ -51,7 +51,8 @@ def get_lower_left(curset):
ll = p ll = p
return ll return ll
def get_border( curset, direct):
def get_border(curset, direct):
""" """
Return the furthest cell(s) in a given direction. Return the furthest cell(s) in a given direction.
""" """
@ -86,6 +87,7 @@ def get_border( curset, direct):
newset = set(maxc) newset = set(maxc)
return newset return newset
def expand_border(curset, direct): def expand_border(curset, direct):
""" """
Expand the current set of sells in a given direction. 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) next_border_set = increment_set(border_set, direct)
return next_border_set return next_border_set
def expand_borders(curset): def expand_borders(curset):
""" """
Return the expansions in planar directions. Return the expansions in planar directions.
@ -106,6 +109,7 @@ def expand_borders(curset):
return(north_set, east_set, south_set, west_set) return(north_set, east_set, south_set, west_set)
def inflate_cell(cell, distance): def inflate_cell(cell, distance):
""" """
Expand the current cell in all directions and return the set. Expand the current cell in all directions and return the set.
@ -122,6 +126,7 @@ def inflate_cell(cell, distance):
return newset return newset
def inflate_set(curset, distance): def inflate_set(curset, distance):
""" """
Expand the set in all directions by the given number of grids. 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 # Recurse with less depth
return inflate_set(newset,distance-1) return inflate_set(newset,distance-1)
def flatten_set(curset): def flatten_set(curset):
""" """
Flatten until we have a set of vector3d objects. Flatten until we have a set of vector3d objects.
@ -149,7 +155,6 @@ def flatten_set(curset):
return newset return newset
def distance_set(coord, curset): def distance_set(coord, curset):
""" """
Return the distance from a coordinate to any item in the set Return the distance from a coordinate to any item in the set

View File

@ -493,7 +493,6 @@ class pin_group:
debug.error("Could not find a connector for {} with {}".format(self.pins, debug.error("Could not find a connector for {} with {}".format(self.pins,
self.enclosures)) self.enclosures))
self.router.write_debug_gds("no_connector.gds") self.router.write_debug_gds("no_connector.gds")
import pdb; pdb.set_trace()
self.enclosures.append(connector) self.enclosures.append(connector)
# At this point, the pins are overlapping, # At this point, the pins are overlapping,

View File

@ -1022,11 +1022,10 @@ class router(router_tech):
if path: if path:
debug.info(2, "Found path: cost={0} {1}".format(cost, str(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) self.add_route(path)
path_set = grid_utils.flatten_set(path) self.path_blockages.append(self.paths[-1])
self.path_blockages.append(path_set)
return True return True
else: else:
return False return False
@ -1133,7 +1132,7 @@ class router(router_tech):
show_all_grids = True show_all_grids = True
if show_all_grids: if show_all_grids:
self.rg.add_all_grids() #self.rg.add_all_grids()
for g in self.rg.map: for g in self.rg.map:
self.annotate_grid(g) self.annotate_grid(g)
@ -1167,6 +1166,14 @@ class router(router_tech):
width=pin.width(), width=pin.width(),
height=pin.height()) 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): def get_pin(self, pin_name):
""" Return the lowest, leftest pin group """ """ Return the lowest, leftest pin group """
keep_pin = None keep_pin = None

View File

@ -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)

View File

@ -12,7 +12,7 @@ from datetime import datetime
import grid_utils import grid_utils
from scipy.sparse import csr_matrix from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import minimum_spanning_tree from scipy.sparse.csgraph import minimum_spanning_tree
from signal_grid import signal_grid
class supply_tree_router(router): class supply_tree_router(router):
""" """
@ -36,9 +36,7 @@ class supply_tree_router(router):
""" """
size = self.ur - self.ll size = self.ur - self.ll
debug.info(1,"Size: {0} x {1}".format(size.x,size.y)) debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
self.rg = signal_grid(self.ll, self.ur, self.route_track_width)
import signal_grid
self.rg = signal_grid.signal_grid(self.ll, self.ur, self.route_track_width)
def route(self, vdd_name="vdd", gnd_name="gnd"): def route(self, vdd_name="vdd", gnd_name="gnd"):
""" """

View File

@ -8,7 +8,6 @@
from vector import vector from vector import vector
from sram_base import sram_base from sram_base import sram_base
from contact import m2_via from contact import m2_via
from globals import OPTS
import channel_route import channel_route
@ -106,7 +105,7 @@ class sram_1bank(sram_base):
# We need to temporarily add some pins for the x offsets # We need to temporarily add some pins for the x offsets
# but we'll remove them so that they have the right y # but we'll remove them so that they have the right y
# offsets after the DFF placement. # offsets after the DFF placement.
self.add_layout_pins() self.add_layout_pins(exit_route=False)
self.route_dffs(add_routes=False) self.route_dffs(add_routes=False)
self.remove_layout_pins() self.remove_layout_pins()
@ -245,7 +244,7 @@ class sram_1bank(sram_base):
self.data_pos[port] = vector(x_offset, y_offset) self.data_pos[port] = vector(x_offset, y_offset)
self.spare_wen_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. 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)) "spare_wen{0}[{1}]".format(port, bit))
all_pins.append(("spare_wen{0}[{1}]".format(port, bit), bottom_or_top)) 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 from signal_exit_router import signal_exit_router as router
rtr=router(self.m3_stack, self) rtr=router(self.m3_stack, self)
rtr.route(all_pins) rtr.exit_route(all_pins)
def route_layout(self): def route_layout(self):
""" Route a single bank SRAM """ """ Route a single bank SRAM """
self.route_supplies()
self.add_layout_pins() self.add_layout_pins()
self.route_clk() self.route_clk()
@ -329,6 +330,7 @@ class sram_1bank(sram_base):
self.route_row_addr_dff() self.route_row_addr_dff()
self.route_dffs() self.route_dffs()
def route_dffs(self, add_routes=True): 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] bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
route_map.extend(list(zip(bank_pins, dff_pins))) 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 # spare wen dff
if self.num_spare_cols > 0 and port in self.write_ports: 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)] dff_names = ["dout_{}".format(x) for x in range(self.num_spare_cols)]

View File

@ -190,7 +190,7 @@ class sram_base(design, verilog, lef):
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
self.route_layout() self.route_layout()
self.route_supplies()
if not OPTS.is_unit_test: if not OPTS.is_unit_test:
print_time("Routing", datetime.datetime.now(), start_time) print_time("Routing", datetime.datetime.now(), start_time)