Begin single layer supply router

This commit is contained in:
mrg 2019-05-27 17:38:59 -07:00
parent 4612c9c182
commit bd4d965e37
7 changed files with 224 additions and 45 deletions

View File

@ -26,16 +26,17 @@ class design(hierarchy_design):
self.setup_drc_constants() self.setup_drc_constants()
self.setup_multiport_constants() self.setup_multiport_constants()
from tech import layer
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space) self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space)
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space) self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space)
if contact.m3m4: if "metal4" in layer:
self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space) self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space)
else: else:
self.m3_pitch = self.m2_pitch self.m3_pitch = self.m2_pitch
def setup_drc_constants(self): def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler.""" """ These are some DRC constants used in many places in the compiler."""
from tech import drc from tech import drc,layer
self.well_width = drc("minwidth_well") self.well_width = drc("minwidth_well")
self.poly_width = drc("minwidth_poly") self.poly_width = drc("minwidth_poly")
self.poly_space = drc("poly_to_poly") self.poly_space = drc("poly_to_poly")
@ -45,7 +46,7 @@ class design(hierarchy_design):
self.m2_space = drc("metal2_to_metal2") self.m2_space = drc("metal2_to_metal2")
self.m3_width = drc("minwidth_metal3") self.m3_width = drc("minwidth_metal3")
self.m3_space = drc("metal3_to_metal3") self.m3_space = drc("metal3_to_metal3")
if contact.m3m4: if "metal4" in layer:
self.m4_width = drc("minwidth_metal4") self.m4_width = drc("minwidth_metal4")
self.m4_space = drc("metal4_to_metal4") self.m4_space = drc("metal4_to_metal4")
self.active_width = drc("minwidth_active") self.active_width = drc("minwidth_active")

View File

@ -45,3 +45,4 @@ class design_rules():

View File

@ -839,6 +839,15 @@ class router(router_tech):
self.rg.add_target(pin_in_tracks) self.rg.add_target(pin_in_tracks)
def add_pin_component_target_except(self, pin_name, index):
"""
This will mark the grids for all *other* pin components as a target.
Marking as source or target also clears blockage status.
"""
for i in range(self.num_pin_components(pin_name)):
if i != index:
self.add_pin_component_target(pin_name, i)
def set_component_blockages(self, pin_name, value=True): def set_component_blockages(self, pin_name, value=True):
""" """
Block all of the pin components. Block all of the pin components.

View File

@ -24,16 +24,25 @@ class router_tech:
""" """
self.layers = layers self.layers = layers
self.rail_track_width = rail_track_width self.rail_track_width = rail_track_width
print(self.layers,len(self.layers))
if len(self.layers)==1:
self.horiz_layer_name = self.vert_layer_name = self.layers[0]
self.horiz_layer_number = self.vert_layer_number = layer[self.layers[0]]
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing
self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
else:
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers (self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
# This is the minimum routed track spacing
via_connect = contact(self.layers, (1, 1)) via_connect = contact(self.layers, (1, 1))
max_via_size = max(via_connect.width,via_connect.height) max_via_size = max(via_connect.width,via_connect.height)
self.horiz_layer_number = layer[self.horiz_layer_name] self.horiz_layer_number = layer[self.horiz_layer_name]
self.vert_layer_number = layer[self.vert_layer_name] self.vert_layer_number = layer[self.vert_layer_name]
if self.rail_track_width>1:
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
@ -44,13 +53,6 @@ class router_tech:
self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing
self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
else:
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_layer_width_space(0)
self.horiz_track_width = max_via_size + self.horiz_layer_spacing
self.vert_track_width = max_via_size + self.vert_layer_spacing
# We'll keep horizontal and vertical tracks the same for simplicity. # We'll keep horizontal and vertical tracks the same for simplicity.
self.track_width = max(self.horiz_track_width,self.vert_track_width) self.track_width = max(self.horiz_track_width,self.vert_track_width)
debug.info(1,"Track width: {:.3f}".format(self.track_width)) debug.info(1,"Track width: {:.3f}".format(self.track_width))
@ -80,24 +82,6 @@ class router_tech:
else: else:
debug.error("Invalid zindex {}".format(zindex),-1) debug.error("Invalid zindex {}".format(zindex),-1)
def get_layer_width_space(self, zindex, width=0, length=0):
"""
Return the width and spacing of a given layer
and wire of a given width and length.
"""
if zindex==1:
layer_name = self.vert_layer_name
elif zindex==0:
layer_name = self.horiz_layer_name
else:
debug.error("Invalid zindex for track", -1)
min_width = drc("minwidth_{0}".format(layer_name), width, length)
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length)
return (min_width,min_spacing)
def get_supply_layer_width_space(self, zindex): def get_supply_layer_width_space(self, zindex):
""" """
These are the width and spacing of a supply layer given a supply rail These are the width and spacing of a supply layer given a supply rail

View File

@ -20,7 +20,7 @@ from datetime import datetime
import grid import grid
import grid_utils import grid_utils
class supply_router(router): class supply_grid_router(router):
""" """
A router class to read an obstruction map from a gds and A router class to read an obstruction map from a gds and
routes a grid to connect the supply on the two layers. routes a grid to connect the supply on the two layers.
@ -391,7 +391,7 @@ class supply_router(router):
# Add the single component of the pin as the source # Add the single component of the pin as the source
# which unmarks it as a blockage too # which unmarks it as a blockage too
self.add_pin_component_source(pin_name,index) self.add_pin_component_source(pin_name, index)
# Add all of the rails as targets # Add all of the rails as targets
# Don't add the other pins, but we could? # Don't add the other pins, but we could?

View File

@ -0,0 +1,176 @@
# 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 gdsMill
import tech
import math
import debug
from globals import OPTS,print_time
from contact import contact
from pin_group import pin_group
from pin_layout import pin_layout
from vector3d import vector3d
from router import router
from direction import direction
from datetime import datetime
import grid
import grid_utils
class supply_tree_router(router):
"""
A router class to read an obstruction map from a gds and
routes a grid to connect the supply on the two layers.
"""
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).
"""
# Power rail width in minimum wire widths
self.rail_track_width = 3
router.__init__(self, layers, design, gds_filename, self.rail_track_width)
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))
import supply_grid
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width)
def route(self, vdd_name="vdd", gnd_name="gnd"):
"""
Route the two nets in a single layer)
"""
debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
self.vdd_name = vdd_name
self.gnd_name = gnd_name
# Clear the pins if we have previously routed
if (hasattr(self,'rg')):
self.clear_pins()
else:
# Creat a routing grid over the entire area
# FIXME: This could be created only over the routing region,
# but this is simplest for now.
self.create_routing_grid()
# Get the pin shapes
start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
# Add the supply rails in a mesh network and connect H/V with vias
start_time = datetime.now()
# Block everything
self.prepare_blockages(self.gnd_name)
self.prepare_blockages(self.vdd_name)
# Route the supply pins to the supply rails
# Route vdd first since we want it to be shorter
start_time = datetime.now()
self.route_pins(vdd_name)
self.route_pins(gnd_name)
print_time("Maze routing supplies",datetime.now(), start_time, 3)
#self.write_debug_gds("final.gds",False)
# Did we route everything??
if not self.check_all_routed(vdd_name):
return False
if not self.check_all_routed(gnd_name):
return False
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):
"""
Reset and add all of the blockages in the design.
Names is a list of pins to add as a blockage.
"""
debug.info(3,"Preparing blockages.")
# Start fresh. Not the best for run-time, but simpler.
self.clear_blockages()
# This adds the initial blockges of the design
#print("BLOCKING:",self.blocked_grids)
self.set_blockages(self.blocked_grids,True)
# Block all of the pin components (some will be unblocked if they're a source/target)
# Also block the previous routes
for name in self.pin_groups:
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
self.set_blockages(blockage_grids,True)
blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages}
self.set_blockages(blockage_grids,True)
# FIXME: These duplicate a bit of work
# These are the paths that have already been routed.
self.set_blockages(self.path_blockages)
# Don't mark the other components as targets since we want to route
# directly to a rail, but unblock all the source components so we can
# route over them
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
self.set_blockages(blockage_grids,False)
def route_pins(self, pin_name):
"""
This will route each of the remaining pin components to the other pins.
After it is done, the cells are added to the pin blockage list.
"""
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
debug.info(1,"Maze routing {0} with {1} pin components to connect.".format(pin_name,
remaining_components))
for index,pg in enumerate(self.pin_groups[pin_name]):
if pg.is_routed():
continue
debug.info(3,"Routing component {0} {1}".format(pin_name, index))
# 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_pin_component_source(pin_name,index)
# Marks all pin components except index as target
self.add_pin_component_target_except(pin_name,index)
# Actually run the A* router
if not self.run_router(detour_scale=5):
self.write_debug_gds("debug_route.gds",False)
#if index==3 and pin_name=="vdd":
# self.write_debug_gds("route.gds",False)

View File

@ -134,18 +134,26 @@ class sram_base(design, verilog, lef):
for inst in self.insts: for inst in self.insts:
self.copy_power_pins(inst,"vdd") self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd") self.copy_power_pins(inst,"gnd")
# Do not route the power supply
if not OPTS.route_supplies:
return
from supply_router import supply_router as router
layer_stack =("metal3","via3","metal4") import tech
rtr=router(layer_stack, self) if not OPTS.route_supplies:
# Do not route the power supply (leave as must-connect pins)
return
elif "metal4" in tech.layer:
# Route a M3/M4 grid
from supply_grid_router import supply_grid_router as router
rtr=router(("metal3","via3","metal4"), self)
elif "metal3" in tech.layer:
from supply_tree_router import supply_tree_router as router
rtr=router(("metal3",), self)
rtr.route() rtr.route()
def compute_bus_sizes(self): def compute_bus_sizes(self):
""" Compute the independent bus widths shared between two and four bank SRAMs """ """ Compute the independent bus widths shared between two and four bank SRAMs """