mirror of https://github.com/VLSIDA/OpenRAM.git
Supply router working except for off by one rail via error
This commit is contained in:
parent
4bf1e206e2
commit
0aad61892b
|
|
@ -134,11 +134,13 @@ class layout(lef.lef):
|
|||
return inst
|
||||
return None
|
||||
|
||||
def add_rect(self, layer, offset, width=0, height=0):
|
||||
"""Adds a rectangle on a given layer,offset with width and height"""
|
||||
if width==0:
|
||||
def add_rect(self, layer, offset, width=None, height=None):
|
||||
"""
|
||||
Adds a rectangle on a given layer,offset with width and height
|
||||
"""
|
||||
if not width:
|
||||
width=drc["minwidth_{}".format(layer)]
|
||||
if height==0:
|
||||
if not height:
|
||||
height=drc["minwidth_{}".format(layer)]
|
||||
# negative layers indicate "unused" layers in a given technology
|
||||
layer_num = techlayer[layer]
|
||||
|
|
@ -147,11 +149,13 @@ class layout(lef.lef):
|
|||
return self.objs[-1]
|
||||
return None
|
||||
|
||||
def add_rect_center(self, layer, offset, width=0, height=0):
|
||||
"""Adds a rectangle on a given layer at the center point with width and height"""
|
||||
if width==0:
|
||||
def add_rect_center(self, layer, offset, width=None, height=None):
|
||||
"""
|
||||
Adds a rectangle on a given layer at the center point with width and height
|
||||
"""
|
||||
if not width:
|
||||
width=drc["minwidth_{}".format(layer)]
|
||||
if height==0:
|
||||
if not height:
|
||||
height=drc["minwidth_{}".format(layer)]
|
||||
# negative layers indicate "unused" layers in a given technology
|
||||
layer_num = techlayer[layer]
|
||||
|
|
@ -163,7 +167,9 @@ class layout(lef.lef):
|
|||
|
||||
|
||||
def add_segment_center(self, layer, start, end):
|
||||
""" Add a min-width rectanglular segment using center line on the start to end point """
|
||||
"""
|
||||
Add a min-width rectanglular segment using center line on the start to end point
|
||||
"""
|
||||
minwidth_layer = drc["minwidth_{}".format(layer)]
|
||||
if start.x!=end.x and start.y!=end.y:
|
||||
debug.error("Nonrectilinear center rect!",-1)
|
||||
|
|
@ -177,7 +183,9 @@ class layout(lef.lef):
|
|||
|
||||
|
||||
def get_pin(self, text):
|
||||
""" Return the pin or list of pins """
|
||||
"""
|
||||
Return the pin or list of pins
|
||||
"""
|
||||
try:
|
||||
if len(self.pin_map[text])>1:
|
||||
debug.error("Should use a pin iterator since more than one pin {}".format(text),-1)
|
||||
|
|
@ -192,7 +200,9 @@ class layout(lef.lef):
|
|||
|
||||
|
||||
def get_pins(self, text):
|
||||
""" Return a pin list (instead of a single pin) """
|
||||
"""
|
||||
Return a pin list (instead of a single pin)
|
||||
"""
|
||||
if text in self.pin_map.keys():
|
||||
return self.pin_map[text]
|
||||
else:
|
||||
|
|
@ -210,7 +220,9 @@ class layout(lef.lef):
|
|||
self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height())
|
||||
|
||||
def add_layout_pin_segment_center(self, text, layer, start, end):
|
||||
""" Creates a path like pin with center-line convention """
|
||||
"""
|
||||
Creates a path like pin with center-line convention
|
||||
"""
|
||||
|
||||
debug.check(start.x==end.x or start.y==end.y,"Cannot have a non-manhatten layout pin.")
|
||||
|
||||
|
|
@ -235,9 +247,9 @@ class layout(lef.lef):
|
|||
|
||||
def add_layout_pin_rect_center(self, text, layer, offset, width=None, height=None):
|
||||
""" Creates a path like pin with center-line convention """
|
||||
if width==None:
|
||||
if not width:
|
||||
width=drc["minwidth_{0}".format(layer)]
|
||||
if height==None:
|
||||
if not height:
|
||||
height=drc["minwidth_{0}".format(layer)]
|
||||
|
||||
ll_offset = offset - vector(0.5*width,0.5*height)
|
||||
|
|
@ -246,14 +258,18 @@ class layout(lef.lef):
|
|||
|
||||
|
||||
def remove_layout_pin(self, text):
|
||||
"""Delete a labeled pin (or all pins of the same name)"""
|
||||
"""
|
||||
Delete a labeled pin (or all pins of the same name)
|
||||
"""
|
||||
self.pin_map[text]=[]
|
||||
|
||||
def add_layout_pin(self, text, layer, offset, width=None, height=None):
|
||||
"""Create a labeled pin """
|
||||
if width==None:
|
||||
"""
|
||||
Create a labeled pin
|
||||
"""
|
||||
if not width:
|
||||
width=drc["minwidth_{0}".format(layer)]
|
||||
if height==None:
|
||||
if not height:
|
||||
height=drc["minwidth_{0}".format(layer)]
|
||||
|
||||
new_pin = pin_layout(text, [offset,offset+vector(width,height)], layer)
|
||||
|
|
@ -273,13 +289,14 @@ class layout(lef.lef):
|
|||
return new_pin
|
||||
|
||||
def add_label_pin(self, text, layer, offset, width=None, height=None):
|
||||
"""Create a labeled pin WITHOUT the pin data structure. This is not an
|
||||
"""
|
||||
Create a labeled pin WITHOUT the pin data structure. This is not an
|
||||
actual pin but a named net so that we can add a correspondence point
|
||||
in LVS.
|
||||
"""
|
||||
if width==None:
|
||||
if not width:
|
||||
width=drc["minwidth_{0}".format(layer)]
|
||||
if height==None:
|
||||
if not height:
|
||||
height=drc["minwidth_{0}".format(layer)]
|
||||
self.add_rect(layer=layer,
|
||||
offset=offset,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ class grid:
|
|||
# let's leave the map sparse, cells are created on demand to reduce memory
|
||||
self.map={}
|
||||
|
||||
def add_all_grids(self):
|
||||
for x in range(self.ll.x, self.ur.x, 1):
|
||||
for y in range(self.ll.y, self.ur.y, 1):
|
||||
self.add_map(vector3d(x,y,0))
|
||||
self.add_map(vector3d(x,y,1))
|
||||
|
||||
def set_blocked(self,n,value=True):
|
||||
if isinstance(n, (list,tuple,set,frozenset)):
|
||||
for item in n:
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ class router:
|
|||
### The routed data structures
|
||||
# A list of paths that have been "routed"
|
||||
self.paths = []
|
||||
# The list of supply rails that may be routed
|
||||
self.supply_rails = []
|
||||
|
||||
# The boundary will determine the limits to the size of the routing grid
|
||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
|
|
@ -833,8 +831,31 @@ class router:
|
|||
|
||||
# Add a shape from ll to ur
|
||||
ur = row[-1]
|
||||
return self.add_enclosure(ll, ur, ll.z)
|
||||
return self.compute_pin_enclosure(ll, ur, ll.z)
|
||||
|
||||
def remove_redundant_shapes(self, pin_list):
|
||||
"""
|
||||
Remove any pin layout that is contained within another.
|
||||
"""
|
||||
|
||||
print("INITIAL:",pin_list)
|
||||
|
||||
# Make a copy of the list to start
|
||||
new_pin_list = pin_list.copy()
|
||||
|
||||
# This is n^2, but the number is small
|
||||
for pin1 in pin_list:
|
||||
for pin2 in pin_list:
|
||||
# Can't contain yourself
|
||||
if pin1 == pin2:
|
||||
continue
|
||||
if pin2.contains(pin1):
|
||||
# It may have already been removed by being enclosed in another pin
|
||||
if pin1 in new_pin_list:
|
||||
new_pin_list.remove(pin1)
|
||||
|
||||
print("FINAL :",new_pin_list)
|
||||
return new_pin_list
|
||||
|
||||
def compute_enclosures(self, tracks):
|
||||
"""
|
||||
|
|
@ -844,19 +865,7 @@ class router:
|
|||
for seed in tracks:
|
||||
pin_list.append(self.enclose_pin_grids(tracks, seed))
|
||||
|
||||
# Prune any enclosre that is contained in another
|
||||
new_pin_list = pin_list
|
||||
for pin1 in pin_list:
|
||||
for pin2 in pin_list:
|
||||
if pin1 == pin2:
|
||||
continue
|
||||
if pin2.contains(pin1):
|
||||
try:
|
||||
new_pin_list.remove(pin1)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return new_pin_list
|
||||
return self.remove_redundant_shapes(pin_list)
|
||||
|
||||
def overlap_any_shape(self, pin_list, shape_list):
|
||||
"""
|
||||
|
|
@ -900,19 +909,24 @@ class router:
|
|||
put a rectangle over it. It does not enclose grid squares that are blocked
|
||||
by other shapes.
|
||||
"""
|
||||
# These are used for debugging
|
||||
self.connector_enclosure = []
|
||||
self.enclosures = []
|
||||
|
||||
for pin_name in self.pin_grids.keys():
|
||||
debug.info(1,"Enclosing pins for {}".format(pin_name))
|
||||
debug.check(len(self.pin_groups[pin_name])==len(self.pin_grids[pin_name]),"Unequal pin_group and pin_grid")
|
||||
for pin_group,pin_set in zip(self.pin_groups[pin_name],self.pin_grids[pin_name]):
|
||||
for pin_group,pin_grid_set in zip(self.pin_groups[pin_name],self.pin_grids[pin_name]):
|
||||
|
||||
# Compute the enclosure pin_layout list of the set of tracks
|
||||
enclosure_list = self.compute_enclosures(pin_set)
|
||||
enclosure_list = self.compute_enclosures(pin_grid_set)
|
||||
for pin in enclosure_list:
|
||||
debug.info(2,"Adding enclosure {0} {1}".format(pin_name, pin))
|
||||
self.cell.add_rect(layer=pin.layer,
|
||||
offset=pin.ll(),
|
||||
width=pin.width(),
|
||||
height=pin.height())
|
||||
self.enclosures.append(pin)
|
||||
|
||||
# Check if a pin shape overlaps any enclosure.
|
||||
# If so, we are done.
|
||||
|
|
@ -926,6 +940,7 @@ class router:
|
|||
offset=new_enclosure.ll(),
|
||||
width=new_enclosure.width(),
|
||||
height=new_enclosure.height())
|
||||
self.connector_enclosure.append(new_enclosure)
|
||||
|
||||
|
||||
|
||||
|
|
@ -956,7 +971,7 @@ class router:
|
|||
xmin = min(pbc.x,ebc.x)
|
||||
xmax = max(pbc.x,ebc.x)
|
||||
ll = vector(xmin, pbc.y)
|
||||
ur = vetor(xmax, puc.y)
|
||||
ur = vector(xmax, puc.y)
|
||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||
else:
|
||||
# Neither, so we must do a corner-to corner
|
||||
|
|
@ -1112,7 +1127,7 @@ class router:
|
|||
ll = path[0][0]
|
||||
ur = path[-1][-1]
|
||||
z = ll.z
|
||||
pin = self.add_enclosure(ll, ur, z, name)
|
||||
pin = self.compute_wide_enclosure(ll, ur, z, name)
|
||||
#print(ll, ur, ll.z, "->",pin)
|
||||
self.cell.add_layout_pin(text=name,
|
||||
layer=pin.layer,
|
||||
|
|
@ -1122,7 +1137,28 @@ class router:
|
|||
|
||||
return pin
|
||||
|
||||
def add_enclosure(self, ll, ur, zindex, name=""):
|
||||
def compute_pin_enclosure(self, ll, ur, zindex, name=""):
|
||||
"""
|
||||
Enclose the tracks from ll to ur in a single rectangle that meets
|
||||
the track DRC rules. If name is supplied, it is added as a pin and
|
||||
not just a rectangle.
|
||||
"""
|
||||
# Get the layer information
|
||||
(width, space) = self.get_layer_width_space(zindex)
|
||||
layer = self.get_layer(zindex)
|
||||
|
||||
# This finds the pin shape enclosed by the track with DRC spacing on the sides
|
||||
(abs_ll,unused) = self.convert_track_to_pin(ll)
|
||||
(unused,abs_ur) = self.convert_track_to_pin(ur)
|
||||
#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.
|
||||
If name is supplied, it is added as a pin and not just a rectangle.
|
||||
|
|
@ -1142,14 +1178,18 @@ class router:
|
|||
# Get the DRC rule for the grid dimensions
|
||||
(width, space) = self.get_layer_width_space(zindex, shape_width, shape_length)
|
||||
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 + vector(0.5*space, 0.5*space)
|
||||
new_ur = abs_ur - vector(0.5*space, 0.5*space)
|
||||
new_ll = abs_ll + spacing
|
||||
new_ur = abs_ur - spacing
|
||||
pin = pin_layout(name, [new_ll, new_ur], layer)
|
||||
|
||||
return pin
|
||||
|
||||
|
||||
|
||||
def get_inertia(self,p0,p1):
|
||||
"""
|
||||
|
|
@ -1246,7 +1286,37 @@ class router:
|
|||
if stop_program:
|
||||
import sys
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def annotate_grid(self, g):
|
||||
"""
|
||||
Display grid information in the GDS file for a single grid cell.
|
||||
"""
|
||||
shape = self.convert_track_to_shape(g)
|
||||
partial_track=vector(0,self.track_width/6.0)
|
||||
self.cell.add_rect(layer="text",
|
||||
offset=shape[0],
|
||||
width=shape[1].x-shape[0].x,
|
||||
height=shape[1].y-shape[0].y)
|
||||
t=self.rg.map[g].get_type()
|
||||
|
||||
# midpoint offset
|
||||
off=vector((shape[1].x+shape[0].x)/2,
|
||||
(shape[1].y+shape[0].y)/2)
|
||||
if g[2]==1:
|
||||
# Upper layer is upper right label
|
||||
type_off=off+partial_track
|
||||
else:
|
||||
# Lower layer is lower left label
|
||||
type_off=off-partial_track
|
||||
if t!=None:
|
||||
self.cell.add_label(text=str(t),
|
||||
layer="text",
|
||||
offset=type_off)
|
||||
self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
|
||||
layer="text",
|
||||
offset=shape[0],
|
||||
zoom=0.05)
|
||||
|
||||
def add_router_info(self):
|
||||
"""
|
||||
Write the routing grid and router cost, blockage, pins on
|
||||
|
|
@ -1255,7 +1325,18 @@ class router:
|
|||
"""
|
||||
debug.info(0,"Adding router info")
|
||||
|
||||
if OPTS.debug_level>0:
|
||||
show_blockages = False
|
||||
show_blockage_grids = False
|
||||
show_enclosures = False
|
||||
show_connectors = False
|
||||
show_all_grids = True
|
||||
|
||||
if show_all_grids:
|
||||
self.rg.add_all_grids()
|
||||
for g in self.rg.map.keys():
|
||||
self.annotate_grid(g)
|
||||
|
||||
if show_blockages:
|
||||
# Display the inflated blockage
|
||||
for blockage in self.blockages:
|
||||
debug.info(1,"Adding {}".format(blockage))
|
||||
|
|
@ -1264,36 +1345,26 @@ class router:
|
|||
offset=ll,
|
||||
width=ur.x-ll.x,
|
||||
height=ur.y-ll.y)
|
||||
if OPTS.debug_level>1:
|
||||
if show_blockage_grids:
|
||||
self.set_blockages(self.blocked_grids,True)
|
||||
grid_keys=self.rg.map.keys()
|
||||
partial_track=vector(0,self.track_width/6.0)
|
||||
for g in grid_keys:
|
||||
shape = self.convert_track_to_shape(g)
|
||||
self.cell.add_rect(layer="text",
|
||||
offset=shape[0],
|
||||
width=shape[1].x-shape[0].x,
|
||||
height=shape[1].y-shape[0].y)
|
||||
t=self.rg.map[g].get_type()
|
||||
|
||||
# midpoint offset
|
||||
off=vector((shape[1].x+shape[0].x)/2,
|
||||
(shape[1].y+shape[0].y)/2)
|
||||
if g[2]==1:
|
||||
# Upper layer is upper right label
|
||||
type_off=off+partial_track
|
||||
else:
|
||||
# Lower layer is lower left label
|
||||
type_off=off-partial_track
|
||||
if t!=None:
|
||||
self.cell.add_label(text=str(t),
|
||||
layer="text",
|
||||
offset=type_off)
|
||||
self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
|
||||
layer="text",
|
||||
offset=shape[0],
|
||||
zoom=0.05)
|
||||
self.annotate_grid(g)
|
||||
|
||||
if show_connectors:
|
||||
for pin in self.connector_enclosure:
|
||||
#print("connector: ",str(pin))
|
||||
self.cell.add_rect(layer="text",
|
||||
offset=pin.ll(),
|
||||
width=pin.width(),
|
||||
height=pin.height())
|
||||
if show_enclosures:
|
||||
for pin in self.enclosures:
|
||||
#print("enclosure: ",pin.name,pin.ll(),pin.width(),pin.height())
|
||||
self.cell.add_rect(layer="text",
|
||||
offset=pin.ll(),
|
||||
width=pin.width(),
|
||||
height=pin.height())
|
||||
|
||||
# FIXME: This should be replaced with vector.snap_to_grid at some point
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ from contact import contact
|
|||
import math
|
||||
import debug
|
||||
from globals import OPTS
|
||||
import grid
|
||||
from pin_layout import pin_layout
|
||||
from vector import vector
|
||||
from vector3d import vector3d
|
||||
|
|
@ -24,6 +23,13 @@ class supply_router(router):
|
|||
"""
|
||||
router.__init__(self, layers, design, gds_filename)
|
||||
|
||||
|
||||
# The list of supply rails that may be routed
|
||||
self.supply_rails = []
|
||||
# This is the same as above but the sets of pins
|
||||
self.supply_rail_tracks = {}
|
||||
self.supply_rail_wire_tracks = {}
|
||||
|
||||
# Power rail width in grid units.
|
||||
self.rail_track_width = 2
|
||||
|
||||
|
|
@ -57,7 +63,9 @@ class supply_router(router):
|
|||
|
||||
# Get the pin shapes
|
||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||
|
||||
|
||||
#self.write_debug_gds("pin_enclosures.gds",stop_program=True)
|
||||
|
||||
# Add the supply rails in a mesh network and connect H/V with vias
|
||||
# Block everything
|
||||
self.prepare_blockages(self.gnd_name)
|
||||
|
|
@ -70,17 +78,108 @@ class supply_router(router):
|
|||
self.route_supply_rails(self.vdd_name,1)
|
||||
|
||||
#self.write_debug_gds("pre_pin_debug.gds",stop_program=True)
|
||||
remaining_vdd_pin_indices = self.route_simple_overlaps(vdd_name)
|
||||
remaining_gnd_pin_indices = self.route_simple_overlaps(gnd_name)
|
||||
|
||||
# Route the supply pins to the supply rails
|
||||
# Route vdd first since we want it to be shorter
|
||||
self.route_pins_to_rails(vdd_name)
|
||||
self.route_pins_to_rails(gnd_name)
|
||||
self.route_pins_to_rails(vdd_name, remaining_vdd_pin_indices)
|
||||
self.route_pins_to_rails(gnd_name, remaining_gnd_pin_indices)
|
||||
|
||||
#self.write_debug_gds("post_pin_debug.gds",stop_program=False)
|
||||
self.write_debug_gds("post_pin_debug.gds",stop_program=False)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def route_simple_overlaps(self, pin_name):
|
||||
"""
|
||||
This checks for simple cases where a pin component already overlaps a supply rail.
|
||||
It will add an enclosure to ensure the overlap in wide DRC rule cases.
|
||||
"""
|
||||
num_components = self.num_pin_components(pin_name)
|
||||
remaining_pins = []
|
||||
supply_tracks = self.supply_rail_tracks[pin_name]
|
||||
|
||||
for index in range(num_components):
|
||||
pin_in_tracks = self.pin_grids[pin_name][index]
|
||||
common_set = supply_tracks & pin_in_tracks
|
||||
|
||||
if len(common_set)==0:
|
||||
# if no overlap, add it to the complex route pins
|
||||
remaining_pins.append(index)
|
||||
else:
|
||||
print("Overlap!",index)
|
||||
self.create_simple_overlap_enclosure(pin_name, common_set)
|
||||
|
||||
return remaining_pins
|
||||
|
||||
def recurse_simple_overlap_enclosure(self, pin_name, start_set, direct):
|
||||
"""
|
||||
Recursive function to return set of tracks that connects to
|
||||
the actual supply rail wire in a given direction (or terminating
|
||||
when any track is no longer in the supply rail.
|
||||
"""
|
||||
import grid_utils
|
||||
next_set = grid_utils.expand_border(start_set, direct)
|
||||
|
||||
supply_tracks = self.supply_rail_tracks[pin_name]
|
||||
supply_wire_tracks = self.supply_rail_wire_tracks[pin_name]
|
||||
|
||||
supply_overlap = next_set & supply_tracks
|
||||
wire_overlap = next_set & supply_wire_tracks
|
||||
|
||||
print("EXAMINING: ",start_set,len(start_set),len(supply_overlap),len(wire_overlap),direct)
|
||||
# If the rail overlap is the same, we are done, since we connected to the actual wire
|
||||
if len(wire_overlap)==len(start_set):
|
||||
print("HIT RAIL", wire_overlap)
|
||||
new_set = start_set | wire_overlap
|
||||
# If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
|
||||
elif len(supply_overlap)==len(start_set):
|
||||
print("RECURSE", supply_overlap)
|
||||
recurse_set = self.recurse_simple_overlap_enclosure(pin_name, supply_overlap, direct)
|
||||
new_set = start_set | supply_overlap | recurse_set
|
||||
else:
|
||||
# If we got no next set, we are done, can't expand!
|
||||
print("NO MORE OVERLAP", supply_overlap)
|
||||
new_set = set()
|
||||
|
||||
return new_set
|
||||
|
||||
def create_simple_overlap_enclosure(self, pin_name, start_set):
|
||||
"""
|
||||
This takes a set of tracks that overlap a supply rail and creates an enclosure
|
||||
that is ensured to overlap the supply rail wire.
|
||||
It then adds rectangle(s) for the enclosure.
|
||||
"""
|
||||
import grid_utils
|
||||
|
||||
additional_set = set()
|
||||
# Check the layer of any element in the pin to determine which direction to route it
|
||||
e = next(iter(start_set))
|
||||
new_set = start_set.copy()
|
||||
if e.z==0:
|
||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.NORTH)
|
||||
if not new_set:
|
||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.SOUTH)
|
||||
else:
|
||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.EAST)
|
||||
if not new_set:
|
||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST)
|
||||
|
||||
enclosure_list = self.compute_enclosures(new_set)
|
||||
for pin in enclosure_list:
|
||||
debug.info(2,"Adding simple overlap enclosure {0} {1}".format(pin_name, pin))
|
||||
self.cell.add_rect(layer=pin.layer,
|
||||
offset=pin.ll(),
|
||||
width=pin.width(),
|
||||
height=pin.height())
|
||||
|
||||
|
||||
|
||||
|
||||
def connect_supply_rails(self, name):
|
||||
"""
|
||||
Determine which supply rails overlap and can accomodate a via.
|
||||
|
|
@ -119,7 +218,7 @@ class supply_router(router):
|
|||
remove_hrails = [rail for flag,rail in zip(horizontal_flags,horizontal_rails) if not flag]
|
||||
remove_vrails = [rail for flag,rail in zip(vertical_flags,vertical_rails) if not flag]
|
||||
for rail in remove_hrails + remove_vrails:
|
||||
debug.info(1,"Removing disconnected supply rail {}".format(rail))
|
||||
debug.info(1,"Removing disconnected supply rail {0} .. {1}".format(rail[0][0],rail[-1][-1]))
|
||||
self.supply_rails.remove(rail)
|
||||
|
||||
def add_supply_rails(self, name):
|
||||
|
|
@ -155,9 +254,19 @@ class supply_router(router):
|
|||
# i.e. a rail of self.rail_track_width needs this many tracks including
|
||||
# space
|
||||
track_pitch = self.rail_track_width*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
|
||||
debug.check(total_space % 2 == 0, "Asymmetric wire track spacing...")
|
||||
self.supply_rail_space_width = int(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):
|
||||
|
|
@ -244,21 +353,46 @@ class supply_router(router):
|
|||
# Add the rails themselves
|
||||
self.add_supply_rails(name)
|
||||
|
||||
# Make the supply rails into a big giant set of grids
|
||||
self.create_supply_track_set(name)
|
||||
|
||||
|
||||
def create_supply_track_set(self, pin_name):
|
||||
"""
|
||||
Take the remaining supply rails and put the middle grids into a set.
|
||||
The middle grids will be guaranteed to have the wire.
|
||||
FIXME: Do this instead with the supply_rail_pitch and width
|
||||
"""
|
||||
rail_set = set()
|
||||
wire_set = set()
|
||||
for rail in self.supply_rails:
|
||||
if rail.name != pin_name:
|
||||
continue
|
||||
# FIXME: Select based on self.supply_rail_wire_width and self.supply_rail_width
|
||||
start_wire_index = self.supply_rail_space_width
|
||||
end_wire_index = self.supply_rail_width - self.supply_rail_space_width
|
||||
for wave_index in range(len(rail)):
|
||||
rail_set.update(rail[wave_index])
|
||||
wire_set.update(rail[wave_index][start_wire_index:end_wire_index])
|
||||
|
||||
self.supply_rail_tracks[pin_name] = rail_set
|
||||
self.supply_rail_wire_tracks[pin_name] = wire_set
|
||||
|
||||
|
||||
|
||||
def route_pins_to_rails(self, pin_name):
|
||||
def route_pins_to_rails(self, pin_name, remaining_component_indices):
|
||||
"""
|
||||
This will route each of the pin components to the supply rails.
|
||||
This will route each of the remaining pin components to the supply rails.
|
||||
After it is done, the cells are added to the pin blockage list.
|
||||
"""
|
||||
|
||||
|
||||
num_components = self.num_pin_components(pin_name)
|
||||
debug.info(1,"Pin {0} has {1} components to route.".format(pin_name, num_components))
|
||||
|
||||
debug.info(1,"Pin {0} has {1} remaining components to route.".format(pin_name,
|
||||
len(remaining_component_indices)))
|
||||
|
||||
recent_paths = []
|
||||
# For every component
|
||||
for index in range(num_components):
|
||||
for index in remaining_component_indices:
|
||||
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
|
||||
|
||||
self.rg.reinit()
|
||||
|
|
|
|||
Loading…
Reference in New Issue