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 = {}
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

View File

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

View File

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

View File

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

View File

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

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
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"):
"""

View File

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

View File

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