Supply tree uses signal grid. PEP8 cleanup.

This commit is contained in:
mrg 2020-12-21 13:51:50 -08:00
parent 98250cf115
commit 348001b1c8
15 changed files with 114 additions and 128 deletions

View File

@ -11,7 +11,7 @@ nominal_corner_only = True
route_supplies = True route_supplies = True
check_lvsdrc = True check_lvsdrc = True
perimeter_pins = True perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False
output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports,

View File

@ -11,8 +11,8 @@ num_w_ports = 0
tech_name = "scn4m_subm" tech_name = "scn4m_subm"
nominal_corner_only = True nominal_corner_only = True
route_supplies = False route_supplies = "tree"
check_lvsdrc = False check_lvsdrc = True
perimeter_pins = False perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False

View File

@ -27,13 +27,14 @@ class router(router_tech):
route on a given layer. This is limited to two layer routes. route on a given layer. This is limited to two layer routes.
It populates blockages on a grid class. It populates blockages on a grid class.
""" """
def __init__(self, layers, design, gds_filename=None, rail_track_width=1): def __init__(self, layers, design, gds_filename=None, route_track_width=1):
""" """
This will instantiate a copy of the gds file or the module at (0,0) and 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 route on top of this. The blockages from the gds/module will be
considered. considered.
""" """
router_tech.__init__(self, layers, rail_track_width)
router_tech.__init__(self, layers, route_track_width)
self.cell = design self.cell = design
@ -1165,6 +1166,14 @@ class router(router_tech):
return keep_pin return keep_pin
def check_all_routed(self, pin_name):
"""
Check that all pin groups are routed.
"""
for pg in self.pin_groups[pin_name]:
if not pg.is_routed():
return False
# FIXME: This should be replaced with vector.snap_to_grid at some point # FIXME: This should be replaced with vector.snap_to_grid at some point
def snap_to_grid(offset): def snap_to_grid(offset):

View File

@ -16,13 +16,13 @@ class router_tech:
""" """
This is a class to hold the router tech constants. This is a class to hold the router tech constants.
""" """
def __init__(self, layers, rail_track_width): def __init__(self, layers, route_track_width):
""" """
Allows us to change the layers that we are routing on. Allows us to change the layers that we are routing on.
This uses the preferreed directions. This uses the preferreed directions.
""" """
self.layers = layers self.layers = layers
self.rail_track_width = rail_track_width self.route_track_width = route_track_width
if len(self.layers) == 1: if len(self.layers) == 1:
self.horiz_layer_name = self.vert_layer_name = self.layers[0] self.horiz_layer_name = self.vert_layer_name = self.layers[0]
@ -123,8 +123,8 @@ class router_tech:
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf) min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
min_width = drc("minwidth_{0}".format(layer_name), self.rail_track_width*min_wire_width, math.inf) min_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.rail_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) return (min_width, min_spacing)

View File

@ -5,7 +5,6 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from itertools import tee
import debug import debug
from heapq import heappush,heappop from heapq import heappush,heappop
from copy import deepcopy from copy import deepcopy
@ -14,6 +13,7 @@ from grid import grid
from grid_path import grid_path from grid_path import grid_path
from vector3d import vector3d from vector3d import vector3d
class signal_grid(grid): class signal_grid(grid):
""" """
Expand the two layer grid to include A* search functions for a source and target. Expand the two layer grid to include A* search functions for a source and target.
@ -34,8 +34,8 @@ class signal_grid(grid):
p.reset() p.reset()
# clear source and target pins # clear source and target pins
self.source=[] self.source = set()
self.target=[] self.target = set()
# Clear the queue # Clear the queue
while len(self.q) > 0: while len(self.q) > 0:
@ -60,7 +60,6 @@ class signal_grid(grid):
heappush(self.q, (cost, self.counter, grid_path([vector3d(s)]))) heappush(self.q, (cost, self.counter, grid_path([vector3d(s)])))
self.counter+=1 self.counter+=1
def route(self, detour_scale): def route(self, detour_scale):
""" """
This does the A* maze routing with preferred direction routing. This does the A* maze routing with preferred direction routing.
@ -83,9 +82,6 @@ class signal_grid(grid):
# Put the source items into the queue # Put the source items into the queue
self.init_queue() self.init_queue()
cheapest_path = None
cheapest_cost = None
# Keep expanding and adding to the priority queue until we are done # Keep expanding and adding to the priority queue until we are done
while len(self.q)>0: while len(self.q)>0:
@ -142,7 +138,6 @@ class signal_grid(grid):
return unblocked_neighbors return unblocked_neighbors
def hpwl(self, src, dest): def hpwl(self, src, dest):
""" """
Return half perimeter wire length from point to another. Return half perimeter wire length from point to another.
@ -167,7 +162,6 @@ class signal_grid(grid):
return cost return cost
def get_inertia(self, p0, p1): def get_inertia(self, p0, p1):
""" """
Sets the direction based on the previous direction we came from. Sets the direction based on the previous direction we came from.

View File

@ -5,15 +5,10 @@
# (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 gdsMill
import tech
from contact import contact
import math
import debug import debug
from pin_layout import pin_layout
from globals import OPTS
from router import router from router import router
class signal_router(router): class signal_router(router):
""" """
A router class to read an obstruction map from a gds and plan a A router class to read an obstruction map from a gds and plan a
@ -27,7 +22,6 @@ class signal_router(router):
""" """
router.__init__(self, layers, design, gds_filename) router.__init__(self, layers, design, gds_filename)
def create_routing_grid(self): def create_routing_grid(self):
""" """
Create a sprase routing grid with A* expansion functions. Create a sprase routing grid with A* expansion functions.
@ -38,8 +32,7 @@ class signal_router(router):
debug.info(1, "Size: {0} x {1}".format(size.x, size.y)) debug.info(1, "Size: {0} x {1}".format(size.x, size.y))
import signal_grid import signal_grid
self.rg = signal_grid.signal_grid(self.ll, self.ur, self.track_width) self.rg = signal_grid.signal_grid(self.ll, self.ur, self.route_track_width)
def route(self, src, dest, detour_scale=5): def route(self, src, dest, detour_scale=5):
""" """

View File

@ -5,12 +5,8 @@
# (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 grid import grid
from signal_grid import signal_grid from signal_grid import signal_grid
from grid_path import grid_path from grid_path import grid_path
from direction import direction
class supply_grid(signal_grid): class supply_grid(signal_grid):
@ -27,13 +23,14 @@ class supply_grid(signal_grid):
def reinit(self): def reinit(self):
""" Reinitialize everything for a new route. """ """ Reinitialize everything for a new route. """
self.source = set() self.source = set()
self.target = set() self.target = set()
# Reset all the cells in the map # Reset all the cells in the map
for p in self.map.values(): for p in self.map.values():
p.reset() p.reset()
def find_start_wave(self, wave, direct): def find_start_wave(self, wave, direct):
""" """
Finds the first loc starting at loc and up that is open. Finds the first loc starting at loc and up that is open.
@ -57,7 +54,6 @@ class supply_grid(signal_grid):
return wave return wave
def is_wave_blocked(self, wave): def is_wave_blocked(self, wave):
""" """
Checks if any of the locations are blocked Checks if any of the locations are blocked
@ -68,7 +64,6 @@ class supply_grid(signal_grid):
else: else:
return False return False
def probe(self, wave, direct): def probe(self, wave, direct):
""" """
Expand the wave until there is a blockage and return Expand the wave until there is a blockage and return

View File

@ -28,9 +28,9 @@ class supply_grid_router(router):
start_time = datetime.now() start_time = datetime.now()
# Power rail width in minimum wire widths # Power rail width in minimum wire widths
self.rail_track_width = 3 self.route_track_width = 3
router.__init__(self, layers, design, gds_filename, self.rail_track_width) router.__init__(self, layers, design, gds_filename, self.route_track_width)
# The list of supply rails (grid sets) that may be routed # The list of supply rails (grid sets) that may be routed
self.supply_rails = {} self.supply_rails = {}
@ -47,7 +47,7 @@ class supply_grid_router(router):
debug.info(1, "Size: {0} x {1}".format(size.x, size.y)) debug.info(1, "Size: {0} x {1}".format(size.x, size.y))
import supply_grid import supply_grid
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width) self.rg = supply_grid.supply_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"):
""" """
@ -104,14 +104,6 @@ class supply_grid_router(router):
return True return True
def check_all_routed(self, pin_name):
"""
Check that all pin groups are routed.
"""
for pg in self.pin_groups[pin_name]:
if not pg.is_routed():
return False
def route_simple_overlaps(self, pin_name): def route_simple_overlaps(self, pin_name):
""" """
This checks for simple cases where a pin component already overlaps a supply rail. This checks for simple cases where a pin component already overlaps a supply rail.
@ -317,7 +309,7 @@ class supply_grid_router(router):
data structure. Return whether it was added or not. data structure. Return whether it was added or not.
""" """
# We must have at least 2 tracks to drop plus 2 tracks for a via # We must have at least 2 tracks to drop plus 2 tracks for a via
if len(wave_path) >= 4 * self.rail_track_width: if len(wave_path) >= 4 * self.route_track_width:
grid_set = wave_path.get_grids() grid_set = wave_path.get_grids()
self.supply_rails[name].append(grid_set) self.supply_rails[name].append(grid_set)
return True return True

View File

@ -26,9 +26,9 @@ class supply_tree_router(router):
either the gds file name or the design itself (by saving to a gds file). either the gds file name or the design itself (by saving to a gds file).
""" """
# Power rail width in minimum wire widths # Power rail width in minimum wire widths
self.rail_track_width = 3 self.route_track_width = 3
router.__init__(self, layers, design, gds_filename, self.rail_track_width) router.__init__(self, layers, design, gds_filename, self.route_track_width)
def create_routing_grid(self): def create_routing_grid(self):
""" """
@ -37,8 +37,8 @@ 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))
import supply_grid import signal_grid
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width) 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"):
""" """
@ -85,15 +85,6 @@ class supply_tree_router(router):
return True return True
def check_all_routed(self, pin_name):
"""
Check that all pin groups are routed.
"""
for pg in self.pin_groups[pin_name]:
if not pg.is_routed():
return False
def prepare_blockages(self, pin_name): def prepare_blockages(self, pin_name):
""" """
Reset and add all of the blockages in the design. Reset and add all of the blockages in the design.
@ -125,7 +116,6 @@ class supply_tree_router(router):
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids} blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
self.set_blockages(blockage_grids,False) self.set_blockages(blockage_grids,False)
def route_pins(self, pin_name): def route_pins(self, pin_name):
""" """
This will route each of the remaining pin components to the other pins. This will route each of the remaining pin components to the other pins.
@ -137,6 +127,7 @@ class supply_tree_router(router):
remaining_components)) remaining_components))
# Create full graph # Create full graph
debug.info(2,"Creating adjacency matrix")
pin_size = len(self.pin_groups[pin_name]) pin_size = len(self.pin_groups[pin_name])
adj_matrix = [[0] * pin_size for i in range(pin_size)] adj_matrix = [[0] * pin_size for i in range(pin_size)]
@ -148,6 +139,7 @@ class supply_tree_router(router):
adj_matrix[index1][index2] = dist adj_matrix[index1][index2] = dist
# Find MST # Find MST
debug.info(2,"Finding MinimumSpanning Tree")
X = csr_matrix(adj_matrix) X = csr_matrix(adj_matrix)
Tcsr = minimum_spanning_tree(X) Tcsr = minimum_spanning_tree(X)
mst = Tcsr.toarray().astype(int) mst = Tcsr.toarray().astype(int)

View File

@ -87,6 +87,17 @@ class sram():
def save(self): def save(self):
""" Save all the output files while reporting time to do it as well. """ """ Save all the output files while reporting time to do it as well. """
# Save the spice file
start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp"
debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname)
functional(self.s,
os.path.basename(spname),
cycles=200,
output_path=OPTS.output_path)
print_time("Spice writing", datetime.datetime.now(), start_time)
if not OPTS.netlist_only: if not OPTS.netlist_only:
# Write the layout # Write the layout
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
@ -107,17 +118,6 @@ class sram():
self.lef_write(lefname) self.lef_write(lefname)
print_time("LEF", datetime.datetime.now(), start_time) print_time("LEF", datetime.datetime.now(), start_time)
# Save the spice file
start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp"
debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname)
functional(self.s,
os.path.basename(spname),
cycles=200,
output_path=OPTS.output_path)
print_time("Spice writing", datetime.datetime.now(), start_time)
# Save the LVS file # Save the LVS file
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
lvsname = OPTS.output_path + self.s.name + ".lvs.sp" lvsname = OPTS.output_path + self.s.name + ".lvs.sp"

View File

@ -5,7 +5,6 @@
# (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 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
@ -102,12 +101,17 @@ class sram_1bank(sram_base):
# Place with an initial wide channel (from above) # Place with an initial wide channel (from above)
self.place_dffs() self.place_dffs()
# Route the channel and set to the new data bus size # Route the channel and set to the new data bus size
# 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.route_dffs(add_routes=False) self.route_dffs(add_routes=False)
self.remove_layout_pins()
# Re-place with the new channel size # Re-place with the new channel size
self.place_dffs() self.place_dffs()
# Now route the channel
self.route_dffs()
def place_row_addr_dffs(self): def place_row_addr_dffs(self):
""" """
@ -298,8 +302,9 @@ class sram_1bank(sram_base):
"din{0}[{1}]".format(port, bit)) "din{0}[{1}]".format(port, bit))
# Data output pins go to BOTTOM/TOP # Data output pins go to BOTTOM/TOP
if port in self.readwrite_ports and OPTS.perimeter_pins: if port in self.readwrite_ports:
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
if OPTS.perimeter_pins:
# This should be routed next to the din pin # This should be routed next to the din pin
p = din_ports[bit] p = din_ports[bit]
self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(port, bit), self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(port, bit),
@ -307,6 +312,10 @@ class sram_1bank(sram_base):
offset=p.center() + vector(self.m3_pitch, 0), offset=p.center() + vector(self.m3_pitch, 0),
width=p.width(), width=p.width(),
height=p.height()) height=p.height())
else:
self.copy_layout_pin(self.bank_inst,
"dout{0}_{1}".format(port, bit),
"dout{0}[{1}]".format(port, bit))
elif port in self.read_ports: elif port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
if OPTS.perimeter_pins: if OPTS.perimeter_pins:
@ -384,6 +393,8 @@ class sram_1bank(sram_base):
self.route_row_addr_dff() self.route_row_addr_dff()
self.route_dffs()
def route_dffs(self, add_routes=True): def route_dffs(self, add_routes=True):
for port in self.all_ports: for port in self.all_ports:

View File

@ -11,7 +11,9 @@ num_words = 16
tech_name = OPTS.tech_name tech_name = OPTS.tech_name
# perimeter_pins = True
nominal_corner_only = True nominal_corner_only = True
route_supplies = "tree" route_supplies = "grid"
check_lvsdrc = True check_lvsdrc = True

View File

@ -23,7 +23,6 @@ from tech import lvs_name
from tech import pex_name from tech import pex_name
debug.info(1, "Initializing verify...") debug.info(1, "Initializing verify...")
if not OPTS.check_lvsdrc: if not OPTS.check_lvsdrc:
debug.info(1, "LVS/DRC/PEX disabled.") debug.info(1, "LVS/DRC/PEX disabled.")
OPTS.drc_exe = None OPTS.drc_exe = None

View File

@ -68,7 +68,6 @@ num_pex_runs = 0
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path, sp_name=None): def write_drc_script(cell_name, gds_name, extract, final_verification, output_path, sp_name=None):
""" Write a magic script to perform DRC and optionally extraction. """ """ Write a magic script to perform DRC and optionally extraction. """
global OPTS global OPTS
# Copy .magicrc file into the output directory # Copy .magicrc file into the output directory

View File

@ -17,8 +17,8 @@ lvs_warned = False
pex_warned = False pex_warned = False
def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None): def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None, sp_name=None):
pass debug.error("Cannot write DRC script for unknown tool", -1)
def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False, output_path=None): def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False, output_path=None):