mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'supply_routing' into dev
This commit is contained in:
commit
7645a909eb
|
|
@ -70,8 +70,7 @@ class router(router_tech):
|
|||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
# These must be un-indexed to get rid of the matrix type
|
||||
self.ll = vector(self.boundary[0][0], self.boundary[0][1])
|
||||
# Pad the UR by a few tracks to add an extra rail possibly
|
||||
self.ur = vector(self.boundary[1][0], self.boundary[1][1]) + self.track_widths.scale(5,5)
|
||||
self.ur = vector(self.boundary[1][0], self.boundary[1][1])
|
||||
|
||||
def clear_pins(self):
|
||||
"""
|
||||
|
|
@ -130,12 +129,8 @@ class router(router_tech):
|
|||
Pin can either be a label or a location,layer pair: [[x,y],layer].
|
||||
"""
|
||||
debug.info(1,"Finding pins for {}.".format(pin_name))
|
||||
#start_time = datetime.now()
|
||||
self.retrieve_pins(pin_name)
|
||||
#print_time("Retrieved pins",datetime.now(), start_time)
|
||||
#start_time = datetime.now()
|
||||
self.analyze_pins(pin_name)
|
||||
#print_time("Analyzed pins",datetime.now(), start_time)
|
||||
|
||||
def find_blockages(self):
|
||||
"""
|
||||
|
|
@ -160,41 +155,25 @@ class router(router_tech):
|
|||
|
||||
# This will get all shapes as blockages and convert to grid units
|
||||
# This ignores shapes that were pins
|
||||
#start_time = datetime.now()
|
||||
self.find_blockages()
|
||||
#print_time("Find blockags",datetime.now(), start_time)
|
||||
|
||||
# Convert the blockages to grid units
|
||||
#start_time = datetime.now()
|
||||
self.convert_blockages()
|
||||
#print_time("Find blockags",datetime.now(), start_time)
|
||||
|
||||
# This will convert the pins to grid units
|
||||
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
|
||||
#start_time = datetime.now()
|
||||
for pin in pin_list:
|
||||
self.convert_pins(pin)
|
||||
#print_time("Convert pins",datetime.now(), start_time)
|
||||
|
||||
#start_time = datetime.now()
|
||||
#for pin in pin_list:
|
||||
# self.combine_adjacent_pins(pin)
|
||||
#print_time("Combine pins",datetime.now(), start_time)
|
||||
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
|
||||
|
||||
# Separate any adjacent grids of differing net names that overlap
|
||||
# Must be done before enclosing pins
|
||||
#start_time = datetime.now()
|
||||
self.separate_adjacent_pins(0)
|
||||
#print_time("Separate pins",datetime.now(), start_time)
|
||||
# For debug
|
||||
#self.separate_adjacent_pins(1)
|
||||
|
||||
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
|
||||
#start_time = datetime.now()
|
||||
self.enclose_pins()
|
||||
#print_time("Enclose pins",datetime.now(), start_time)
|
||||
#self.write_debug_gds("debug_enclose_pins.gds",stop_program=True)
|
||||
|
||||
|
||||
def combine_adjacent_pins(self, pin_name):
|
||||
|
|
@ -282,7 +261,7 @@ class router(router_tech):
|
|||
adj_grids = pg1.adjacent_grids(pg2, separation)
|
||||
# These should have the same length, so...
|
||||
if len(adj_grids)>0:
|
||||
debug.info(2,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids))
|
||||
debug.info(3,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids))
|
||||
self.remove_adjacent_grid(pg1, pg2, adj_grids)
|
||||
|
||||
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
||||
|
|
@ -304,12 +283,12 @@ class router(router_tech):
|
|||
# If the adjacent grids are a subset of the secondary grids (i.e. not necessary)
|
||||
# remove them from each
|
||||
if adj in bigger.secondary_grids:
|
||||
debug.info(2,"Removing {} from bigger secondary {}".format(adj, bigger))
|
||||
debug.info(3,"Removing {} from bigger secondary {}".format(adj, bigger))
|
||||
bigger.grids.remove(adj)
|
||||
bigger.secondary_grids.remove(adj)
|
||||
self.blocked_grids.add(adj)
|
||||
elif adj in smaller.secondary_grids:
|
||||
debug.info(2,"Removing {} from smaller secondary {}".format(adj, smaller))
|
||||
debug.info(3,"Removing {} from smaller secondary {}".format(adj, smaller))
|
||||
smaller.grids.remove(adj)
|
||||
smaller.secondary_grids.remove(adj)
|
||||
self.blocked_grids.add(adj)
|
||||
|
|
@ -317,10 +296,10 @@ class router(router_tech):
|
|||
# If we couldn't remove from a secondary grid, we must remove from the primary
|
||||
# grid of at least one pin
|
||||
if adj in bigger.grids:
|
||||
debug.info(2,"Removing {} from bigger primary {}".format(adj, bigger))
|
||||
debug.info(3,"Removing {} from bigger primary {}".format(adj, bigger))
|
||||
bigger.grids.remove(adj)
|
||||
elif adj in smaller.grids:
|
||||
debug.info(2,"Removing {} from smaller primary {}".format(adj, smaller))
|
||||
debug.info(3,"Removing {} from smaller primary {}".format(adj, smaller))
|
||||
smaller.grids.remove(adj)
|
||||
|
||||
|
||||
|
|
@ -361,17 +340,6 @@ class router(router_tech):
|
|||
self.set_blockages(blockage_grids,False)
|
||||
|
||||
|
||||
# def translate_coordinates(self, coord, mirr, angle, xyShift):
|
||||
# """
|
||||
# Calculate coordinates after flip, rotate, and shift
|
||||
# """
|
||||
# coordinate = []
|
||||
# for item in coord:
|
||||
# x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
|
||||
# y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
|
||||
# coordinate += [(x, y)]
|
||||
# return coordinate
|
||||
|
||||
def convert_shape_to_units(self, shape):
|
||||
"""
|
||||
Scale a shape (two vector list) to user units
|
||||
|
|
@ -498,11 +466,6 @@ class router(router_tech):
|
|||
# and the track points are at the center
|
||||
ll = ll.round()
|
||||
ur = ur.round()
|
||||
# if ll[0]<45 and ll[0]>35 and ll[1]<5 and ll[1]>-5:
|
||||
# debug.info(0,"Converting [ {0} , {1} ]".format(old_ll,old_ur))
|
||||
# debug.info(0,"Converted [ {0} , {1} ]".format(ll,ur))
|
||||
# pin=self.convert_track_to_shape(ll)
|
||||
# debug.info(0,"Pin {}".format(pin))
|
||||
return [ll,ur]
|
||||
|
||||
def convert_pin_to_tracks(self, pin_name, pin, expansion=0):
|
||||
|
|
@ -558,7 +521,6 @@ class router(router_tech):
|
|||
"""
|
||||
Find a list of the single pin with the most overlap.
|
||||
"""
|
||||
#print("INSUFFICIENT LIST",insufficient_list)
|
||||
# Find the coordinate with the most overlap
|
||||
best_coord = None
|
||||
best_overlap = -math.inf
|
||||
|
|
@ -579,7 +541,6 @@ class router(router_tech):
|
|||
Get a grid cell that is the furthest from the blocked grids.
|
||||
"""
|
||||
|
||||
#print("INSUFFICIENT LIST",insufficient_list)
|
||||
# Find the coordinate with the most overlap
|
||||
best_coord = None
|
||||
best_dist = math.inf
|
||||
|
|
@ -596,7 +557,6 @@ class router(router_tech):
|
|||
Given a pin and a list of grid cells (probably non-overlapping),
|
||||
return the nearest grid cell (center to center).
|
||||
"""
|
||||
#print("INSUFFICIENT LIST",insufficient_list)
|
||||
# Find the coordinate with the most overlap
|
||||
best_coord = None
|
||||
best_dist = math.inf
|
||||
|
|
@ -638,10 +598,6 @@ class router(router_tech):
|
|||
else:
|
||||
debug.info(2," No overlap: {0} {1}".format(overlap_length,0))
|
||||
return (None,None)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def convert_track_to_pin(self, track):
|
||||
|
|
@ -764,8 +720,6 @@ class router(router_tech):
|
|||
pg.enclose_pin()
|
||||
pg.add_enclosure(self.cell)
|
||||
|
||||
#self.write_debug_gds("pin_debug.gds", False)
|
||||
|
||||
def add_source(self, pin_name):
|
||||
"""
|
||||
This will mark the grids for all pin components as a source.
|
||||
|
|
@ -835,9 +789,6 @@ class router(router_tech):
|
|||
"""
|
||||
debug.info(4,"Set path: " + str(path))
|
||||
|
||||
# Keep track of path for future blockages
|
||||
#path.set_blocked()
|
||||
|
||||
# This is marked for debug
|
||||
path.set_path()
|
||||
|
||||
|
|
@ -906,44 +857,10 @@ class router(router_tech):
|
|||
(abs_ll,unused) = pin.rect
|
||||
pin = self.convert_track_to_pin(ur)
|
||||
(unused,abs_ur) = pin.rect
|
||||
#print("enclose ll={0} ur={1}".format(ll,ur))
|
||||
#print("enclose ll={0} ur={1}".format(abs_ll,abs_ur))
|
||||
|
||||
pin = pin_layout(name, [abs_ll, abs_ur], layer)
|
||||
|
||||
return pin
|
||||
|
||||
|
||||
# def compute_wide_enclosure(self, ll, ur, zindex, name=""):
|
||||
# """
|
||||
# Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
|
||||
# """
|
||||
|
||||
# # Find the pin enclosure of the whole track shape (ignoring DRCs)
|
||||
# (abs_ll,unused) = self.convert_track_to_shape(ll)
|
||||
# (unused,abs_ur) = self.convert_track_to_shape(ur)
|
||||
|
||||
# # Get the layer information
|
||||
# x_distance = abs(abs_ll.x-abs_ur.x)
|
||||
# y_distance = abs(abs_ll.y-abs_ur.y)
|
||||
# shape_width = min(x_distance, y_distance)
|
||||
# shape_length = max(x_distance, y_distance)
|
||||
|
||||
# # Get the DRC rule for the grid dimensions
|
||||
# (width, space) = self.get_supply_layer_width_space(zindex)
|
||||
# layer = self.get_layer(zindex)
|
||||
|
||||
# if zindex==0:
|
||||
# spacing = vector(0.5*self.track_width, 0.5*space)
|
||||
# else:
|
||||
# spacing = vector(0.5*space, 0.5*self.track_width)
|
||||
# # Compute the shape offsets with correct spacing
|
||||
# new_ll = abs_ll + spacing
|
||||
# new_ur = abs_ur - spacing
|
||||
# pin = pin_layout(name, [new_ll, new_ur], layer)
|
||||
|
||||
# return pin
|
||||
|
||||
|
||||
def contract_path(self,path):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ class router_tech:
|
|||
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
||||
debug.info(1,"Track width: {:.3f}".format(self.track_width))
|
||||
self.track_space = max(self.horiz_layer_spacing,self.vert_layer_spacing)
|
||||
debug.info(1,"Track spacing: {:.3f}".format(self.track_space))
|
||||
debug.info(1,"Track space: {:.3f}".format(self.track_space))
|
||||
self.track_wire = self.track_width - self.track_space
|
||||
debug.info(1,"Wire width: {:.3f}".format(self.track_wire))
|
||||
debug.info(1,"Track wire width: {:.3f}".format(self.track_wire))
|
||||
|
||||
self.track_widths = vector([self.track_width] * 2)
|
||||
self.track_factor = vector([1/self.track_width] * 2)
|
||||
|
|
|
|||
|
|
@ -64,17 +64,10 @@ class supply_router(router):
|
|||
# but this is simplest for now.
|
||||
self.create_routing_grid()
|
||||
|
||||
# Compute the grid dimensions
|
||||
self.compute_supply_rail_dimensions()
|
||||
|
||||
# Get the pin shapes
|
||||
#start_time = datetime.now()
|
||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||
#print_time("Pins and blockages",datetime.now(), start_time)
|
||||
#self.write_debug_gds("pin_enclosures.gds",stop_program=True)
|
||||
|
||||
# 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)
|
||||
# Determine the rail locations
|
||||
|
|
@ -84,23 +77,15 @@ class supply_router(router):
|
|||
self.prepare_blockages(self.vdd_name)
|
||||
# Determine the rail locations
|
||||
self.route_supply_rails(self.vdd_name,1)
|
||||
#self.write_debug_gds("debug_rails.gds",stop_program=True)
|
||||
#print_time("Supply rails",datetime.now(), start_time)
|
||||
|
||||
#start_time = datetime.now()
|
||||
self.route_simple_overlaps(vdd_name)
|
||||
self.route_simple_overlaps(gnd_name)
|
||||
#print_time("Simple overlaps",datetime.now(), start_time)
|
||||
#self.write_debug_gds("debug_simple_route.gds",stop_program=False)
|
||||
|
||||
# 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_to_rails(vdd_name)
|
||||
self.route_pins_to_rails(gnd_name)
|
||||
#print_time("Routing",datetime.now(), start_time)
|
||||
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
|
||||
|
||||
|
||||
#self.write_debug_gds("final.gds",False)
|
||||
|
||||
return True
|
||||
|
|
@ -227,40 +212,6 @@ class supply_router(router):
|
|||
width=pin.width(),
|
||||
height=pin.height())
|
||||
|
||||
def compute_supply_rail_dimensions(self):
|
||||
"""
|
||||
Compute the supply rail dimensions including wide metal spacing rules.
|
||||
"""
|
||||
|
||||
self.max_yoffset = self.rg.ur.y
|
||||
self.max_xoffset = self.rg.ur.x
|
||||
|
||||
# # Longest length is conservative
|
||||
# rail_length = max(self.max_yoffset,self.max_xoffset)
|
||||
# # Convert the number of tracks to dimensions to get the design rule spacing
|
||||
# rail_width = self.track_width*self.rail_track_width
|
||||
|
||||
# # Get the conservative width and spacing of the top rails
|
||||
# (horizontal_width, horizontal_space) = self.get_supply_layer_width_space(0)
|
||||
# (vertical_width, vertical_space) = self.get_supply_layer_width_space(1)
|
||||
# width = max(horizontal_width, vertical_width)
|
||||
# space = max(horizontal_space, vertical_space)
|
||||
|
||||
# track_pitch = width + space
|
||||
|
||||
# # Determine the pitch (in tracks) of the rail wire + spacing
|
||||
# self.supply_rail_width = math.ceil(track_pitch/self.track_width)
|
||||
# debug.info(1,"Rail step: {}".format(self.supply_rail_width))
|
||||
|
||||
# # Conservatively determine the number of tracks that the rail actually occupies
|
||||
# space_tracks = math.ceil(space/self.track_width)
|
||||
# self.supply_rail_wire_width = self.supply_rail_width - space_tracks
|
||||
# debug.info(1,"Rail wire tracks: {}".format(self.supply_rail_wire_width))
|
||||
# total_space = self.supply_rail_width - self.supply_rail_wire_width
|
||||
# self.supply_rail_space_width = math.floor(0.5*total_space)
|
||||
# debug.info(1,"Rail space tracks: {} (on both sides)".format(self.supply_rail_space_width))
|
||||
|
||||
|
||||
def compute_supply_rails(self, name, supply_number):
|
||||
"""
|
||||
Compute the unblocked locations for the horizontal and vertical supply rails.
|
||||
|
|
@ -270,14 +221,19 @@ class supply_router(router):
|
|||
|
||||
self.supply_rails[name]=[]
|
||||
|
||||
start_offset = supply_number
|
||||
max_yoffset = self.rg.ur.y
|
||||
max_xoffset = self.rg.ur.x
|
||||
min_yoffset = self.rg.ll.y
|
||||
min_xoffset = self.rg.ll.x
|
||||
|
||||
start_offset = min_yoffset + supply_number
|
||||
|
||||
# Horizontal supply rails
|
||||
for offset in range(start_offset, self.max_yoffset, 2):
|
||||
for offset in range(start_offset, max_yoffset, 2):
|
||||
# Seed the function at the location with the given width
|
||||
wave = [vector3d(0,offset,0)]
|
||||
wave = [vector3d(min_xoffset,offset,0)]
|
||||
# While we can keep expanding east in this horizontal track
|
||||
while wave and wave[0].x < self.max_xoffset:
|
||||
while wave and wave[0].x < max_xoffset:
|
||||
added_rail = self.find_supply_rail(name, wave, direction.EAST)
|
||||
if not added_rail:
|
||||
# Just seed with the next one
|
||||
|
|
@ -288,11 +244,11 @@ class supply_router(router):
|
|||
|
||||
# Vertical supply rails
|
||||
max_offset = self.rg.ur.x
|
||||
for offset in range(start_offset, self.max_xoffset, 2):
|
||||
for offset in range(start_offset, max_xoffset, 2):
|
||||
# Seed the function at the location with the given width
|
||||
wave = [vector3d(offset,0,1)]
|
||||
wave = [vector3d(offset,min_yoffset,1)]
|
||||
# While we can keep expanding north in this vertical track
|
||||
while wave and wave[0].y < self.max_yoffset:
|
||||
while wave and wave[0].y < max_yoffset:
|
||||
added_rail = self.find_supply_rail(name, wave, direction.NORTH)
|
||||
if not added_rail:
|
||||
# Just seed with the next one
|
||||
|
|
|
|||
|
|
@ -21,11 +21,6 @@ class sram_1bank(sram_base):
|
|||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
sram_base.create_netlist(self)
|
||||
self.create_modules()
|
||||
|
||||
def create_modules(self):
|
||||
"""
|
||||
This adds the modules for a single bank SRAM with control
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import sys
|
|||
import datetime
|
||||
import getpass
|
||||
import debug
|
||||
from datetime import datetime
|
||||
from importlib import reload
|
||||
from vector import vector
|
||||
from globals import OPTS, print_time
|
||||
|
|
@ -63,37 +64,52 @@ class sram_base(design):
|
|||
|
||||
def create_netlist(self):
|
||||
""" Netlist creation """
|
||||
|
||||
|
||||
start_time = datetime.now()
|
||||
|
||||
# Must create the control logic before pins to get the pins
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
|
||||
# This is for the lib file if we don't create layout
|
||||
self.width=0
|
||||
self.height=0
|
||||
|
||||
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Netlisting",datetime.now(), start_time)
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
start_time = datetime.now()
|
||||
self.place_instances()
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Placement",datetime.now(), start_time)
|
||||
|
||||
start_time = datetime.now()
|
||||
self.route_layout()
|
||||
self.route_supplies()
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Routing",datetime.now(), start_time)
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
||||
# Must be done after offsetting lower-left
|
||||
self.route_supplies()
|
||||
|
||||
highest_coord = self.find_highest_coords()
|
||||
self.width = highest_coord[0]
|
||||
self.height = highest_coord[1]
|
||||
|
||||
|
||||
start_time = datetime.now()
|
||||
self.DRC_LVS(final_verification=True)
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Verification",datetime.now(), start_time)
|
||||
|
||||
|
||||
def create_modules(self):
|
||||
debug.error("Must override pure virtual function.",-1)
|
||||
|
||||
def route_supplies(self):
|
||||
""" Route the supply grid and connect the pins to them. """
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue